diff --git a/gz3d/client/index.html b/gz3d/client/index.html index 0b67c26134f5442016a0848ac84976856283303e..2dd977d34d2e2fc9464126d02bb1b4b653c38900 100644 --- a/gz3d/client/index.html +++ b/gz3d/client/index.html @@ -21,6 +21,8 @@ <script src="js/include/RenderPass.js"></script> <script src="js/include/MaskPass.js"></script> <script src="js/include/ShaderPass.js"></script> + <script src="js/include/ThreeBackwardsCompatibility.js"></script> + <script src="js/include/FirstPersonControls.js"></script> <script src="js/include/xml2json.js"></script> <script src="gz3d.js"></script> <link rel="stylesheet" href="style/gz3d.css"/> diff --git a/gz3d/client/js/include/ColladaLoader.js b/gz3d/client/js/include/ColladaLoader.js index f6e35d1e8e2c30a0e163953ac4eebbc1379f7a4e..353ad00f6f0e831afaf4e8baf468bf2aed4014bb 100644 --- a/gz3d/client/js/include/ColladaLoader.js +++ b/gz3d/client/js/include/ColladaLoader.js @@ -1,16 +1,18 @@ /** - * @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com - */ +* @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com +* @author Tony Parisi / http://www.tonyparisi.com/ +*/ THREE.ColladaLoader = function () { var COLLADA = null; var scene = null; - var daeScene; + var visualScene; + var kinematicsModel; var readyCallbackFunc = null; - var sources = {}; + var sources = {}; var images = {}; var animations = {}; var controllers = {}; @@ -21,7 +23,9 @@ THREE.ColladaLoader = function () { var lights = {}; var animData; + var kinematics; var visualScenes; + var kinematicsModels; var baseUrl; var morphs; var skins; @@ -52,7 +56,7 @@ THREE.ColladaLoader = function () { var colladaUp = 'Y'; var upConversion = null; - function load ( url, readyCallback, progressCallback ) { + function load ( url, readyCallback, progressCallback, failCallback ) { var length = 0; @@ -62,9 +66,9 @@ THREE.ColladaLoader = function () { request.onreadystatechange = function() { - if( request.readyState == 4 ) { + if ( request.readyState === 4 ) { - if( request.status == 0 || request.status == 200 ) { + if ( request.status === 0 || request.status === 200 ) { if ( request.responseXML ) { @@ -81,17 +85,25 @@ THREE.ColladaLoader = function () { } else { - console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" ); + if ( faillCallback ) { + + failCallback(); + + } else { + + console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" ); + + } } } - } else if ( request.readyState == 3 ) { + } else if ( request.readyState === 3 ) { if ( progressCallback ) { - if ( length == 0 ) { + if ( length === 0 ) { length = request.getResponseHeader( "Content-Length" ); @@ -114,7 +126,7 @@ THREE.ColladaLoader = function () { } - }; + } function parse( doc, callBack, url ) { @@ -131,25 +143,26 @@ THREE.ColladaLoader = function () { parseAsset(); setUpConversion(); - images = parseLib( "//dae:library_images/dae:image", _Image, "image" ); - materials = parseLib( "//dae:library_materials/dae:material", Material, "material" ); - effects = parseLib( "//dae:library_effects/dae:effect", Effect, "effect" ); - geometries = parseLib( "//dae:library_geometries/dae:geometry", Geometry, "geometry" ); - cameras = parseLib( ".//dae:library_cameras/dae:camera", Camera, "camera" ); - lights = parseLib( ".//dae:library_lights/dae:light", Light, "light" ); - controllers = parseLib( "//dae:library_controllers/dae:controller", Controller, "controller" ); - animations = parseLib( "//dae:library_animations/dae:animation", Animation, "animation" ); - visualScenes = parseLib( ".//dae:library_visual_scenes/dae:visual_scene", VisualScene, "visual_scene" ); + images = parseLib( "library_images image", _Image, "image" ); + materials = parseLib( "library_materials material", Material, "material" ); + effects = parseLib( "library_effects effect", Effect, "effect" ); + geometries = parseLib( "library_geometries geometry", Geometry, "geometry" ); + cameras = parseLib( "library_cameras camera", Camera, "camera" ); + lights = parseLib( "library_lights light", Light, "light" ); + controllers = parseLib( "library_controllers controller", Controller, "controller" ); + animations = parseLib( "library_animations animation", Animation, "animation" ); + visualScenes = parseLib( "library_visual_scenes visual_scene", VisualScene, "visual_scene" ); + kinematicsModels = parseLib( "library_kinematics_models kinematics_model", KinematicsModel, "kinematics_model" ); morphs = []; skins = []; - daeScene = parseScene(); - scene = new THREE.Object3D(); + visualScene = parseScene(); + scene = new THREE.Group(); - for ( var i = 0; i < daeScene.nodes.length; i ++ ) { + for ( var i = 0; i < visualScene.nodes.length; i ++ ) { - scene.add( createSceneGraph( daeScene.nodes[ i ] ) ); + scene.add( createSceneGraph( visualScene.nodes[ i ] ) ); } @@ -158,12 +171,16 @@ THREE.ColladaLoader = function () { createAnimations(); + kinematicsModel = parseKinematicsModel(); + createKinematics(); + var result = { scene: scene, morphs: morphs, skins: skins, animations: animData, + kinematics: kinematics, dae: { images: images, materials: materials, @@ -174,7 +191,10 @@ THREE.ColladaLoader = function () { controllers: controllers, animations: animations, visualScenes: visualScenes, - scene: daeScene + visualScene: visualScene, + scene: visualScene, + kinematicsModels: kinematicsModels, + kinematicsModel: kinematicsModel } }; @@ -187,19 +207,19 @@ THREE.ColladaLoader = function () { return result; - }; + } function setPreferredShading ( shading ) { preferredShading = shading; - }; + } function parseAsset () { - var elements = COLLADA.evaluate( '//dae:asset', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); + var elements = COLLADA.querySelectorAll('asset'); - var element = elements.iterateNext(); + var element = elements[0]; if ( element && element.childNodes ) { @@ -232,33 +252,35 @@ THREE.ColladaLoader = function () { } - }; + } function parseLib ( q, classSpec, prefix ) { - var elements = COLLADA.evaluate(q, COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ; + var elements = COLLADA.querySelectorAll(q); var lib = {}; - var element = elements.iterateNext(); + var i = 0; - while ( element ) { + var elementsLength = elements.length; + + for ( var j = 0; j < elementsLength; j ++ ) { + var element = elements[j]; var daeElement = ( new classSpec() ).parse( element ); - if ( !daeElement.id || daeElement.id.length == 0 ) daeElement.id = prefix + ( i ++ ); - lib[ daeElement.id ] = daeElement; - element = elements.iterateNext(); + if ( !daeElement.id || daeElement.id.length === 0 ) daeElement.id = prefix + ( i ++ ); + lib[ daeElement.id ] = daeElement; } return lib; - }; + } function parseScene() { - var sceneElement = COLLADA.evaluate( './/dae:scene/dae:instance_visual_scene', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ).iterateNext(); + var sceneElement = COLLADA.querySelectorAll('scene instance_visual_scene')[0]; if ( sceneElement ) { @@ -271,7 +293,24 @@ THREE.ColladaLoader = function () { } - }; + } + + function parseKinematicsModel() { + + var kinematicsModelElement = COLLADA.querySelectorAll('instance_kinematics_model')[0]; + + if ( kinematicsModelElement ) { + + var url = kinematicsModelElement.getAttribute( 'url' ).replace(/^#/, ''); + return kinematicsModels[ url.length > 0 ? url : 'kinematics_model0' ]; + + } else { + + return null; + + } + + } function createAnimations() { @@ -280,11 +319,11 @@ THREE.ColladaLoader = function () { // fill in the keys recurseHierarchy( scene ); - }; + } function recurseHierarchy( node ) { - var n = daeScene.getChildById( node.name, true ), + var n = visualScene.getChildById( node.colladaId, true ), newData = null; if ( n && n.keys ) { @@ -303,13 +342,13 @@ THREE.ColladaLoader = function () { animData.push(newData); - for ( var i = 0, il = n.keys.length; i < il; i++ ) { + for ( var i = 0, il = n.keys.length; i < il; i ++ ) { newData.length = Math.max( newData.length, n.keys[i].time ); } - } else { + } else { newData = { hierarchy: [ { @@ -320,7 +359,7 @@ THREE.ColladaLoader = function () { } - for ( var i = 0, il = node.children.length; i < il; i++ ) { + for ( var i = 0, il = node.children.length; i < il; i ++ ) { var d = recurseHierarchy( node.children[i] ); @@ -337,21 +376,22 @@ THREE.ColladaLoader = function () { return newData; - }; + } function calcAnimationBounds () { var start = 1000000; var end = -start; var frames = 0; - + var ID; for ( var id in animations ) { var animation = animations[ id ]; - + ID = ID || animation.id; for ( var i = 0; i < animation.sampler.length; i ++ ) { var sampler = animation.sampler[ i ]; + sampler.create(); start = Math.min( start, sampler.startTime ); @@ -362,9 +402,9 @@ THREE.ColladaLoader = function () { } - return { start:start, end:end, frames:frames }; + return { start:start, end:end, frames:frames,ID:ID }; - }; + } function createMorph ( geometry, ctrl ) { @@ -423,7 +463,7 @@ THREE.ColladaLoader = function () { } var skin = skinCtrl.skin; - var skeleton = daeScene.getChildById( ctrl.skeleton[ 0 ] ); + var skeleton = visualScene.getChildById( ctrl.skeleton[ 0 ] ); var hierarchy = []; applyBindShape = applyBindShape !== undefined ? applyBindShape : true; @@ -455,12 +495,14 @@ THREE.ColladaLoader = function () { } - }; + } function setupSkeleton ( node, bones, frame, parent ) { node.world = node.world || new THREE.Matrix4(); + node.localworld = node.localworld || new THREE.Matrix4(); node.world.copy( node.matrix ); + node.localworld.copy( node.matrix ); if ( node.channels && node.channels.length ) { @@ -470,7 +512,9 @@ THREE.ColladaLoader = function () { if ( m instanceof THREE.Matrix4 ) { node.world.copy( m ); - + node.localworld.copy(m); + if (frame === 0) + node.matrix.copy(m); } } @@ -489,7 +533,7 @@ THREE.ColladaLoader = function () { } - }; + } function setupSkinningMatrices ( bones, skin ) { @@ -504,7 +548,7 @@ THREE.ColladaLoader = function () { for ( var j = 0; j < skin.joints.length; j ++ ) { - if ( bone.sid == skin.joints[ j ] ) { + if ( bone.sid === skin.joints[ j ] ) { found = j; break; @@ -520,16 +564,18 @@ THREE.ColladaLoader = function () { bone.invBindMatrix = inv; bone.skinningMatrix = new THREE.Matrix4(); bone.skinningMatrix.multiplyMatrices(bone.world, inv); // (IBMi * JMi) + bone.animatrix = new THREE.Matrix4(); + bone.animatrix.copy(bone.localworld); bone.weights = []; for ( var j = 0; j < skin.weights.length; j ++ ) { - for (var k = 0; k < skin.weights[ j ].length; k ++) { + for (var k = 0; k < skin.weights[ j ].length; k ++ ) { var w = skin.weights[ j ][ k ]; - if ( w.joint == found ) { + if ( w.joint === found ) { bone.weights.push( w ); @@ -541,13 +587,96 @@ THREE.ColladaLoader = function () { } else { - throw 'ColladaLoader: Could not find joint \'' + bone.sid + '\'.'; + console.warn( "ColladaLoader: Could not find joint '" + bone.sid + "'." ); + + bone.skinningMatrix = new THREE.Matrix4(); + bone.weights = []; + + } + } + + } + + //Walk the Collada tree and flatten the bones into a list, extract the position, quat and scale from the matrix + function flattenSkeleton(skeleton) { + + var list = []; + var walk = function(parentid, node, list) { + + var bone = {}; + bone.name = node.sid; + bone.parent = parentid; + bone.matrix = node.matrix; + var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ]; + bone.matrix.decompose(data[0], data[1], data[2]); + + bone.pos = [ data[0].x,data[0].y,data[0].z ]; + + bone.scl = [ data[2].x,data[2].y,data[2].z ]; + bone.rotq = [ data[1].x,data[1].y,data[1].z,data[1].w ]; + list.push(bone); + + for (var i in node.nodes) { + + walk(node.sid, node.nodes[i], list); + + } + + }; + + walk(-1, skeleton, list); + return list; + + } + + //Move the vertices into the pose that is proper for the start of the animation + function skinToBindPose(geometry,skeleton,skinController) { + + var bones = []; + setupSkeleton( skeleton, bones, -1 ); + setupSkinningMatrices( bones, skinController.skin ); + v = new THREE.Vector3(); + var skinned = []; + + for (var i = 0; i < geometry.vertices.length; i ++) { + + skinned.push(new THREE.Vector3()); + + } + + for ( i = 0; i < bones.length; i ++ ) { + + if ( bones[ i ].type != 'JOINT' ) continue; + + for ( j = 0; j < bones[ i ].weights.length; j ++ ) { + + w = bones[ i ].weights[ j ]; + vidx = w.index; + weight = w.weight; + + o = geometry.vertices[vidx]; + s = skinned[vidx]; + v.x = o.x; + v.y = o.y; + v.z = o.z; + + v.applyMatrix4( bones[i].skinningMatrix ); + + s.x += (v.x * weight); + s.y += (v.y * weight); + s.z += (v.z * weight); } } - }; + for (var i = 0; i < geometry.vertices.length; i ++) { + + geometry.vertices[i] = skinned[i]; + + } + + } function applySkin ( geometry, instanceCtrl, frame ) { @@ -570,72 +699,336 @@ THREE.ColladaLoader = function () { } var animationBounds = calcAnimationBounds(); - var skeleton = daeScene.getChildById( instanceCtrl.skeleton[0], true ) || - daeScene.getChildBySid( instanceCtrl.skeleton[0], true ); + var skeleton = visualScene.getChildById( instanceCtrl.skeleton[0], true ) || visualScene.getChildBySid( instanceCtrl.skeleton[0], true ); + + //flatten the skeleton into a list of bones + var bonelist = flattenSkeleton(skeleton); + var joints = skinController.skin.joints; + + //sort that list so that the order reflects the order in the joint list + var sortedbones = []; + for (var i = 0; i < joints.length; i ++) { + + for (var j = 0; j < bonelist.length; j ++) { + + if (bonelist[j].name === joints[i]) { + + sortedbones[i] = bonelist[j]; + + } + + } + + } + + //hook up the parents by index instead of name + for (var i = 0; i < sortedbones.length; i ++) { + + for (var j = 0; j < sortedbones.length; j ++) { + + if (sortedbones[i].parent === sortedbones[j].name) { + + sortedbones[i].parent = j; + + } + + } + + } + var i, j, w, vidx, weight; var v = new THREE.Vector3(), o, s; // move vertices to bind shape - for ( i = 0; i < geometry.vertices.length; i ++ ) { - geometry.vertices[i].applyMatrix4( skinController.skin.bindShapeMatrix ); + } + + var skinIndices = []; + var skinWeights = []; + var weights = skinController.skin.weights; + + // hook up the skin weights + // TODO - this might be a good place to choose greatest 4 weights + for ( var i =0; i < weights.length; i ++ ) { + + var indicies = new THREE.Vector4(weights[i][0] ? weights[i][0].joint : 0,weights[i][1] ? weights[i][1].joint : 0,weights[i][2] ? weights[i][2].joint : 0,weights[i][3] ? weights[i][3].joint : 0); + var weight = new THREE.Vector4(weights[i][0] ? weights[i][0].weight : 0,weights[i][1] ? weights[i][1].weight : 0,weights[i][2] ? weights[i][2].weight : 0,weights[i][3] ? weights[i][3].weight : 0); + + skinIndices.push(indicies); + skinWeights.push(weight); } + geometry.skinIndices = skinIndices; + geometry.skinWeights = skinWeights; + geometry.bones = sortedbones; // process animation, or simply pose the rig if no animation - for ( frame = 0; frame < animationBounds.frames; frame ++ ) { + //create an animation for the animated bones + //NOTE: this has no effect when using morphtargets + var animationdata = { "name":animationBounds.ID,"fps":30,"length":animationBounds.frames / 30,"hierarchy":[] }; - var bones = []; - var skinned = []; + for (var j = 0; j < sortedbones.length; j ++) { + + animationdata.hierarchy.push({ parent:sortedbones[j].parent, name:sortedbones[j].name, keys:[] }); - // zero skinned vertices + } - for ( i = 0; i < geometry.vertices.length; i++ ) { + console.log( 'ColladaLoader:', animationBounds.ID + ' has ' + sortedbones.length + ' bones.' ); - skinned.push( new THREE.Vector3() ); - } + skinToBindPose(geometry, skeleton, skinController); + + + for ( frame = 0; frame < animationBounds.frames; frame ++ ) { + + var bones = []; + var skinned = []; // process the frame and setup the rig with a fresh // transform, possibly from the bone's animation channel(s) setupSkeleton( skeleton, bones, frame ); setupSkinningMatrices( bones, skinController.skin ); - // skin 'm + for (var i = 0; i < bones.length; i ++) { + + for (var j = 0; j < animationdata.hierarchy.length; j ++) { + + if (animationdata.hierarchy[j].name === bones[i].sid) { + + var key = {}; + key.time = (frame / 30); + key.matrix = bones[i].animatrix; + + if (frame === 0) + bones[i].matrix = key.matrix; + + var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ]; + key.matrix.decompose(data[0], data[1], data[2]); + + key.pos = [ data[0].x,data[0].y,data[0].z ]; + + key.scl = [ data[2].x,data[2].y,data[2].z ]; + key.rot = data[1]; + + animationdata.hierarchy[j].keys.push(key); + + } + + } + + } + + geometry.animation = animationdata; + + } + + }; + + function createKinematics() { + + if ( kinematicsModel && kinematicsModel.joints.length === 0 ) { + kinematics = undefined; + return; + } + + var jointMap = {}; + + var _addToMap = function( jointIndex, parentVisualElement ) { + + var parentVisualElementId = parentVisualElement.getAttribute( 'id' ); + var colladaNode = visualScene.getChildById( parentVisualElementId, true ); + var joint = kinematicsModel.joints[ jointIndex ]; + + scene.traverse(function( node ) { + + if ( node.colladaId == parentVisualElementId ) { + + jointMap[ jointIndex ] = { + node: node, + transforms: colladaNode.transforms, + joint: joint, + position: joint.zeroPosition + }; + + } + + }); + + }; + + kinematics = { + + joints: kinematicsModel && kinematicsModel.joints, + + getJointValue: function( jointIndex ) { + + var jointData = jointMap[ jointIndex ]; + + if ( jointData ) { + + return jointData.position; + + } else { + + console.log( 'getJointValue: joint ' + jointIndex + ' doesn\'t exist' ); + + } + + }, + + setJointValue: function( jointIndex, value ) { + + var jointData = jointMap[ jointIndex ]; + + if ( jointData ) { + + var joint = jointData.joint; + + if ( value > joint.limits.max || value < joint.limits.min ) { + + console.log( 'setJointValue: joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ')' ); + + } else if ( joint.static ) { + + console.log( 'setJointValue: joint ' + jointIndex + ' is static' ); + + } else { + + var threejsNode = jointData.node; + var axis = joint.axis; + var transforms = jointData.transforms; + + var matrix = new THREE.Matrix4(); + + for (i = 0; i < transforms.length; i ++ ) { + + var transform = transforms[ i ]; + + // kinda ghetto joint detection + if ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) { - for ( i = 0; i < bones.length; i ++ ) { + // apply actual joint value here + switch ( joint.type ) { - if ( bones[ i ].type != 'JOINT' ) continue; + case 'revolute': - for ( j = 0; j < bones[ i ].weights.length; j ++ ) { + matrix.multiply( m1.makeRotationAxis( axis, THREE.Math.degToRad(value) ) ); + break; - w = bones[ i ].weights[ j ]; - vidx = w.index; - weight = w.weight; + case 'prismatic': - o = geometry.vertices[vidx]; - s = skinned[vidx]; + matrix.multiply( m1.makeTranslation(axis.x * value, axis.y * value, axis.z * value ) ); + break; + + default: + + console.warn( 'setJointValue: unknown joint type: ' + joint.type ); + break; + + } + + } else { + + var m1 = new THREE.Matrix4(); + + switch ( transform.type ) { + + case 'matrix': + + matrix.multiply( transform.obj ); + + break; + + case 'translate': + + matrix.multiply( m1.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) ); + + break; + + case 'rotate': + + matrix.multiply( m1.makeRotationAxis( transform.obj, transform.angle ) ); + + break; + + } + } + } - v.x = o.x; - v.y = o.y; - v.z = o.z; + // apply the matrix to the threejs node + var elementsFloat32Arr = matrix.elements; + var elements = Array.prototype.slice.call( elementsFloat32Arr ); + + var elementsRowMajor = [ + elements[ 0 ], + elements[ 4 ], + elements[ 8 ], + elements[ 12 ], + elements[ 1 ], + elements[ 5 ], + elements[ 9 ], + elements[ 13 ], + elements[ 2 ], + elements[ 6 ], + elements[ 10 ], + elements[ 14 ], + elements[ 3 ], + elements[ 7 ], + elements[ 11 ], + elements[ 15 ] + ]; + + threejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor ); + threejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale ); + } - v.applyMatrix4( bones[i].skinningMatrix ); + } else { - s.x += (v.x * weight); - s.y += (v.y * weight); - s.z += (v.z * weight); + console.log( 'setJointValue: joint ' + jointIndex + ' doesn\'t exist' ); } } - geometry.morphTargets.push( { name: "target_" + frame, vertices: skinned } ); + }; + + var element = COLLADA.querySelector('scene instance_kinematics_scene'); + + if ( element ) { + + for ( var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[ i ]; + + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'bind_joint_axis': + + var visualTarget = child.getAttribute( 'target' ).split( '/' ).pop(); + var axis = child.querySelector('axis param').textContent; + var jointIndex = parseInt( axis.split( 'joint' ).pop().split( '.' )[0] ); + var visualTargetElement = COLLADA.querySelector( '[sid="' + visualTarget + '"]' ); + + if ( visualTargetElement ) { + var parentVisualElement = visualTargetElement.parentElement; + _addToMap(jointIndex, parentVisualElement); + } + + break; + + default: + + break; + + } + } } }; @@ -735,7 +1128,7 @@ THREE.ColladaLoader = function () { if ( !geometry.mesh || !geometry.mesh.primitives ) continue; - if ( obj.name.length == 0 ) { + if ( obj.name.length === 0 ) { obj.name = geometry.id; @@ -771,7 +1164,7 @@ THREE.ColladaLoader = function () { used_materials[ instance_material.symbol ] = num_materials; used_materials_array.push( material3js ); first_material = material3js; - first_material.name = mat.name == null || mat.name === '' ? mat.id : mat.name; + first_material.name = mat.name === null || mat.name === '' ? mat.id : mat.name; num_materials ++; } @@ -779,7 +1172,7 @@ THREE.ColladaLoader = function () { } var mesh; - var material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } ); + var material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } ); var geom = geometry.mesh.geometry3js; if ( num_materials > 1 ) { @@ -797,16 +1190,33 @@ THREE.ColladaLoader = function () { if ( skinController !== undefined ) { + applySkin( geom, skinController ); - material.morphTargets = true; + if ( geom.morphTargets.length > 0 ) { + + material.morphTargets = true; + material.skinning = false; + + } else { + + material.morphTargets = false; + material.skinning = true; + + } + mesh = new THREE.SkinnedMesh( geom, material, false ); - mesh.skeleton = skinController.skeleton; - mesh.skinController = controllers[ skinController.url ]; - mesh.skinInstanceController = skinController; + + + //mesh.skeleton = skinController.skeleton; + //mesh.skinController = controllers[ skinController.url ]; + //mesh.skinInstanceController = skinController; mesh.name = 'skin_' + skins.length; + + + //mesh.animationHandle.setKey(0); skins.push( mesh ); } else if ( morphController !== undefined ) { @@ -822,13 +1232,19 @@ THREE.ColladaLoader = function () { } else { - mesh = new THREE.Mesh( geom, material ); - mesh.geometry.name = geometry.name; - // mesh.geom.name = geometry.id; + if ( geom.isLineStrip === true ) { + + mesh = new THREE.Line( geom ); + + } else { + + mesh = new THREE.Mesh( geom, material ); + + } } - node.geometries.length > 1 ? obj.add( mesh ) : obj = mesh; + obj.add(mesh); } @@ -839,13 +1255,15 @@ THREE.ColladaLoader = function () { var instance_camera = node.cameras[i]; var cparams = cameras[instance_camera.url]; - obj = new THREE.PerspectiveCamera(cparams.fov, parseFloat(cparams.aspect_ratio), + var cam = new THREE.PerspectiveCamera(cparams.yfov, parseFloat(cparams.aspect_ratio), parseFloat(cparams.znear), parseFloat(cparams.zfar)); + obj.add(cam); } for ( i = 0; i < node.lights.length; i ++ ) { + var light = null; var instance_light = node.lights[i]; var lparams = lights[instance_light.url]; @@ -853,7 +1271,7 @@ THREE.ColladaLoader = function () { var color = lparams.color.getHex(); var intensity = lparams.intensity; - var distance = 0; + var distance = lparams.distance; var angle = lparams.falloff_angle; var exponent; // Intentionally undefined, don't know what this is yet @@ -861,37 +1279,44 @@ THREE.ColladaLoader = function () { case 'directional': - obj = new THREE.DirectionalLight( color, intensity, distance ); + light = new THREE.DirectionalLight( color, intensity, distance ); + light.position.set(0, 0, 1); break; case 'point': - obj = new THREE.PointLight( color, intensity, distance ); + light = new THREE.PointLight( color, intensity, distance ); break; case 'spot': - obj = new THREE.SpotLight( color, intensity, distance, angle, exponent ); + light = new THREE.SpotLight( color, intensity, distance, angle, exponent ); + light.position.set(0, 0, 1); break; case 'ambient': - obj = new THREE.AmbientLight( color ); + light = new THREE.AmbientLight( color ); break; } } + if (light) { + obj.add(light); + } } obj.name = node.name || node.id || ""; + obj.colladaId = node.id || ""; + obj.layer = node.layer || ""; obj.matrix = node.matrix; obj.matrix.decompose( obj.position, obj.quaternion, obj.scale ); if ( options.centerGeometry && obj.geometry ) { - var delta = THREE.GeometryUtils.center( obj.geometry ); + var delta = obj.geometry.center(); delta.multiply( obj.scale ); delta.applyQuaternion( obj.quaternion ); @@ -913,7 +1338,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < skin.joints.length; i ++ ) { - if ( skin.joints[ i ] == id ) { + if ( skin.joints[ i ] === id ) { return i; @@ -925,11 +1350,25 @@ THREE.ColladaLoader = function () { function getLibraryNode( id ) { - return COLLADA.evaluate( './/dae:library_nodes//dae:node[@id=\'' + id + '\']', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ).iterateNext(); + var nodes = COLLADA.querySelectorAll('library_nodes node'); + + for ( var i = 0; i < nodes.length; i++ ) { + + var attObj = nodes[i].attributes.getNamedItem('id'); + + if ( attObj && attObj.value === id ) { + + return nodes[i]; + + } + + } + + return undefined; }; - function getChannelsForNode (node ) { + function getChannelsForNode ( node ) { var channels = []; var startTime = 1000000; @@ -1067,7 +1506,7 @@ THREE.ColladaLoader = function () { var keys = [], sids = []; - for ( var i = 0, il = node.channels.length; i < il; i++ ) { + for ( var i = 0, il = node.channels.length; i < il; i ++ ) { var channel = node.channels[i], fullSid = channel.fullSid, @@ -1080,7 +1519,7 @@ THREE.ColladaLoader = function () { member = []; - for ( var j = 0, jl = channel.arrIndices.length; j < jl; j++ ) { + for ( var j = 0, jl = channel.arrIndices.length; j < jl; j ++ ) { member[ j ] = getConvertedIndex( channel.arrIndices[ j ] ); @@ -1100,17 +1539,17 @@ THREE.ColladaLoader = function () { } - for ( var j = 0, jl = input.length; j < jl; j++ ) { + for ( var j = 0, jl = input.length; j < jl; j ++ ) { var time = input[j], - data = sampler.getData( transform.type, j ), + data = sampler.getData( transform.type, j, member ), key = findKey( keys, time ); if ( !key ) { key = new Key( time ); var timeNdx = findTimeNdx( keys, time ); - keys.splice( timeNdx == -1 ? keys.length : timeNdx, 0, key ); + keys.splice( timeNdx === -1 ? keys.length : timeNdx, 0, key ); } @@ -1127,11 +1566,11 @@ THREE.ColladaLoader = function () { } // post process - for ( var i = 0; i < sids.length; i++ ) { + for ( var i = 0; i < sids.length; i ++ ) { var sid = sids[ i ]; - for ( var j = 0; j < keys.length; j++ ) { + for ( var j = 0; j < keys.length; j ++ ) { var key = keys[ j ]; @@ -1156,7 +1595,7 @@ THREE.ColladaLoader = function () { var retVal = null; - for ( var i = 0, il = keys.length; i < il && retVal == null; i++ ) { + for ( var i = 0, il = keys.length; i < il && retVal === null; i ++ ) { var key = keys[i]; @@ -1180,7 +1619,7 @@ THREE.ColladaLoader = function () { var ndx = -1; - for ( var i = 0, il = keys.length; i < il && ndx == -1; i++ ) { + for ( var i = 0, il = keys.length; i < il && ndx === -1; i ++ ) { var key = keys[i]; @@ -1198,8 +1637,8 @@ THREE.ColladaLoader = function () { function interpolateKeys ( keys, key, ndx, fullSid ) { - var prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx-1 : 0 ), - nextKey = getNextKeyWith( keys, fullSid, ndx+1 ); + var prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx - 1 : 0 ), + nextKey = getNextKeyWith( keys, fullSid, ndx + 1 ); if ( prevKey && nextKey ) { @@ -1217,7 +1656,7 @@ THREE.ColladaLoader = function () { data = []; - for ( var i = 0; i < prevData.length; ++i ) { + for ( var i = 0; i < prevData.length; ++ i ) { data[ i ] = prevData[ i ] + ( nextData[ i ] - prevData[ i ] ) * scale; @@ -1239,7 +1678,7 @@ THREE.ColladaLoader = function () { function getNextKeyWith( keys, fullSid, ndx ) { - for ( ; ndx < keys.length; ndx++ ) { + for ( ; ndx < keys.length; ndx ++ ) { var key = keys[ ndx ]; @@ -1261,7 +1700,7 @@ THREE.ColladaLoader = function () { ndx = ndx >= 0 ? ndx : ndx + keys.length; - for ( ; ndx >= 0; ndx-- ) { + for ( ; ndx >= 0; ndx -- ) { var key = keys[ ndx ]; @@ -1292,7 +1731,7 @@ THREE.ColladaLoader = function () { var child = element.childNodes[ i ]; - if ( child.nodeName == 'init_from' ) { + if ( child.nodeName === 'init_from' ) { this.init_from = child.textContent; @@ -1320,7 +1759,7 @@ THREE.ColladaLoader = function () { this.name = element.getAttribute('name'); this.type = "none"; - for ( var i = 0; i < element.childNodes.length; i++ ) { + for ( var i = 0; i < element.childNodes.length; i ++ ) { var child = element.childNodes[ i ]; @@ -1523,11 +1962,11 @@ THREE.ColladaLoader = function () { var input = ( new Input() ).parse( child ); var source = sources[ input.source ]; - if ( input.semantic == 'JOINT' ) { + if ( input.semantic === 'JOINT' ) { this.joints = source.read(); - } else if ( input.semantic == 'INV_BIND_MATRIX' ) { + } else if ( input.semantic === 'INV_BIND_MATRIX' ) { this.invBindMatrices = source.read(); @@ -1583,7 +2022,7 @@ THREE.ColladaLoader = function () { var numBones = vcount[i]; var vertex_weights = []; - for ( var j = 0; j < numBones; j++ ) { + for ( var j = 0; j < numBones; j ++ ) { var influence = {}; @@ -1632,7 +2071,7 @@ THREE.ColladaLoader = function () { this.id = ""; this.name = ""; this.nodes = []; - this.scene = new THREE.Object3D(); + this.scene = new THREE.Group(); }; @@ -1747,7 +2186,7 @@ THREE.ColladaLoader = function () { } - if ( sid == transformSid ) { + if ( sid === transformSid ) { channel.info = { sid: sid, dotSyntax: dotSyntax, arrSyntax: arrSyntax, arrIndices: arrIndices }; return channel; @@ -1762,7 +2201,7 @@ THREE.ColladaLoader = function () { Node.prototype.getChildById = function ( id, recursive ) { - if ( this.id == id ) { + if ( this.id === id ) { return this; @@ -1790,7 +2229,7 @@ THREE.ColladaLoader = function () { Node.prototype.getChildBySid = function ( sid, recursive ) { - if ( this.sid == sid ) { + if ( this.sid === sid ) { return this; @@ -1819,7 +2258,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < this.transforms.length; i ++ ) { - if ( this.transforms[ i ].sid == sid ) return this.transforms[ i ]; + if ( this.transforms[ i ].sid === sid ) return this.transforms[ i ]; } @@ -1835,8 +2274,9 @@ THREE.ColladaLoader = function () { this.sid = element.getAttribute('sid'); this.name = element.getAttribute('name'); this.type = element.getAttribute('type'); + this.layer = element.getAttribute('layer'); - this.type = this.type == 'JOINT' ? this.type : 'NODE'; + this.type = this.type === 'JOINT' ? this.type : 'NODE'; this.nodes = []; this.transforms = []; @@ -2202,21 +2642,16 @@ THREE.ColladaLoader = function () { case 'bind_material': - var instances = COLLADA.evaluate( './/dae:instance_material', child, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); - - if ( instances ) { - - var instance = instances.iterateNext(); - - while ( instance ) { + var instances = child.querySelectorAll('instance_material'); - this.instance_material.push( (new InstanceMaterial()).parse(instance) ); - instance = instances.iterateNext(); + for ( var j = 0; j < instances.length; j ++ ) { - } + var instance = instances[j]; + this.instance_material.push( (new InstanceMaterial()).parse(instance) ); } + break; case 'extra': @@ -2264,20 +2699,14 @@ THREE.ColladaLoader = function () { var child = element.childNodes[i]; if ( child.nodeType != 1 ) continue; - if ( child.nodeName == 'bind_material' ) { - - var instances = COLLADA.evaluate( './/dae:instance_material', child, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); - - if ( instances ) { + if ( child.nodeName === 'bind_material' ) { - var instance = instances.iterateNext(); + var instances = child.querySelectorAll('instance_material'); - while ( instance ) { + for ( var j = 0; j < instances.length; j ++ ) { - this.instance_material.push( (new InstanceMaterial()).parse(instance) ); - instance = instances.iterateNext(); - - } + var instance = instances[j]; + this.instance_material.push( (new InstanceMaterial()).parse(instance) ); } @@ -2294,7 +2723,6 @@ THREE.ColladaLoader = function () { function Geometry() { this.id = ""; - this.name = ""; this.mesh = null; }; @@ -2302,7 +2730,6 @@ THREE.ColladaLoader = function () { Geometry.prototype.parse = function ( element ) { this.id = element.getAttribute('id'); - this.name = element.getAttribute('name'); extractDoubleSided( this, element ); @@ -2340,13 +2767,11 @@ THREE.ColladaLoader = function () { }; - Mesh.prototype.parse = function( element ) { + Mesh.prototype.parse = function ( element ) { this.primitives = []; - var i, j; - - for ( i = 0; i < element.childNodes.length; i ++ ) { + for ( var i = 0; i < element.childNodes.length; i ++ ) { var child = element.childNodes[ i ]; @@ -2362,6 +2787,11 @@ THREE.ColladaLoader = function () { this.vertices = ( new Vertices() ).parse( child ); break; + case 'linestrips': + + this.primitives.push( ( new LineStrips().parse( child ) ) ); + break; + case 'triangles': this.primitives.push( ( new Triangles().parse( child ) ) ); @@ -2386,15 +2816,23 @@ THREE.ColladaLoader = function () { this.geometry3js = new THREE.Geometry(); + if ( this.vertices === null ) { + + // TODO (mrdoob): Study case when this is null (carrier.dae) + + return this; + + } + var vertexData = sources[ this.vertices.input['POSITION'].source ].data; - for ( i = 0; i < vertexData.length; i += 3 ) { + for ( var i = 0; i < vertexData.length; i += 3 ) { this.geometry3js.vertices.push( getConvertedVec3( vertexData, i ).clone() ); } - for ( i = 0; i < this.primitives.length; i ++ ) { + for ( var i = 0; i < this.primitives.length; i ++ ) { var primitive = this.primitives[ i ]; primitive.setVertices( this.vertices ); @@ -2402,9 +2840,6 @@ THREE.ColladaLoader = function () { } - this.geometry3js.computeCentroids(); - this.geometry3js.computeFaceNormals(); - if ( this.geometry3js.calcNormals ) { this.geometry3js.computeVertexNormals(); @@ -2412,13 +2847,20 @@ THREE.ColladaLoader = function () { } - // this.geometry3js.computeBoundingBox(); - return this; }; - Mesh.prototype.handlePrimitive = function( primitive, geom ) { + Mesh.prototype.handlePrimitive = function ( primitive, geom ) { + + if ( primitive instanceof LineStrips ) { + + // TODO: Handle indices. Maybe easier with BufferGeometry? + + geom.isLineStrip = true; + return; + + } var j, k, pList = primitive.p, inputs = primitive.inputs; var input, index, idx32; @@ -2429,8 +2871,9 @@ THREE.ColladaLoader = function () { for ( j = 0; j < inputs.length; j ++ ) { input = inputs[ j ]; + var offset = input.offset + 1; - maxOffset = (maxOffset < offset)? offset : maxOffset; + maxOffset = (maxOffset < offset) ? offset : maxOffset; switch ( input.semantic ) { @@ -2442,7 +2885,7 @@ THREE.ColladaLoader = function () { } - for ( var pCount = 0; pCount < pList.length; ++pCount ) { + for ( var pCount = 0; pCount < pList.length; ++ pCount ) { var p = pList[ pCount ], i = 0; @@ -2514,7 +2957,7 @@ THREE.ColladaLoader = function () { } - if ( ns.length == 0 ) { + if ( ns.length === 0 ) { // check the vertices inputs input = this.vertices.input.NORMAL; @@ -2524,7 +2967,7 @@ THREE.ColladaLoader = function () { source = sources[ input.source ]; numParams = source.accessor.params.length; - for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) { + for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) { ns.push( getConvertedVec3( source.data, vs[ ndx ] * numParams ) ); @@ -2550,7 +2993,7 @@ THREE.ColladaLoader = function () { source = sources[ input.source ]; numParams = source.accessor.params.length; - for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) { + for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) { idx32 = vs[ ndx ] * numParams; if ( ts[ input.set ] === undefined ) ts[ input.set ] = [ ]; @@ -2563,7 +3006,7 @@ THREE.ColladaLoader = function () { } - if ( cs.length == 0 ) { + if ( cs.length === 0 ) { // check the vertices inputs input = this.vertices.input.COLOR; @@ -2573,7 +3016,7 @@ THREE.ColladaLoader = function () { source = sources[ input.source ]; numParams = source.accessor.params.length; - for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) { + for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) { idx32 = vs[ ndx ] * numParams; cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) ); @@ -2592,9 +3035,9 @@ THREE.ColladaLoader = function () { } else if ( vcount === 4 ) { - faces.push( new THREE.Face3( vs[0], vs[1], vs[3], [ns[0], ns[1], ns[3]], cs.length ? [cs[0], cs[1], cs[3]] : new THREE.Color() ) ); + faces.push( new THREE.Face3( vs[0], vs[1], vs[3], [ ns[0].clone(), ns[1].clone(), ns[3].clone() ], cs.length ? [ cs[0], cs[1], cs[3] ] : new THREE.Color() ) ); - faces.push( new THREE.Face3( vs[1], vs[2], vs[3], [ns[1], ns[2], ns[3]], cs.length ? [cs[1], cs[2], cs[3]] : new THREE.Color() ) ); + faces.push( new THREE.Face3( vs[1], vs[2], vs[3], [ ns[1].clone(), ns[2].clone(), ns[3].clone() ], cs.length ? [ cs[1], cs[2], cs[3] ] : new THREE.Color() ) ); } else if ( vcount > 4 && options.subdivideFaces ) { @@ -2605,9 +3048,7 @@ THREE.ColladaLoader = function () { for ( k = 1; k < vcount - 1; ) { - // FIXME: normals don't seem to be quite right - - faces.push( new THREE.Face3( vs[0], vs[k], vs[k+1], [ ns[0], ns[k++], ns[k] ], clr ) ); + faces.push( new THREE.Face3( vs[0], vs[k], vs[k + 1], [ ns[0].clone(), ns[k ++].clone(), ns[k].clone() ], clr ) ); } @@ -2621,14 +3062,14 @@ THREE.ColladaLoader = function () { face.daeMaterial = primitive.material; geom.faces.push( face ); - for ( k = 0; k < texture_sets.length; k++ ) { + for ( k = 0; k < texture_sets.length; k ++ ) { uv = ts[ texture_sets[k] ]; if ( vcount > 4 ) { // Grab the right UVs for the vertices in this face - uvArr = [ uv[0], uv[ndx+1], uv[ndx+2] ]; + uvArr = [ uv[0], uv[ndx + 1], uv[ndx + 2] ]; } else if ( vcount === 4 ) { @@ -2669,6 +3110,7 @@ THREE.ColladaLoader = function () { i += maxOffset * vcount; } + } }; @@ -2688,7 +3130,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < this.inputs.length; i ++ ) { - if ( this.inputs[ i ].source == vertices.id ) { + if ( this.inputs[ i ].source === vertices.id ) { this.inputs[ i ].source = vertices.input[ 'POSITION' ].source; @@ -2749,6 +3191,18 @@ THREE.ColladaLoader = function () { }; Polylist.prototype = Object.create( Polygons.prototype ); + Polylist.prototype.constructor = Polylist; + + function LineStrips() { + + Polygons.call( this ); + + this.vcount = 1; + + }; + + LineStrips.prototype = Object.create( Polygons.prototype ); + LineStrips.prototype.constructor = LineStrips; function Triangles () { @@ -2759,6 +3213,7 @@ THREE.ColladaLoader = function () { }; Triangles.prototype = Object.create( Polygons.prototype ); + Triangles.prototype.constructor = Triangles; function Accessor() { @@ -2780,7 +3235,7 @@ THREE.ColladaLoader = function () { var child = element.childNodes[ i ]; - if ( child.nodeName == 'param' ) { + if ( child.nodeName === 'param' ) { var param = {}; param[ 'name' ] = child.getAttribute( 'name' ); @@ -2807,7 +3262,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < element.childNodes.length; i ++ ) { - if ( element.childNodes[i].nodeName == 'input' ) { + if ( element.childNodes[i].nodeName === 'input' ) { var input = ( new Input() ).parse( element.childNodes[ i ] ); this.input[ input.semantic ] = input; @@ -2836,7 +3291,7 @@ THREE.ColladaLoader = function () { this.set = _attr_as_int(element, 'set', -1); this.offset = _attr_as_int(element, 'offset', 0); - if ( this.semantic == 'TEXCOORD' && this.set < 0 ) { + if ( this.semantic === 'TEXCOORD' && this.set < 0 ) { this.set = 0; @@ -2892,7 +3347,7 @@ THREE.ColladaLoader = function () { for ( var j = 0; j < child.childNodes.length; j ++ ) { - if ( child.childNodes[ j ].nodeName == 'accessor' ) { + if ( child.childNodes[ j ].nodeName === 'accessor' ) { this.accessor = ( new Accessor() ).parse( child.childNodes[ j ] ); break; @@ -2919,35 +3374,35 @@ THREE.ColladaLoader = function () { //for (var i = 0; i < this.accessor.params.length; i++) { - var param = this.accessor.params[ 0 ]; + var param = this.accessor.params[ 0 ]; //console.log(param.name + " " + param.type); - switch ( param.type ) { + switch ( param.type ) { - case 'IDREF': - case 'Name': case 'name': - case 'float': + case 'IDREF': + case 'Name': case 'name': + case 'float': - return this.data; + return this.data; - case 'float4x4': + case 'float4x4': - for ( var j = 0; j < this.data.length; j += 16 ) { + for ( var j = 0; j < this.data.length; j += 16 ) { - var s = this.data.slice( j, j + 16 ); - var m = getConvertedMat4( s ); - result.push( m ); - } + var s = this.data.slice( j, j + 16 ); + var m = getConvertedMat4( s ); + result.push( m ); + } - break; + break; - default: + default: - console.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' ); - break; + console.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' ); + break; - } + } //} @@ -2970,7 +3425,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < element.childNodes.length; i ++ ) { - if ( element.childNodes[ i ].nodeName == 'instance_effect' ) { + if ( element.childNodes[ i ].nodeName === 'instance_effect' ) { this.instance_effect = ( new InstanceEffect() ).parse( element.childNodes[ i ] ); break; @@ -2997,7 +3452,7 @@ THREE.ColladaLoader = function () { ColorOrTexture.prototype.isColor = function () { - return ( this.texture == null ); + return ( this.texture === null ); }; @@ -3009,9 +3464,10 @@ THREE.ColladaLoader = function () { ColorOrTexture.prototype.parse = function ( element ) { - if (element.nodeName == 'transparent') - { + if (element.nodeName === 'transparent') { + this.opaque = element.getAttribute('opaque'); + } for ( var i = 0; i < element.childNodes.length; i ++ ) { @@ -3041,7 +3497,7 @@ THREE.ColladaLoader = function () { repeatU: 1, repeatV: 1, wrapU: 1, - wrapV: 1, + wrapV: 1 }; this.parseTexture( child ); break; @@ -3087,16 +3543,29 @@ THREE.ColladaLoader = function () { case 'repeatV': this.texOpts[ child.nodeName ] = parseFloat( child.textContent ); + break; - case 'wrapU': - case 'wrapV': + case 'wrapU': + case 'wrapV': + + // some dae have a value of true which becomes NaN via parseInt + + if ( child.textContent.toUpperCase() === 'TRUE' ) { + + this.texOpts[ child.nodeName ] = 1; + + } else { + + this.texOpts[ child.nodeName ] = parseInt( child.textContent ); - this.texOpts[ child.nodeName ] = parseInt( child.textContent ); + } break; default: + this.texOpts[ child.nodeName ] = child.textContent; + break; } @@ -3124,7 +3593,6 @@ THREE.ColladaLoader = function () { switch ( child.nodeName ) { - case 'ambient': case 'emission': case 'diffuse': case 'specular': @@ -3133,12 +3601,34 @@ THREE.ColladaLoader = function () { this[ child.nodeName ] = ( new ColorOrTexture() ).parse( child ); break; + case 'bump': + + // If 'bumptype' is 'heightfield', create a 'bump' property + // Else if 'bumptype' is 'normalmap', create a 'normal' property + // (Default to 'bump') + var bumpType = child.getAttribute( 'bumptype' ); + if ( bumpType ) { + if ( bumpType.toLowerCase() === "heightfield" ) { + this[ 'bump' ] = ( new ColorOrTexture() ).parse( child ); + } else if ( bumpType.toLowerCase() === "normalmap" ) { + this[ 'normal' ] = ( new ColorOrTexture() ).parse( child ); + } else { + console.error( "Shader.prototype.parse: Invalid value for attribute 'bumptype' (" + bumpType + ") - valid bumptypes are 'HEIGHTFIELD' and 'NORMALMAP' - defaulting to 'HEIGHTFIELD'" ); + this[ 'bump' ] = ( new ColorOrTexture() ).parse( child ); + } + } else { + console.warn( "Shader.prototype.parse: Attribute 'bumptype' missing from bump node - defaulting to 'HEIGHTFIELD'" ); + this[ 'bump' ] = ( new ColorOrTexture() ).parse( child ); + } + + break; + case 'shininess': case 'reflectivity': case 'index_of_refraction': case 'transparency': - var f = evaluateXPath( child, './/dae:float' ); + var f = child.querySelectorAll('float'); if ( f.length > 0 ) this[ child.nodeName ] = parseFloat( f[ 0 ].textContent ); @@ -3162,23 +3652,30 @@ THREE.ColladaLoader = function () { var props = {}; var transparent = false; - if (this['transparency'] !== undefined && this['transparent'] !== undefined) - { + + if (this['transparency'] !== undefined && this['transparent'] !== undefined) { // convert transparent color RBG to average value var transparentColor = this['transparent']; - var transparencyLevel = (this.transparent.color.r + - this.transparent.color.g + - this.transparent.color.b) - / 3 * this.transparency; + var transparencyLevel = (this.transparent.color.r + this.transparent.color.g + this.transparent.color.b) / 3 * this.transparency; - if (transparencyLevel > 0) - { + if (transparencyLevel > 0) { transparent = true; props[ 'transparent' ] = true; props[ 'opacity' ] = 1 - transparencyLevel; + } + } + var keys = { + 'diffuse':'map', + 'ambient':'lightMap', + 'specular':'specularMap', + 'emission':'emissionMap', + 'bump':'bumpMap', + 'normal':'normalMap' + }; + for ( var prop in this ) { switch ( prop ) { @@ -3187,6 +3684,8 @@ THREE.ColladaLoader = function () { case 'emission': case 'diffuse': case 'specular': + case 'bump': + case 'normal': var cot = this[ prop ]; @@ -3195,36 +3694,51 @@ THREE.ColladaLoader = function () { if ( cot.isTexture() ) { var samplerId = cot.texture; - - - var image; - var surfaceId = this.effect.sampler[samplerId]; + if ( surfaceId !== undefined && surfaceId.source !== undefined ) { + var surface = this.effect.surface[surfaceId.source]; - image = images[surface.init_from]; - } - else { - image = images[samplerId]; - } - if (image) { + if ( surface !== undefined ) { + + var image = images[ surface.init_from ]; + + if ( image ) { + + var url = baseUrl + image.init_from; + + var texture; + var loader = THREE.Loader.Handlers.get( url ); - var texture = THREE.ImageUtils.loadTexture(baseUrl + image.init_from); - texture.wrapS = cot.texOpts.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; - texture.wrapT = cot.texOpts.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; - texture.offset.x = cot.texOpts.offsetU; - texture.offset.y = cot.texOpts.offsetV; - texture.repeat.x = cot.texOpts.repeatU; - texture.repeat.y = cot.texOpts.repeatV; - props['map'] = texture; + if ( loader !== null ) { - // Texture with baked lighting? - if (prop === 'emission') props['emissive'] = 0xffffff; + texture = loader.load( url ); + + } else { + + texture = new THREE.Texture(); + + loadTextureImage( texture, url ); + + } + + texture.wrapS = cot.texOpts.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + texture.wrapT = cot.texOpts.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + texture.offset.x = cot.texOpts.offsetU; + texture.offset.y = cot.texOpts.offsetV; + texture.repeat.x = cot.texOpts.repeatU; + texture.repeat.y = cot.texOpts.repeatV; + props[keys[prop]] = texture; + + // Texture with baked lighting? + if (prop === 'emission') props['emissive'] = 0xffffff; + + } } -// } + } } else if ( prop === 'diffuse' || !transparent ) { @@ -3252,7 +3766,7 @@ THREE.ColladaLoader = function () { case 'reflectivity': props[ prop ] = this[ prop ]; - if( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap; + if ( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap; props['combine'] = THREE.MixOperation; //mix regular shading with reflective component break; @@ -3420,7 +3934,7 @@ THREE.ColladaLoader = function () { Effect.prototype.create = function () { - if ( this.shader == null ) { + if ( this.shader === null ) { return null; @@ -3545,7 +4059,7 @@ THREE.ColladaLoader = function () { }; - Effect.prototype.parseTechnique= function ( element ) { + Effect.prototype.parseTechnique = function ( element ) { for ( var i = 0; i < element.childNodes.length; i ++ ) { @@ -3561,7 +4075,51 @@ THREE.ColladaLoader = function () { this.shader = ( new Shader( child.nodeName, this ) ).parse( child ); break; + case 'extra': + this.parseExtra(child); + break; + default: + break; + + } + + } + + }; + + Effect.prototype.parseExtra = function ( element ) { + + for ( var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[i]; + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'technique': + this.parseExtraTechnique( child ); + break; + default: + break; + + } + + } + + }; + + Effect.prototype.parseExtraTechnique = function ( element ) { + + for ( var i = 0; i < element.childNodes.length; i ++ ) { + var child = element.childNodes[i]; + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'bump': + this.shader.parse( element ); + break; default: break; @@ -3821,7 +4379,7 @@ THREE.ColladaLoader = function () { }; - Sampler.prototype.getData = function ( type, ndx ) { + Sampler.prototype.getData = function ( type, ndx, member ) { var data; @@ -3834,7 +4392,7 @@ THREE.ColladaLoader = function () { data = []; ndx *= this.strideOut; - for ( var i = 0; i < this.strideOut; ++i ) { + for ( var i = 0; i < this.strideOut; ++ i ) { data[ i ] = this.output[ ndx + i ]; @@ -3867,6 +4425,10 @@ THREE.ColladaLoader = function () { data = this.output[ ndx ]; + if ( member && type === 'translate' ) { + data = getConvertedTranslation( member, data ); + } + } return data; @@ -3893,7 +4455,7 @@ THREE.ColladaLoader = function () { Key.prototype.apply = function ( opt_sid ) { - for ( var i = 0; i < this.targets.length; ++i ) { + for ( var i = 0; i < this.targets.length; ++ i ) { var target = this.targets[ i ]; @@ -3909,7 +4471,7 @@ THREE.ColladaLoader = function () { Key.prototype.getTarget = function ( fullSid ) { - for ( var i = 0; i < this.targets.length; ++i ) { + for ( var i = 0; i < this.targets.length; ++ i ) { if ( this.targets[ i ].sid === fullSid ) { @@ -3925,7 +4487,7 @@ THREE.ColladaLoader = function () { Key.prototype.hasTarget = function ( fullSid ) { - for ( var i = 0; i < this.targets.length; ++i ) { + for ( var i = 0; i < this.targets.length; ++ i ) { if ( this.targets[ i ].sid === fullSid ) { @@ -3942,7 +4504,7 @@ THREE.ColladaLoader = function () { // TODO: Currently only doing linear interpolation. Should support full COLLADA spec. Key.prototype.interpolate = function ( nextKey, time ) { - for ( var i = 0; i < this.targets.length; ++i ) { + for ( var i = 0, l = this.targets.length; i < l; i ++ ) { var target = this.targets[ i ], nextTarget = nextKey.getTarget( target.sid ), @@ -3954,20 +4516,14 @@ THREE.ColladaLoader = function () { nextData = nextTarget.data, prevData = target.data; - // check scale error - - if ( scale < 0 || scale > 1 ) { - - console.log( "Key.interpolate: Warning! Scale out of bounds:" + scale ); - scale = scale < 0 ? 0 : 1; - - } + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; if ( prevData.length ) { data = []; - for ( var j = 0; j < prevData.length; ++j ) { + for ( var j = 0; j < prevData.length; ++ j ) { data[ j ] = prevData[ j ] + ( nextData[ j ] - prevData[ j ] ) * scale; @@ -4032,7 +4588,7 @@ THREE.ColladaLoader = function () { for ( var i = 0; i < element.childNodes.length; i ++ ) { - if ( element.childNodes[ i ].nodeName == 'technique_common' ) { + if ( element.childNodes[ i ].nodeName === 'technique_common' ) { var technique = element.childNodes[ i ]; @@ -4040,7 +4596,7 @@ THREE.ColladaLoader = function () { this.technique = technique.childNodes[ j ].nodeName; - if ( this.technique == 'perspective' ) { + if ( this.technique === 'perspective' ) { var perspective = technique.childNodes[ j ]; @@ -4070,7 +4626,7 @@ THREE.ColladaLoader = function () { } - } else if ( this.technique == 'orthographic' ) { + } else if ( this.technique === 'orthographic' ) { var orthographic = technique.childNodes[ j ]; @@ -4202,6 +4758,10 @@ THREE.ColladaLoader = function () { this.falloff_angle = parseFloat( child.textContent ); break; + + case 'quadratic_attenuation': + var f = parseFloat( child.textContent ); + this.distance = f ? Math.sqrt( 1 / f ) : 0; } } @@ -4251,6 +4811,231 @@ THREE.ColladaLoader = function () { }; + function KinematicsModel( ) { + + this.id = ''; + this.name = ''; + this.joints = []; + this.links = []; + + } + + KinematicsModel.prototype.parse = function( element ) { + + this.id = element.getAttribute('id'); + this.name = element.getAttribute('name'); + this.joints = []; + this.links = []; + + for (var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[ i ]; + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'technique_common': + + this.parseCommon(child); + break; + + default: + break; + + } + + } + + return this; + + }; + + KinematicsModel.prototype.parseCommon = function( element ) { + + for (var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[ i ]; + if ( child.nodeType != 1 ) continue; + + switch ( element.childNodes[ i ].nodeName ) { + + case 'joint': + this.joints.push( (new Joint()).parse(child) ); + break; + + case 'link': + this.links.push( (new Link()).parse(child) ); + break; + + default: + break; + + } + + } + + return this; + + }; + + function Joint( ) { + + this.sid = ''; + this.name = ''; + this.axis = new THREE.Vector3(); + this.limits = { + min: 0, + max: 0 + }; + this.type = ''; + this.static = false; + this.zeroPosition = 0.0; + this.middlePosition = 0.0; + + } + + Joint.prototype.parse = function( element ) { + + this.sid = element.getAttribute('sid'); + this.name = element.getAttribute('name'); + this.axis = new THREE.Vector3(); + this.limits = { + min: 0, + max: 0 + }; + this.type = ''; + this.static = false; + this.zeroPosition = 0.0; + this.middlePosition = 0.0; + + var axisElement = element.querySelector('axis'); + var _axis = _floats(axisElement.textContent); + this.axis = getConvertedVec3(_axis, 0); + + var min = element.querySelector('limits min') ? parseFloat(element.querySelector('limits min').textContent) : -360; + var max = element.querySelector('limits max') ? parseFloat(element.querySelector('limits max').textContent) : 360; + + this.limits = { + min: min, + max: max + }; + + var jointTypes = [ 'prismatic', 'revolute' ]; + for (var i = 0; i < jointTypes.length; i ++ ) { + + var type = jointTypes[ i ]; + + var jointElement = element.querySelector(type); + + if ( jointElement ) { + + this.type = type; + + } + + } + + // if the min is equal to or somehow greater than the max, consider the joint static + if ( this.limits.min >= this.limits.max ) { + + this.static = true; + + } + + this.middlePosition = (this.limits.min + this.limits.max) / 2.0; + return this; + + }; + + function Link( ) { + + this.sid = ''; + this.name = ''; + this.transforms = []; + this.attachments = []; + + } + + Link.prototype.parse = function( element ) { + + this.sid = element.getAttribute('sid'); + this.name = element.getAttribute('name'); + this.transforms = []; + this.attachments = []; + + for (var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[ i ]; + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'attachment_full': + this.attachments.push( (new Attachment()).parse(child) ); + break; + + case 'rotate': + case 'translate': + case 'matrix': + + this.transforms.push( (new Transform()).parse(child) ); + break; + + default: + + break; + + } + + } + + return this; + + }; + + function Attachment( ) { + + this.joint = ''; + this.transforms = []; + this.links = []; + + } + + Attachment.prototype.parse = function( element ) { + + this.joint = element.getAttribute('joint').split('/').pop(); + this.links = []; + + for (var i = 0; i < element.childNodes.length; i ++ ) { + + var child = element.childNodes[ i ]; + if ( child.nodeType != 1 ) continue; + + switch ( child.nodeName ) { + + case 'link': + this.links.push( (new Link()).parse(child) ); + break; + + case 'rotate': + case 'translate': + case 'matrix': + + this.transforms.push( (new Transform()).parse(child) ); + break; + + default: + + break; + + } + + } + + return this; + + }; + function _source( element ) { var id = element.getAttribute( 'id' ); @@ -4268,7 +5053,7 @@ THREE.ColladaLoader = function () { function _nsResolver( nsPrefix ) { - if ( nsPrefix == "dae" ) { + if ( nsPrefix === "dae" ) { return "http://www.collada.org/2005/11/COLLADASchema"; @@ -4285,7 +5070,7 @@ THREE.ColladaLoader = function () { for ( var i = 0, l = raw.length; i < l; i ++ ) { - data.push( (raw[i] == 'true' || raw[i] == '1') ? true : false ); + data.push( (raw[i] === 'true' || raw[i] === '1') ? true : false ); } @@ -4398,7 +5183,7 @@ THREE.ColladaLoader = function () { var parts = f.toString().split( '.' ); parts[ 1 ] = parts.length > 1 ? parts[ 1 ].substr( 0, num ) : "0"; - while( parts[ 1 ].length < num ) { + while ( parts[ 1 ].length < num ) { parts[ 1 ] += '0'; @@ -4408,21 +5193,16 @@ THREE.ColladaLoader = function () { }; - function evaluateXPath( node, query ) { - - var instances = COLLADA.evaluate( query, node, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); - - var inst = instances.iterateNext(); - var result = []; + function loadTextureImage ( texture, url ) { - while ( inst ) { + loader = new THREE.ImageLoader(); - result.push( inst ); - inst = instances.iterateNext(); + loader.load( url, function ( image ) { - } + texture.image = image; + texture.needsUpdate = true; - return result; + } ); }; @@ -4430,12 +5210,10 @@ THREE.ColladaLoader = function () { obj.doubleSided = false; - var node = COLLADA.evaluate( './/dae:extra//dae:double_sided', element, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); + var node = element.querySelectorAll('extra double_sided')[0]; if ( node ) { - node = node.iterateNext(); - if ( node && parseInt( node.textContent, 10 ) === 1 ) { obj.doubleSided = true; @@ -4450,7 +5228,7 @@ THREE.ColladaLoader = function () { function setUpConversion() { - if ( !options.convertUpAxis || colladaUp === options.upAxis ) { + if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) { upConversion = null; @@ -4481,7 +5259,7 @@ THREE.ColladaLoader = function () { function fixCoords( data, sign ) { - if ( !options.convertUpAxis || colladaUp === options.upAxis ) { + if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) { return; @@ -4537,6 +5315,31 @@ THREE.ColladaLoader = function () { }; + function getConvertedTranslation( axis, data ) { + + if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) { + + return data; + + } + + switch ( axis ) { + case 'X': + data = upConversion === 'XtoY' ? data * -1 : data; + break; + case 'Y': + data = upConversion === 'YtoZ' || upConversion === 'YtoX' ? data * -1 : data; + break; + case 'Z': + data = upConversion === 'ZtoY' ? data * -1 : data ; + break; + default: + break; + } + + return data; + }; + function getConvertedVec3( data, offset ) { var arr = [ data[ offset ], data[ offset + 1 ], data[ offset + 2 ] ]; @@ -4593,7 +5396,7 @@ THREE.ColladaLoader = function () { } - return new THREE.Matrix4( + return new THREE.Matrix4().set( data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], @@ -4606,7 +5409,7 @@ THREE.ColladaLoader = function () { if ( index > -1 && index < 3 ) { - var members = ['X', 'Y', 'Z'], + var members = [ 'X', 'Y', 'Z' ], indices = { X: 0, Y: 1, Z: 2 }; index = getConvertedMember( members[ index ] ); diff --git a/gz3d/client/js/include/Detector.js b/gz3d/client/js/include/Detector.js index 4f34bf112e05074a650dec0d751ac4030138ea9b..3a4fad55bddde72bf86b91386ed9ededccd27af1 100644 --- a/gz3d/client/js/include/Detector.js +++ b/gz3d/client/js/include/Detector.js @@ -6,7 +6,7 @@ var Detector = { canvas: !! window.CanvasRenderingContext2D, - webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), + webgl: ( function () { try { var canvas = document.createElement( 'canvas' ); return !! ( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) ); } catch ( e ) { return false; } } )(), workers: !! window.Worker, fileapi: window.File && window.FileReader && window.FileList && window.Blob, @@ -57,3 +57,10 @@ var Detector = { } }; + +// browserify support +if ( typeof module === 'object' ) { + + module.exports = Detector; + +} diff --git a/gz3d/client/js/include/EffectComposer.js b/gz3d/client/js/include/EffectComposer.js index ef540e856a03b3fa77a43cdd0306f37df7bdbb0d..55a4702406d95a98c1d153f62874105b80cea9d9 100644 --- a/gz3d/client/js/include/EffectComposer.js +++ b/gz3d/client/js/include/EffectComposer.js @@ -8,8 +8,10 @@ THREE.EffectComposer = function ( renderer, renderTarget ) { if ( renderTarget === undefined ) { - var width = window.innerWidth || 1; - var height = window.innerHeight || 1; + var pixelRatio = renderer.getPixelRatio(); + + var width = Math.floor( renderer.context.canvas.width / pixelRatio ) || 1; + var height = Math.floor( renderer.context.canvas.height / pixelRatio ) || 1; var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; renderTarget = new THREE.WebGLRenderTarget( width, height, parameters ); @@ -108,8 +110,10 @@ THREE.EffectComposer.prototype = { renderTarget = this.renderTarget1.clone(); - renderTarget.width = window.innerWidth; - renderTarget.height = window.innerHeight; + var pixelRatio = this.renderer.getPixelRatio(); + + renderTarget.width = Math.floor( this.renderer.context.canvas.width / pixelRatio ); + renderTarget.height = Math.floor( this.renderer.context.canvas.height / pixelRatio ); } @@ -133,12 +137,3 @@ THREE.EffectComposer.prototype = { } }; - -// shared ortho camera - -THREE.EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); - -THREE.EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null ); - -THREE.EffectComposer.scene = new THREE.Scene(); -THREE.EffectComposer.scene.add( THREE.EffectComposer.quad ); diff --git a/gz3d/client/js/include/FirstPersonControls.js b/gz3d/client/js/include/FirstPersonControls.js new file mode 100644 index 0000000000000000000000000000000000000000..35a202ed19869d807d232809fb98e656e8179299 --- /dev/null +++ b/gz3d/client/js/include/FirstPersonControls.js @@ -0,0 +1,295 @@ +/** + * First person controls for the gz3d camera/scene. + * Adapted from https://threejsdoc.appspot.com/doc/three.js/src.source/extras/controls/FirstPersonControls.js.html. + * + * Note that there is a third parameter now, called 'domElementForKeyBindings' which specifies to which element in + * the DOM the key strokes are bound. (Before they were automatically bound to the parameter 'domElement'). + */ + +/* global THREE: true */ + +THREE.FirstPersonControls = function(object, domElement, domElementForKeyBindings) +{ + 'use strict'; + + this.object = object; + this.domElement = angular.isDefined(domElement) ? domElement : document; + domElementForKeyBindings = angular.isDefined(domElementForKeyBindings) ? domElementForKeyBindings : document; + + if (this.domElement !== document) { + this.domElement.setAttribute('tabindex', -1); + } + + // Set to false to disable this control + this.enabled = true; + this.keyBindingsEnabled = true; + + this.movementSpeed = 0.05; + this.lookSpeed = 0.01; + + this.target = new THREE.Vector3(); + this.lookVertical = true; + + this.activeLook = true; + + this.azimuth = 0.0; + this.zenith = 0.0; + this.zenithMin = 0.0; + this.zenithMax = Math.PI; + this.azimuthOnMouseDown = 0.0; + this.zenithOnMouseDown = 0.0; + + this.moveForward = false; + this.moveBackward = false; + this.moveLeft = false; + this.moveRight = false; + this.moveUp = false; + this.moveDown = false; + this.initPosition = false; + + this.rotateLeft = false; + this.rotateRight = false; + this.rotateUp = false; + this.rotateDown = false; + this.initRotation = false; + + this.freeze = false; + + this.mouseDragOn = false; + this.mousePosOnKeyDown = new THREE.Vector2(); + this.mousePosCurrent = new THREE.Vector2(); + + this.initialPosition = new THREE.Vector3().copy(this.object.position); + this.initialRotation = new THREE.Quaternion().copy(this.object.quaternion); + + this.onMouseDown = function (event) { + // HBP-NRP: The next three lines are commented since this leads to problems in chrome with respect + // to AngularJS, also see: [NRRPLT-1992] + //if (this.domElement !== document) { + // this.domElement.focus(); + //} + + event.preventDefault(); + event.stopPropagation(); + + if (this.activeLook) { + switch (event.button) { + case 0: + this.updateSphericalAngles(); + this.mousePosOnKeyDown.set(event.pageX, event.pageY); + this.azimuthOnMouseDown = this.azimuth; + this.zenithOnMouseDown = this.zenith; + this.mouseDragOn = true; + break; + case 2: + } + } + }; + + this.onMouseUp = function (event) { + event.preventDefault(); + + // We do not stop the event propagation here, since there may be other + // components sitting on top, which also may have registered a handler + // and expect the event to be fired. + //event.stopPropagation(); + + if (this.activeLook) { + switch (event.button) { + case 0: + this.mouseDragOn = false; + this.azimuthOnMouseDown = this.azimuth; + this.zenithOnMouseDown = this.zenith; + break; + case 2: + } + } + }; + + this.onMouseMove = function (event) { + this.mousePosCurrent.set(event.pageX, event.pageY); + }; + + this.onKeyDown = function (event) { + if(this.keyBindingsEnabled === false) { + return; + } + switch(event.keyCode) { + case 38: /*up*/ + case 87: /*W*/ this.moveForward = true; break; + + case 37: /*left*/ + case 65: /*A*/ this.moveLeft = true; break; + + case 40: /*down*/ + case 83: /*S*/ this.moveBackward = true; break; + + case 39: /*right*/ + case 68: /*D*/ this.moveRight = true; break; + + case 33: /*page up*/ + case 82: /*R*/ this.moveUp = true; break; + + case 34: /*page down*/ + case 70: /*F*/ this.moveDown = true; break; + } + }; + + this.onKeyUp = function (event) { + if(this.keyBindingsEnabled === false) { + return; + } + switch(event.keyCode) { + case 38: /*up*/ + case 87: /*W*/ this.moveForward = false; break; + + case 37: /*left*/ + case 65: /*A*/ this.moveLeft = false; break; + + case 40: /*down*/ + case 83: /*S*/ this.moveBackward = false; break; + + case 39: /*right*/ + case 68: /*D*/ this.moveRight = false; break; + + case 33: /*page up*/ + case 82: /*R*/ this.moveUp = false; break; + + case 34: /*page down*/ + case 70: /*F*/ this.moveDown = false; break; + + case 81: /*Q*/ this.freeze = !this.freeze; break;// TODO(Luc): handles this from gz3d-view.js with some visual indication that the scene is frozen + } + }; + + this.fpRotate = function(rightAmount, upAmount) { + // rotate left/right + // rotation happens around the world up axis so up remains up (no upside-down) + var camera = this.object; + var q = new THREE.Quaternion(); + q.setFromAxisAngle(new THREE.Vector3(0.0, 0.0, 1.0), rightAmount); + camera.quaternion.multiplyQuaternions(q, camera.quaternion); + // rotate up/down + camera.rotateX(upAmount); + }; + + this.update = function(delta) { + if (!this.enabled) { + return; + } + + if (delta === undefined) { + delta = 1.0; + } + + var speed = 0.0; + + if (!this.freeze) { + /* --- translation --- */ + if (this.initPosition) { + this.object.position.copy(this.initialPosition); + } + + speed = delta * this.movementSpeed; + + if (this.moveForward) { + this.object.translateZ(-speed); + } + if (this.moveBackward) { + this.object.translateZ(speed); + } + if (this.moveLeft) { + this.object.translateX(-speed); + } + if (this.moveRight) { + this.object.translateX(speed); + } + if (this.moveUp) { + this.object.translateY(speed); + } + if (this.moveDown) { + this.object.translateY(-speed); + } + + /* --- rotation by means of a manipulator --- */ + var ROTATION_SPEED_FACTOR = 0.1; + if (this.rotateUp || this.rotateDown) { + var sign = this.rotateUp ? 1.0 : -1.0; + this.fpRotate(0.0, sign * ROTATION_SPEED_FACTOR * speed); + } + if (this.rotateRight) { + this.fpRotate(ROTATION_SPEED_FACTOR * speed, 0.0); + } + if (this.rotateLeft) { + this.fpRotate(-ROTATION_SPEED_FACTOR * speed, 0.0); + } + if (this.initRotation) { + this.object.quaternion.copy(this.initialRotation); + } + + /* --- rotation by means of a mouse drag --- */ + if (this.mouseDragOn) { + var actualLookSpeed = delta * this.lookSpeed; + if (!this.activeLook) { + actualLookSpeed = 0; + } + + var mouseDelta = new THREE.Vector2(); + mouseDelta.x = this.mousePosCurrent.x - this.mousePosOnKeyDown.x; + mouseDelta.y = this.mousePosCurrent.y - this.mousePosOnKeyDown.y; + + this.azimuth = this.azimuthOnMouseDown - mouseDelta.x * actualLookSpeed; + this.azimuth = this.azimuth % (2 * Math.PI); + + if (this.lookVertical) { + this.zenith = this.zenithOnMouseDown + mouseDelta.y * actualLookSpeed; + this.zenith = Math.max(this.zenithMin, Math.min(this.zenithMax, this.zenith)); + } else { + this.zenith = Math.PI / 2; + } + + var targetPosition = this.target, position = this.object.position; + + targetPosition.x = position.x + Math.sin(this.zenith) * Math.cos(this.azimuth); + targetPosition.y = position.y + Math.sin(this.zenith) * Math.sin(this.azimuth); + targetPosition.z = position.z + Math.cos(this.zenith); + + this.object.lookAt(targetPosition); + } + } + }; + + this.onMouseDownManipulator = function(action) { + this[action] = true; + }; + + this.onMouseUpManipulator = function(action) { + this[action] = false; + }; + + this.updateSphericalAngles = function() { + var vecForward = new THREE.Vector3(); + vecForward.set(object.matrix.elements[8], object.matrix.elements[9], object.matrix.elements[10]); + vecForward.normalize(); + + this.zenith = Math.acos(-vecForward.z); + this.azimuth = Math.atan(vecForward.y / vecForward.x) + Math.PI; + }; + + function bind(scope, fn) { + return function () { + fn.apply(scope, arguments); + }; + } + + this.domElement.addEventListener('contextmenu', function (event) { event.preventDefault(); }, false); + this.domElement.addEventListener('mousemove', bind(this, this.onMouseMove), false); + this.domElement.addEventListener('mousedown', bind(this, this.onMouseDown), false); + this.domElement.addEventListener('mouseup', bind(this, this.onMouseUp), false); + + domElementForKeyBindings.addEventListener('keydown', bind(this, this.onKeyDown), false); + domElementForKeyBindings.addEventListener('keyup', bind(this, this.onKeyUp), false); + +}; + +THREE.FirstPersonControls.prototype = Object.create(THREE.EventDispatcher.prototype); diff --git a/gz3d/client/js/include/OrbitControls.js b/gz3d/client/js/include/OrbitControls.js index eb740cc1cd4f34535a26fc6423c18e9cd31a7814..d2bbd7fb45b284222ddd01fd9e50167503581f89 100644 --- a/gz3d/client/js/include/OrbitControls.js +++ b/gz3d/client/js/include/OrbitControls.js @@ -28,781 +28,781 @@ THREE.OrbitControls = function (object, domElement) { - this.object = object; - this.domElement = (domElement !== undefined) ? domElement : document; - - // API - - // Set to false to disable this control - this.enabled = true; - - // "target" sets the location of focus, where the control orbits around - // and where it pans with respect to. - this.target = new THREE.Vector3(); - this.targetIndicator = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20), - new THREE.MeshPhongMaterial({emissive: 0x333300, - ambient: 0xffff00, - shading: THREE.SmoothShading})); - this.targetIndicator.visible = false; - this.showTargetIndicator = false; - // center is old, deprecated; use "target" instead - this.center = this.target; - this.object.lookAt(this.target); - // This option actually enables dollying in and out; left as "zoom" for - // backwards compatibility - this.noZoom = false; - this.zoomSpeed = 1.0; - // Limits to how far you can dolly in and out - this.minDistance = 0; - this.maxDistance = Infinity; - - // Set to true to disable this control - this.noRotate = false; - this.rotateSpeed = 1.0; - - // Set to true to disable this control - this.noPan = false; - this.keyPanSpeed = 7.0; // pixels moved per arrow key push - - // Set to true to automatically rotate around the target - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 - - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0; // radians - this.maxPolarAngle = Math.PI; // radians - - // Set to true to disable use of the keys - this.noKeys = false; - // The four arrow keys - this.keys = {LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40}; - - //////////// - // internals - - var scope = this; - - var EPS = 0.000001; - - var rotateStart = new THREE.Vector2(); - var rotateEnd = new THREE.Vector2(); - var rotateDelta = new THREE.Vector2(); - - var panStart = new THREE.Vector2(); - var panEnd = new THREE.Vector2(); - var panDelta = new THREE.Vector2(); - - var dollyStart = new THREE.Vector2(); - var dollyEnd = new THREE.Vector2(); - var dollyDelta = new THREE.Vector2(); - - var phiDelta = 0; - var thetaDelta = 0; - var scale = 1; - var pan = new THREE.Vector3(); - - var lastPosition = new THREE.Vector3(); - - var STATE = {NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, - TOUCH_DOLLY_PAN : 4}; - var state = STATE.NONE; - - var scrollTime = null; - - // events - - var changeEvent = - { - type: 'change' - }; - - this.rotateLeft = function (angle) - { - if (angle === undefined) - { - angle = getAutoRotationAngle(); - } - thetaDelta -= angle; - }; - - this.rotateUp = function (angle) - { - if (angle === undefined) - { - angle = getAutoRotationAngle(); - } - phiDelta -= angle; - }; - - // pass in distance in world space to move left - this.panLeft = function (distance) - { - var panOffset = new THREE.Vector3(); - var te = this.object.matrix.elements; - // get X column of matrix - panOffset.set(te[0], te[1], te[2]); - panOffset.multiplyScalar(-distance); - - pan.add(panOffset); - }; - - // pass in distance in world space to move up - this.panUp = function (distance) - { - var panOffset = new THREE.Vector3(); - var te = this.object.matrix.elements; - // get Y column of matrix - panOffset.set(te[4], te[5], te[6]); - panOffset.multiplyScalar(distance); - - pan.add(panOffset); - }; - - // main entry point; pass in Vector2 of change desired in pixel space, - // right and down are positive - this.pan = function (delta) - { - var element = scope.domElement === document ? - scope.domElement.body : scope.domElement; - - if (scope.object.fov !== undefined) - { - // perspective - var position = scope.object.position; - var offset = position.clone().sub(scope.target); - - var targetDistance = Math.max(offset.length(), 15); - - // half of the fov is center to top of screen - targetDistance *= Math.tan((scope.object.fov/2) * Math.PI / 180.0); - // we actually don't use screenWidth, since perspective camera is fixed - // to screen height - scope.panLeft(2 * delta.x * targetDistance / element.clientHeight); - scope.panUp(2 * delta.y * targetDistance / element.clientHeight); - } - else if (scope.object.top !== undefined) - { - // orthographic - scope.panLeft(delta.x * (scope.object.right - scope.object.left) / - element.clientWidth); - scope.panUp(delta.y * (scope.object.top - scope.object.bottom) / - element.clientHeight); - } - else - { - // camera neither orthographic or perspective - warn user - console.warn('WARNING: OrbitControls.js encountered an unknown'+ - 'camera type - pan disabled.'); - } - }; - - this.dollyIn = function (dollyScale) - { - if (dollyScale === undefined) - { - dollyScale = getZoomScale(); - } - - scale /= dollyScale; - }; - - this.dollyOut = function (dollyScale) - { - if (dollyScale === undefined) - { - dollyScale = getZoomScale(); - } - - scale *= dollyScale; - }; - - this.update = function () - { - var position = this.object.position; - var offset = position.clone().sub(this.target); - - // angle from y-axis around z-axis - var theta = Math.atan2(offset.x, offset.y); - - // angle from z-axis - var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), - offset.z); - - if (this.autoRotate) - { - this.rotateLeft(getAutoRotationAngle()); - } - - var oldTheta = theta; - var oldPhi = phi; - - theta -= thetaDelta; - phi += phiDelta; - - // restrict phi to be between desired limits - phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi)); - - // restrict phi to be betwee EPS and PI-EPS - phi = Math.max(EPS, Math.min(Math.PI - EPS, phi)); - - var radius = offset.length() * scale; - - // restrict radius to be between desired limits - radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius)); - - // move target to panned location - this.target.add(pan); - - offset.x = radius * Math.sin(phi) * Math.sin(theta); - offset.z = radius * Math.cos(phi); - offset.y = radius * Math.sin(phi) * Math.cos(theta); - - if (thetaDelta || phiDelta) - { - var rotateAroundWorldAxis = function (object, axis, radians) - { - rotWorldMatrix = new THREE.Matrix4(); - rotWorldMatrix.makeRotationAxis(axis.normalize(), radians); - rotWorldMatrix.multiply(object.matrix); // pre-multiply - - rotWorldMatrix.decompose(object.position, - object.quaternion, object.scale); - object.updateMatrix(); - } - - this.object.position.sub(this.target); - this.object.updateMatrix(); - rotateAroundWorldAxis(this.object, new THREE.Vector3(0, 0, 1), - oldTheta - theta); - var localPitch = new THREE.Vector3(1, 0, 0); - localPitch.applyQuaternion(this.object.quaternion); - rotateAroundWorldAxis(this.object, localPitch, phi - oldPhi); - this.object.position.add(this.target); - this.object.updateMatrix(); - - /*var refObj = new THREE.Object3D(); - refObj.position.x = this.target.x; - refObj.position.y = this.target.y; - refObj.position.z = this.target.z; - refObj.updateMatrix(); - refObj.updateMatrixWorld(); - - var parent = this.object.parent; - if (parent) - { - parent.remove(this.object); - } - - refObj.add(this.object); - this.object.position.x = offset.x; - this.object.position.y = offset.y; - this.object.position.z = offset.z; - -// console.log (offset.x + ' ' + offset.y + ' '); - this.object.updateMatrix(); - this.object.updateMatrixWorld(); - - var quat = new THREE.Quaternion(); - quat.setFromEuler(new THREE.Vector3(theta, 0, phi)); -// console.log('p t ' + phi + ' ' + theta); - refObj.quaternion.w = quat.w; - refObj.quaternion.x = quat.x; - refObj.quaternion.y = quat.y; - refObj.quaternion.z = quat.z; - refObj.updateMatrix(); - refObj.updateMatrixWorld(); - - var matrixWorld = new THREE.Matrix4(); - matrixWorld.copy(this.object.matrixWorld); - - refObj.remove(this.object); - if (parent) - parent.add(this.object); - - - matrixWorld.decompose(this.object.position, this.object.quaternion, - this.object.scale); - console.log('p t ' + this.object.position.x + ' ' + this.object.position.y + ' ' + - this.object.position.z); - -// this.object.matrxiWorld = matrixWorld; - this.object.updateMatrix(); - this.object.updateMatrixWorld();*/ - //this.object.lookAt(this.target); - } - else - { - position.copy(this.target).add(offset); + this.object = object; + this.domElement = (domElement !== undefined) ? domElement : document; + + // API + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the control orbits around + // and where it pans with respect to. + this.target = new THREE.Vector3(); + this.targetIndicator = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20), + new THREE.MeshPhongMaterial({emissive: 0x333300, + color: 0xffff00, + shading: THREE.SmoothShading})); + this.targetIndicator.visible = false; + this.showTargetIndicator = false; + // center is old, deprecated; use "target" instead + this.center = this.target; + this.object.lookAt(this.target); + // This option actually enables dollying in and out; left as "zoom" for + // backwards compatibility + this.noZoom = false; + this.zoomSpeed = 1.0; + // Limits to how far you can dolly in and out + this.minDistance = 0; + this.maxDistance = Infinity; + + // Set to true to disable this control + this.noRotate = false; + this.rotateSpeed = 1.0; + + // Set to true to disable this control + this.noPan = false; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // Set to true to disable use of the keys + this.noKeys = false; + // The four arrow keys + this.keys = {LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40}; + + //////////// + // internals + + var scope = this; + + var EPS = 0.000001; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var pan = new THREE.Vector3(); + + var lastPosition = new THREE.Vector3(); + + var STATE = {NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, + TOUCH_DOLLY_PAN : 4}; + var state = STATE.NONE; + + var scrollTime = null; + + // events + + var changeEvent = + { + type: 'change' + }; + + this.rotateLeft = function (angle) + { + if (angle === undefined) + { + angle = getAutoRotationAngle(); + } + thetaDelta -= angle; + }; + + this.rotateUp = function (angle) + { + if (angle === undefined) + { + angle = getAutoRotationAngle(); + } + phiDelta -= angle; + }; + + // pass in distance in world space to move left + this.panLeft = function (distance) + { + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get X column of matrix + panOffset.set(te[0], te[1], te[2]); + panOffset.multiplyScalar(-distance); + + pan.add(panOffset); + }; + + // pass in distance in world space to move up + this.panUp = function (distance) + { + var panOffset = new THREE.Vector3(); + var te = this.object.matrix.elements; + // get Y column of matrix + panOffset.set(te[4], te[5], te[6]); + panOffset.multiplyScalar(distance); + + pan.add(panOffset); + }; + + // main entry point; pass in Vector2 of change desired in pixel space, + // right and down are positive + this.pan = function (delta) + { + var element = scope.domElement === document ? + scope.domElement.body : scope.domElement; + + if (scope.object.fov !== undefined) + { + // perspective + var position = scope.object.position; + var offset = position.clone().sub(scope.target); + + var targetDistance = Math.max(offset.length(), 15); + + // half of the fov is center to top of screen + targetDistance *= Math.tan((scope.object.fov/2) * Math.PI / 180.0); + // we actually don't use screenWidth, since perspective camera is fixed + // to screen height + scope.panLeft(2 * delta.x * targetDistance / element.clientHeight); + scope.panUp(2 * delta.y * targetDistance / element.clientHeight); + } + else if (scope.object.top !== undefined) + { + // orthographic + scope.panLeft(delta.x * (scope.object.right - scope.object.left) / + element.clientWidth); + scope.panUp(delta.y * (scope.object.top - scope.object.bottom) / + element.clientHeight); + } + else + { + // camera neither orthographic or perspective - warn user + console.warn('WARNING: OrbitControls.js encountered an unknown'+ + 'camera type - pan disabled.'); + } + }; + + this.dollyIn = function (dollyScale) + { + if (dollyScale === undefined) + { + dollyScale = getZoomScale(); + } + + scale /= dollyScale; + }; + + this.dollyOut = function (dollyScale) + { + if (dollyScale === undefined) + { + dollyScale = getZoomScale(); + } + + scale *= dollyScale; + }; + + this.update = function () + { + var position = this.object.position; + var offset = position.clone().sub(this.target); + + // angle from y-axis around z-axis + var theta = Math.atan2(offset.x, offset.y); + + // angle from z-axis + var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), + offset.z); + + if (this.autoRotate) + { + this.rotateLeft(getAutoRotationAngle()); + } + + var oldTheta = theta; + var oldPhi = phi; + + theta -= thetaDelta; + phi += phiDelta; + + // restrict phi to be between desired limits + phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, phi)); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max(EPS, Math.min(Math.PI - EPS, phi)); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius)); + + // move target to panned location + this.target.add(pan); + + offset.x = radius * Math.sin(phi) * Math.sin(theta); + offset.z = radius * Math.cos(phi); + offset.y = radius * Math.sin(phi) * Math.cos(theta); + + if (thetaDelta || phiDelta) + { + var rotateAroundWorldAxis = function (object, axis, radians) + { + rotWorldMatrix = new THREE.Matrix4(); + rotWorldMatrix.makeRotationAxis(axis.normalize(), radians); + rotWorldMatrix.multiply(object.matrix); // pre-multiply + + rotWorldMatrix.decompose(object.position, + object.quaternion, object.scale); + object.updateMatrix(); + } + + this.object.position.sub(this.target); + this.object.updateMatrix(); + rotateAroundWorldAxis(this.object, new THREE.Vector3(0, 0, 1), + oldTheta - theta); + var localPitch = new THREE.Vector3(1, 0, 0); + localPitch.applyQuaternion(this.object.quaternion); + rotateAroundWorldAxis(this.object, localPitch, phi - oldPhi); + this.object.position.add(this.target); + this.object.updateMatrix(); + + /*var refObj = new THREE.Object3D(); + refObj.position.x = this.target.x; + refObj.position.y = this.target.y; + refObj.position.z = this.target.z; + refObj.updateMatrix(); + refObj.updateMatrixWorld(); + + var parent = this.object.parent; + if (parent) + { + parent.remove(this.object); + } + + refObj.add(this.object); + this.object.position.x = offset.x; + this.object.position.y = offset.y; + this.object.position.z = offset.z; + + // console.log (offset.x + ' ' + offset.y + ' '); + this.object.updateMatrix(); + this.object.updateMatrixWorld(); + + var quat = new THREE.Quaternion(); + quat.setFromEuler(new THREE.Vector3(theta, 0, phi)); + // console.log('p t ' + phi + ' ' + theta); + refObj.quaternion.w = quat.w; + refObj.quaternion.x = quat.x; + refObj.quaternion.y = quat.y; + refObj.quaternion.z = quat.z; + refObj.updateMatrix(); + refObj.updateMatrixWorld(); + + var matrixWorld = new THREE.Matrix4(); + matrixWorld.copy(this.object.matrixWorld); + + refObj.remove(this.object); + if (parent) + parent.add(this.object); + + + matrixWorld.decompose(this.object.position, this.object.quaternion, + this.object.scale); + console.log('p t ' + this.object.position.x + ' ' + this.object.position.y + ' ' + + this.object.position.z); + + // this.object.matrxiWorld = matrixWorld; + this.object.updateMatrix(); + this.object.updateMatrixWorld();*/ + //this.object.lookAt(this.target); + } + else + { + position.copy(this.target).add(offset); // position.copy(newPos).add(offset); - } - - //console.log(offset.x + ' ' + offset.y + ' ' + offset.z); - - thetaDelta = 0; - phiDelta = 0; - scale = 1; - pan.set(0,0,0); - - if (lastPosition.distanceTo(this.object.position) > 0) - { - this.dispatchEvent(changeEvent); - lastPosition.copy(this.object.position); - } - - if (scope.enabled === false) - { - setTargetIndicatorVisible(false) - } - - var millisecs = new Date().getTime(); - if (scrollTime && millisecs - scrollTime > 400) - { - setTargetIndicatorVisible(false) - scrollTime = null; - } - - if (scope.targetIndicator.visible) - { - var scaleVec = new THREE.Vector3(); - scaleVec.copy(object.position).sub(scope.targetIndicator.position); - var indicatorScale = scaleVec.length()/100; - scope.targetIndicator.scale.set( - indicatorScale, indicatorScale, indicatorScale); - } - - }; - - function setTargetIndicatorVisible(visible) - { - scope.targetIndicator.visible = visible; - if (!scope.showTargetIndicator) - { - scope.targetIndicator.visible = false; - } - } - - function getAutoRotationAngle() - { - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - } - - function getZoomScale() - { - return Math.pow(0.95, scope.zoomSpeed); - } - - function onMouseDown(event) - { - if (scope.enabled === false) - { - return; - } - event.preventDefault(); - - if (event.shiftKey && event.button === 0) - { - if (scope.noRotate === true) - { - return; - } - state = STATE.ROTATE; - rotateStart.set(event.clientX, event.clientY); - } - else if (event.button === 1) - { - if (scope.noRotate === true) - { - return; - } - - state = STATE.ROTATE; - - rotateStart.set(event.clientX, event.clientY); - } - else if (event.button === 2) - { - if (scope.noZoom === true) - { - return; - } - - state = STATE.DOLLY; - - dollyStart.set(event.clientX, event.clientY); - } - else if (event.button === 0) - { - if (scope.noPan === true) - { - return; - } - - state = STATE.PAN; - - panStart.set(event.clientX, event.clientY); - } - scope.targetIndicator.position.set(scope.target.x,scope.target.y, - scope.target.z); - setTargetIndicatorVisible(true) - - scope.domElement.addEventListener('mousemove', onMouseMove, false); - scope.domElement.addEventListener('mouseup', onMouseUp, false); - } - - function onMouseMove(event) - { - if (scope.enabled === false) - { - scope.domElement.removeEventListener('mousemove', onMouseMove, false); - scope.domElement.removeEventListener('mouseup', onMouseUp, false); - return; - } - - event.preventDefault(); - - var element = scope.domElement === document ? scope.domElement.body : - scope.domElement; - - if (state === STATE.ROTATE) - { - if (scope.noRotate === true) - { - return; - } - - rotateEnd.set(event.clientX, event.clientY); - rotateDelta.subVectors(rotateEnd, rotateStart); - - // rotating across whole screen goes 360 degrees around - scope.rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * - scope.rotateSpeed); - // rotating up and down along whole screen attempts to go 360, - // but limited to 180 - scope.rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * - scope.rotateSpeed); - - rotateStart.copy(rotateEnd); - } - else if (state === STATE.DOLLY) - { - if (scope.noZoom === true) - { - return; - } - - dollyEnd.set(event.clientX, event.clientY); - dollyDelta.subVectors(dollyEnd, dollyStart); - - if (dollyDelta.y > 0) - { - scope.dollyIn(); - } - else - { - scope.dollyOut(); - } - - dollyStart.copy(dollyEnd); - } - else if (state === STATE.PAN) - { - if (scope.noPan === true) - { - return; - } - - panEnd.set(event.clientX, event.clientY); - panDelta.subVectors(panEnd, panStart); - - scope.pan(panDelta); - - panStart.copy(panEnd); - } - - scope.update(); - } - - function onMouseUp(/* event */) - { - if (scope.enabled === false) - { - return; - } - - scope.domElement.removeEventListener('mousemove', onMouseMove, false); - scope.domElement.removeEventListener('mouseup', onMouseUp, false); - - state = STATE.NONE; - setTargetIndicatorVisible(false) - } - - function onMouseWheel(event) - { - if (scope.enabled === false || scope.noZoom === true) - { - return; - } - - scope.targetIndicator.position.set(scope.target.x,scope.target.y, - scope.target.z); - setTargetIndicatorVisible(true) - scrollTime = new Date().getTime(); - - var delta = 0; - - if (event.wheelDelta) // WebKit / Opera / Explorer 9 - { - delta = event.wheelDelta; - } - else if (event.detail) // Firefox - { - delta = - event.detail; - } - - if (delta > 0) - { - scope.dollyOut(); - } - else - { - scope.dollyIn(); - } - } - - function onKeyDown(event) - { - if (scope.enabled === false) - { - return; - } - if (scope.noKeys === true) - { - return; - } - if (scope.noPan === true) - { - return; - } - - var needUpdate = false; - - switch (event.keyCode) - { - case scope.keys.UP: - scope.pan(new THREE.Vector2(0, scope.keyPanSpeed)); - needUpdate = true; - break; - case scope.keys.BOTTOM: - scope.pan(new THREE.Vector2(0, -scope.keyPanSpeed)); - needUpdate = true; - break; - case scope.keys.LEFT: - scope.pan(new THREE.Vector2(scope.keyPanSpeed, 0)); - needUpdate = true; - break; - case scope.keys.RIGHT: - scope.pan(new THREE.Vector2(-scope.keyPanSpeed, 0)); - needUpdate = true; - break; - } - - if (needUpdate) - { - scope.update(); - } - } - - function touchstart(event) - { - if (scope.enabled === false) - { - return; - } - - scope.targetIndicator.position.set(scope.target.x,scope.target.y, - scope.target.z); - setTargetIndicatorVisible(true) - - switch (event.touches.length) - { - case 1: // one-fingered touch: rotate - if (scope.noRotate === true) - { - return; - } - - state = STATE.TOUCH_ROTATE; - - rotateStart.set(event.touches[0].pageX, event.touches[0].pageY); - break; - - case 2: // two-fingered touch: dolly + pan - if (scope.noZoom === false) - { - state = STATE.TOUCH_DOLLY_PAN; - - var dx = event.touches[0].pageX - event.touches[1].pageX; - var dy = event.touches[0].pageY - event.touches[1].pageY; - var distance = Math.sqrt(dx * dx + dy * dy); - dollyStart.set(0, distance); - } - - if (scope.noPan === false) - { - var panAvgX = (event.touches[0].pageX + event.touches[1].pageX)/2; - var panAvgY = (event.touches[0].pageY + event.touches[1].pageY)/2; - - panStart.set(panAvgX, panAvgY); - } - break; - - default: - state = STATE.NONE; - } - } - - function touchmove(event) - { - if (scope.enabled === false) - { - return; - } - - event.preventDefault(); - event.stopPropagation(); - - var element = scope.domElement === document ? scope.domElement.body : - scope.domElement; - - switch (event.touches.length) - { - case 1: // one-fingered touch: rotate - if (scope.noRotate === true) - { - return; - } - if (state !== STATE.TOUCH_ROTATE) - { - return; - } - - rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY); - rotateDelta.subVectors(rotateEnd, rotateStart); - - // rotating across whole screen goes 360 degrees around - scope.rotateLeft(2 * Math.PI * rotateDelta.x / - element.clientWidth * scope.rotateSpeed); - // rotating up and down along whole screen attempts to go 360, - // but limited to 180 - scope.rotateUp(2 * Math.PI * rotateDelta.y / - element.clientHeight * scope.rotateSpeed); - - rotateStart.copy(rotateEnd); - break; - - case 2: // two-fingered touch: dolly + pan - if (state !== STATE.TOUCH_DOLLY_PAN) - { - return; - } - - // Dolly delta - if (scope.noZoom === false) - { - var dx = event.touches[0].pageX - event.touches[1].pageX; - var dy = event.touches[0].pageY - event.touches[1].pageY; - var distance = Math.sqrt(dx * dx + dy * dy); - - dollyEnd.set(0, distance); - dollyDelta.subVectors(dollyEnd, dollyStart); - var dollyAbs = Math.abs(dollyDelta.y); - dollyStart.copy(dollyEnd); - } - - // Pan delta - if (scope.noPan === false) - { - var panAvgX = (event.touches[0].pageX + event.touches[1].pageX)/2; - var panAvgY = (event.touches[0].pageY + event.touches[1].pageY)/2; - - panEnd.set(panAvgX, panAvgY); - panDelta.subVectors(panEnd, panStart); - var panAbs = Math.max(Math.abs(panDelta.x),Math.abs(panDelta.y)); - panStart.copy(panEnd); - } - - // Choose one - if (scope.noPan === false && scope.noZoom === false) - { - if (dollyAbs > panAbs) - { - // Only dolly - scope.noPan = true; - } - else - { - // Only pan - scope.noZoom = true; - } - } - - // Dolly - if (scope.noZoom === false) - { - // Threshold - if (Math.abs(dollyDelta.y) > 1.3) - { - if (dollyDelta.y > 0) - { - scope.dollyOut(); - } - else - { - scope.dollyIn(); - } - } - } - - // Pan - if (scope.noPan === false) - { - scope.pan(panDelta); - } - break; - - default: - state = STATE.NONE; - } - } - - function touchend(/* event */) - { - if (scope.enabled === false) - { - return; - } - - state = STATE.NONE; - scope.noPan = false; - scope.noZoom = false; - - setTargetIndicatorVisible(false) - } - - this.domElement.addEventListener('contextmenu', function (event) - { - event.preventDefault(); - }, false); - this.domElement.addEventListener('mousedown', onMouseDown, false); - this.domElement.addEventListener('mousewheel', onMouseWheel, false); - this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox - - this.domElement.addEventListener('keydown', onKeyDown, false); - - this.domElement.addEventListener('touchstart', touchstart, false); - this.domElement.addEventListener('touchend', touchend, false); - this.domElement.addEventListener('touchmove', touchmove, false); + } + + //console.log(offset.x + ' ' + offset.y + ' ' + offset.z); + + thetaDelta = 0; + phiDelta = 0; + scale = 1; + pan.set(0,0,0); + + if (lastPosition.distanceTo(this.object.position) > 0) + { + this.dispatchEvent(changeEvent); + lastPosition.copy(this.object.position); + } + + if (scope.enabled === false) + { + setTargetIndicatorVisible(false) + } + + var millisecs = new Date().getTime(); + if (scrollTime && millisecs - scrollTime > 400) + { + setTargetIndicatorVisible(false) + scrollTime = null; + } + + if (scope.targetIndicator.visible) + { + var scaleVec = new THREE.Vector3(); + scaleVec.copy(object.position).sub(scope.targetIndicator.position); + var indicatorScale = scaleVec.length()/100; + scope.targetIndicator.scale.set( + indicatorScale, indicatorScale, indicatorScale); + } + + }; + + function setTargetIndicatorVisible(visible) + { + scope.targetIndicator.visible = visible; + if (!scope.showTargetIndicator) + { + scope.targetIndicator.visible = false; + } + } + + function getAutoRotationAngle() + { + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + } + + function getZoomScale() + { + return Math.pow(0.95, scope.zoomSpeed); + } + + function onMouseDown(event) + { + if (scope.enabled === false) + { + return; + } + event.preventDefault(); + + if (event.shiftKey && event.button === 0) + { + if (scope.noRotate === true) + { + return; + } + state = STATE.ROTATE; + rotateStart.set(event.clientX, event.clientY); + } + else if (event.button === 1) + { + if (scope.noRotate === true) + { + return; + } + + state = STATE.ROTATE; + + rotateStart.set(event.clientX, event.clientY); + } + else if (event.button === 2) + { + if (scope.noZoom === true) + { + return; + } + + state = STATE.DOLLY; + + dollyStart.set(event.clientX, event.clientY); + } + else if (event.button === 0) + { + if (scope.noPan === true) + { + return; + } + + state = STATE.PAN; + + panStart.set(event.clientX, event.clientY); + } + scope.targetIndicator.position.set(scope.target.x,scope.target.y, + scope.target.z); + setTargetIndicatorVisible(true) + + scope.domElement.addEventListener('mousemove', onMouseMove, false); + scope.domElement.addEventListener('mouseup', onMouseUp, false); + } + + function onMouseMove(event) + { + if (scope.enabled === false) + { + scope.domElement.removeEventListener('mousemove', onMouseMove, false); + scope.domElement.removeEventListener('mouseup', onMouseUp, false); + return; + } + + event.preventDefault(); + + var element = scope.domElement === document ? scope.domElement.body : + scope.domElement; + + if (state === STATE.ROTATE) + { + if (scope.noRotate === true) + { + return; + } + + rotateEnd.set(event.clientX, event.clientY); + rotateDelta.subVectors(rotateEnd, rotateStart); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * + scope.rotateSpeed); + // rotating up and down along whole screen attempts to go 360, + // but limited to 180 + scope.rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * + scope.rotateSpeed); + + rotateStart.copy(rotateEnd); + } + else if (state === STATE.DOLLY) + { + if (scope.noZoom === true) + { + return; + } + + dollyEnd.set(event.clientX, event.clientY); + dollyDelta.subVectors(dollyEnd, dollyStart); + + if (dollyDelta.y > 0) + { + scope.dollyIn(); + } + else + { + scope.dollyOut(); + } + + dollyStart.copy(dollyEnd); + } + else if (state === STATE.PAN) + { + if (scope.noPan === true) + { + return; + } + + panEnd.set(event.clientX, event.clientY); + panDelta.subVectors(panEnd, panStart); + + scope.pan(panDelta); + + panStart.copy(panEnd); + } + + scope.update(); + } + + function onMouseUp(/* event */) + { + if (scope.enabled === false) + { + return; + } + + scope.domElement.removeEventListener('mousemove', onMouseMove, false); + scope.domElement.removeEventListener('mouseup', onMouseUp, false); + + state = STATE.NONE; + setTargetIndicatorVisible(false) + } + + function onMouseWheel(event) + { + if (scope.enabled === false || scope.noZoom === true) + { + return; + } + + scope.targetIndicator.position.set(scope.target.x,scope.target.y, + scope.target.z); + setTargetIndicatorVisible(true) + scrollTime = new Date().getTime(); + + var delta = 0; + + if (event.wheelDelta) // WebKit / Opera / Explorer 9 + { + delta = event.wheelDelta; + } + else if (event.detail) // Firefox + { + delta = - event.detail; + } + + if (delta > 0) + { + scope.dollyOut(); + } + else + { + scope.dollyIn(); + } + } + + function onKeyDown(event) + { + if (scope.enabled === false) + { + return; + } + if (scope.noKeys === true) + { + return; + } + if (scope.noPan === true) + { + return; + } + + var needUpdate = false; + + switch (event.keyCode) + { + case scope.keys.UP: + scope.pan(new THREE.Vector2(0, scope.keyPanSpeed)); + needUpdate = true; + break; + case scope.keys.BOTTOM: + scope.pan(new THREE.Vector2(0, -scope.keyPanSpeed)); + needUpdate = true; + break; + case scope.keys.LEFT: + scope.pan(new THREE.Vector2(scope.keyPanSpeed, 0)); + needUpdate = true; + break; + case scope.keys.RIGHT: + scope.pan(new THREE.Vector2(-scope.keyPanSpeed, 0)); + needUpdate = true; + break; + } + + if (needUpdate) + { + scope.update(); + } + } + + function touchstart(event) + { + if (scope.enabled === false) + { + return; + } + + scope.targetIndicator.position.set(scope.target.x,scope.target.y, + scope.target.z); + setTargetIndicatorVisible(true) + + switch (event.touches.length) + { + case 1: // one-fingered touch: rotate + if (scope.noRotate === true) + { + return; + } + + state = STATE.TOUCH_ROTATE; + + rotateStart.set(event.touches[0].pageX, event.touches[0].pageY); + break; + + case 2: // two-fingered touch: dolly + pan + if (scope.noZoom === false) + { + state = STATE.TOUCH_DOLLY_PAN; + + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + var distance = Math.sqrt(dx * dx + dy * dy); + dollyStart.set(0, distance); + } + + if (scope.noPan === false) + { + var panAvgX = (event.touches[0].pageX + event.touches[1].pageX)/2; + var panAvgY = (event.touches[0].pageY + event.touches[1].pageY)/2; + + panStart.set(panAvgX, panAvgY); + } + break; + + default: + state = STATE.NONE; + } + } + + function touchmove(event) + { + if (scope.enabled === false) + { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + var element = scope.domElement === document ? scope.domElement.body : + scope.domElement; + + switch (event.touches.length) + { + case 1: // one-fingered touch: rotate + if (scope.noRotate === true) + { + return; + } + if (state !== STATE.TOUCH_ROTATE) + { + return; + } + + rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY); + rotateDelta.subVectors(rotateEnd, rotateStart); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft(2 * Math.PI * rotateDelta.x / + element.clientWidth * scope.rotateSpeed); + // rotating up and down along whole screen attempts to go 360, + // but limited to 180 + scope.rotateUp(2 * Math.PI * rotateDelta.y / + element.clientHeight * scope.rotateSpeed); + + rotateStart.copy(rotateEnd); + break; + + case 2: // two-fingered touch: dolly + pan + if (state !== STATE.TOUCH_DOLLY_PAN) + { + return; + } + + // Dolly delta + if (scope.noZoom === false) + { + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + var distance = Math.sqrt(dx * dx + dy * dy); + + dollyEnd.set(0, distance); + dollyDelta.subVectors(dollyEnd, dollyStart); + var dollyAbs = Math.abs(dollyDelta.y); + dollyStart.copy(dollyEnd); + } + + // Pan delta + if (scope.noPan === false) + { + var panAvgX = (event.touches[0].pageX + event.touches[1].pageX)/2; + var panAvgY = (event.touches[0].pageY + event.touches[1].pageY)/2; + + panEnd.set(panAvgX, panAvgY); + panDelta.subVectors(panEnd, panStart); + var panAbs = Math.max(Math.abs(panDelta.x),Math.abs(panDelta.y)); + panStart.copy(panEnd); + } + + // Choose one + if (scope.noPan === false && scope.noZoom === false) + { + if (dollyAbs > panAbs) + { + // Only dolly + scope.noPan = true; + } + else + { + // Only pan + scope.noZoom = true; + } + } + + // Dolly + if (scope.noZoom === false) + { + // Threshold + if (Math.abs(dollyDelta.y) > 1.3) + { + if (dollyDelta.y > 0) + { + scope.dollyOut(); + } + else + { + scope.dollyIn(); + } + } + } + + // Pan + if (scope.noPan === false) + { + scope.pan(panDelta); + } + break; + + default: + state = STATE.NONE; + } + } + + function touchend(/* event */) + { + if (scope.enabled === false) + { + return; + } + + state = STATE.NONE; + scope.noPan = false; + scope.noZoom = false; + + setTargetIndicatorVisible(false) + } + + this.domElement.addEventListener('contextmenu', function (event) + { + event.preventDefault(); + }, false); + this.domElement.addEventListener('mousedown', onMouseDown, false); + this.domElement.addEventListener('mousewheel', onMouseWheel, false); + this.domElement.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox + + this.domElement.addEventListener('keydown', onKeyDown, false); + + this.domElement.addEventListener('touchstart', touchstart, false); + this.domElement.addEventListener('touchend', touchend, false); + this.domElement.addEventListener('touchmove', touchmove, false); }; -THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype); +THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype); \ No newline at end of file diff --git a/gz3d/client/js/include/Projector.js b/gz3d/client/js/include/Projector.js new file mode 100644 index 0000000000000000000000000000000000000000..f207472f773c307cbeafb5b952349c1f28563e48 --- /dev/null +++ b/gz3d/client/js/include/Projector.js @@ -0,0 +1,904 @@ +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author julianwa / https://github.com/julianwa + */ + +THREE.RenderableObject = function () { + + this.id = 0; + + this.object = null; + this.z = 0; + +}; + +// + +THREE.RenderableFace = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + this.v3 = new THREE.RenderableVertex(); + + this.normalModel = new THREE.Vector3(); + + this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + this.vertexNormalsLength = 0; + + this.color = new THREE.Color(); + this.material = null; + this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; + + this.z = 0; + +}; + +// + +THREE.RenderableVertex = function () { + + this.position = new THREE.Vector3(); + this.positionWorld = new THREE.Vector3(); + this.positionScreen = new THREE.Vector4(); + + this.visible = true; + +}; + +THREE.RenderableVertex.prototype.copy = function ( vertex ) { + + this.positionWorld.copy( vertex.positionWorld ); + this.positionScreen.copy( vertex.positionScreen ); + +}; + +// + +THREE.RenderableLine = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + + this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; + this.material = null; + + this.z = 0; + +}; + +// + +THREE.RenderableSprite = function () { + + this.id = 0; + + this.object = null; + + this.x = 0; + this.y = 0; + this.z = 0; + + this.rotation = 0; + this.scale = new THREE.Vector2(); + + this.material = null; + +}; + +// + +THREE.Projector = function () { + + var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, + _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, + _face, _faceCount, _facePool = [], _facePoolLength = 0, + _line, _lineCount, _linePool = [], _linePoolLength = 0, + _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + + _renderData = { objects: [], lights: [], elements: [] }, + + _vector3 = new THREE.Vector3(), + _vector4 = new THREE.Vector4(), + + _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), + _boundingBox = new THREE.Box3(), + _points3 = new Array( 3 ), + _points4 = new Array( 4 ), + + _viewMatrix = new THREE.Matrix4(), + _viewProjectionMatrix = new THREE.Matrix4(), + + _modelMatrix, + _modelViewProjectionMatrix = new THREE.Matrix4(), + + _normalMatrix = new THREE.Matrix3(), + + _frustum = new THREE.Frustum(), + + _clippedVertex1PositionScreen = new THREE.Vector4(), + _clippedVertex2PositionScreen = new THREE.Vector4(); + + // + + this.projectVector = function ( vector, camera ) { + + console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + vector.project( camera ); + + }; + + this.unprojectVector = function ( vector, camera ) { + + console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + vector.unproject( camera ); + + }; + + this.pickingRay = function ( vector, camera ) { + + console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + + }; + + // + + var RenderList = function () { + + var normals = []; + var uvs = []; + + var object = null; + var material = null; + + var normalMatrix = new THREE.Matrix3(); + + var setObject = function ( value ) { + + object = value; + material = object.material; + + normalMatrix.getNormalMatrix( object.matrixWorld ); + + normals.length = 0; + uvs.length = 0; + + }; + + var projectVertex = function ( vertex ) { + + var position = vertex.position; + var positionWorld = vertex.positionWorld; + var positionScreen = vertex.positionScreen; + + positionWorld.copy( position ).applyMatrix4( _modelMatrix ); + positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / positionScreen.w; + + positionScreen.x *= invW; + positionScreen.y *= invW; + positionScreen.z *= invW; + + vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 && + positionScreen.y >= - 1 && positionScreen.y <= 1 && + positionScreen.z >= - 1 && positionScreen.z <= 1; + + }; + + var pushVertex = function ( x, y, z ) { + + _vertex = getNextVertexInPool(); + _vertex.position.set( x, y, z ); + + projectVertex( _vertex ); + + }; + + var pushNormal = function ( x, y, z ) { + + normals.push( x, y, z ); + + }; + + var pushUv = function ( x, y ) { + + uvs.push( x, y ); + + }; + + var checkTriangleVisibility = function ( v1, v2, v3 ) { + + if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; + + _points3[ 0 ] = v1.positionScreen; + _points3[ 1 ] = v2.positionScreen; + _points3[ 2 ] = v3.positionScreen; + + return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ); + + }; + + var checkBackfaceCulling = function ( v1, v2, v3 ) { + + return ( ( v3.positionScreen.x - v1.positionScreen.x ) * + ( v2.positionScreen.y - v1.positionScreen.y ) - + ( v3.positionScreen.y - v1.positionScreen.y ) * + ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; + + }; + + var pushLine = function ( a, b ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.copy( v1 ); + _line.v2.copy( v2 ); + _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; + + _line.material = object.material; + + _renderData.elements.push( _line ); + + }; + + var pushTriangle = function ( a, b, c ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + var v3 = _vertexPool[ c ]; + + if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; + + if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + for ( var i = 0; i < 3; i ++ ) { + + var offset = arguments[ i ] * 3; + var normal = _face.vertexNormalsModel[ i ]; + + normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] ); + normal.applyMatrix3( normalMatrix ).normalize(); + + var offset2 = arguments[ i ] * 2; + + var uv = _face.uvs[ i ]; + uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] ); + + } + + _face.vertexNormalsLength = 3; + + _face.material = object.material; + + _renderData.elements.push( _face ); + + } + + }; + + return { + setObject: setObject, + projectVertex: projectVertex, + checkTriangleVisibility: checkTriangleVisibility, + checkBackfaceCulling: checkBackfaceCulling, + pushVertex: pushVertex, + pushNormal: pushNormal, + pushUv: pushUv, + pushLine: pushLine, + pushTriangle: pushTriangle + } + + }; + + var renderList = new RenderList(); + + this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + + _faceCount = 0; + _lineCount = 0; + _spriteCount = 0; + + _renderData.elements.length = 0; + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); + + _frustum.setFromMatrix( _viewProjectionMatrix ); + + // + + _objectCount = 0; + + _renderData.objects.length = 0; + _renderData.lights.length = 0; + + scene.traverseVisible( function ( object ) { + + if ( object instanceof THREE.Light ) { + + _renderData.lights.push( object ); + + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { + + if ( object.material.visible === false ) return; + + if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + + _object = getNextObjectInPool(); + _object.id = object.id; + _object.object = object; + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + _renderData.objects.push( _object ); + + } + + } + + } ); + + if ( sortObjects === true ) { + + _renderData.objects.sort( painterSort ); + + } + + // + + for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + + var object = _renderData.objects[ o ].object; + var geometry = object.geometry; + + renderList.setObject( object ); + + _modelMatrix = object.matrixWorld; + + _vertexCount = 0; + + if ( object instanceof THREE.Mesh ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + var offsets = geometry.offsets; + + if ( attributes.position === undefined ) continue; + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + if ( attributes.normal !== undefined ) { + + var normals = attributes.normal.array; + + for ( var i = 0, l = normals.length; i < l; i += 3 ) { + + renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); + + } + + } + + if ( attributes.uv !== undefined ) { + + var uvs = attributes.uv.array; + + for ( var i = 0, l = uvs.length; i < l; i += 2 ) { + + renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); + + } + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + if ( offsets.length > 0 ) { + + for ( var o = 0; o < offsets.length; o ++ ) { + + var offset = offsets[ o ]; + var index = offset.index; + + for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); + + } + + } + + } else { + + for ( var i = 0, l = indices.length; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } + + } + + } else { + + for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { + + renderList.pushTriangle( i, i + 1, i + 2 ); + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + var vertices = geometry.vertices; + var faces = geometry.faces; + var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + + _normalMatrix.getNormalMatrix( _modelMatrix ); + + var material = object.material; + + var isFaceMaterial = material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? object.material : null; + + for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { + + var vertex = vertices[ v ]; + + _vector3.copy( vertex ); + + if ( material.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = object.morphTargetInfluences; + + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + + var influence = morphInfluences[ t ]; + + if ( influence === 0 ) continue; + + var target = morphTargets[ t ]; + var targetVertex = target.vertices[ v ]; + + _vector3.x += ( targetVertex.x - vertex.x ) * influence; + _vector3.y += ( targetVertex.y - vertex.y ) * influence; + _vector3.z += ( targetVertex.z - vertex.z ) * influence; + + } + + } + + renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z ); + + } + + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + + var face = faces[ f ]; + + var material = isFaceMaterial === true + ? objectMaterials.materials[ face.materialIndex ] + : object.material; + + if ( material === undefined ) continue; + + var side = material.side; + + var v1 = _vertexPool[ face.a ]; + var v2 = _vertexPool[ face.b ]; + var v3 = _vertexPool[ face.c ]; + + if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; + + var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); + + if ( side !== THREE.DoubleSide ) { + if ( side === THREE.FrontSide && visible === false ) continue; + if ( side === THREE.BackSide && visible === true ) continue; + } + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + + _face.normalModel.copy( face.normal ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + _face.normalModel.negate(); + + } + + _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); + + var faceVertexNormals = face.vertexNormals; + + for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { + + var normalModel = _face.vertexNormalsModel[ n ]; + normalModel.copy( faceVertexNormals[ n ] ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + normalModel.negate(); + + } + + normalModel.applyMatrix3( _normalMatrix ).normalize(); + + } + + _face.vertexNormalsLength = faceVertexNormals.length; + + var vertexUvs = faceVertexUvs[ f ]; + + if ( vertexUvs !== undefined ) { + + for ( var u = 0; u < 3; u ++ ) { + + _face.uvs[ u ].copy( vertexUvs[ u ] ); + + } + + } + + _face.color = face.color; + _face.material = material; + + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + _renderData.elements.push( _face ); + + } + + } + + } else if ( object instanceof THREE.Line ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + + if ( attributes.position !== undefined ) { + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + for ( var i = 0, l = indices.length; i < l; i += 2 ) { + + renderList.pushLine( indices[ i ], indices[ i + 1 ] ); + + } + + } else { + + var step = object.mode === THREE.LinePieces ? 2 : 1; + + for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) { + + renderList.pushLine( i, i + 1 ); + + } + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + + var vertices = object.geometry.vertices; + + if ( vertices.length === 0 ) continue; + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + + // Handle LineStrip and LinePieces + var step = object.mode === THREE.LinePieces ? 2 : 1; + + for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + + if ( ( v + 1 ) % step > 0 ) continue; + + v2 = _vertexPool[ _vertexCount - 2 ]; + + _clippedVertex1PositionScreen.copy( v1.positionScreen ); + _clippedVertex2PositionScreen.copy( v2.positionScreen ); + + if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + + // Perform the perspective divide + _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); + _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); + _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + + _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + + _line.material = object.material; + + if ( object.material.vertexColors === THREE.VertexColors ) { + + _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); + _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); + + } + + _renderData.elements.push( _line ); + + } + + } + + } + + } else if ( object instanceof THREE.Sprite ) { + + _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); + _vector4.applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / _vector4.w; + + _vector4.z *= invW; + + if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { + + _sprite = getNextSpriteInPool(); + _sprite.id = object.id; + _sprite.x = _vector4.x * invW; + _sprite.y = _vector4.y * invW; + _sprite.z = _vector4.z; + _sprite.object = object; + + _sprite.rotation = object.rotation; + + _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); + _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); + + _sprite.material = object.material; + + _renderData.elements.push( _sprite ); + + } + + } + + } + + if ( sortElements === true ) { + + _renderData.elements.sort( painterSort ); + + } + + return _renderData; + + }; + + // Pools + + function getNextObjectInPool() { + + if ( _objectCount === _objectPoolLength ) { + + var object = new THREE.RenderableObject(); + _objectPool.push( object ); + _objectPoolLength ++; + _objectCount ++; + return object; + + } + + return _objectPool[ _objectCount ++ ]; + + } + + function getNextVertexInPool() { + + if ( _vertexCount === _vertexPoolLength ) { + + var vertex = new THREE.RenderableVertex(); + _vertexPool.push( vertex ); + _vertexPoolLength ++; + _vertexCount ++; + return vertex; + + } + + return _vertexPool[ _vertexCount ++ ]; + + } + + function getNextFaceInPool() { + + if ( _faceCount === _facePoolLength ) { + + var face = new THREE.RenderableFace(); + _facePool.push( face ); + _facePoolLength ++; + _faceCount ++; + return face; + + } + + return _facePool[ _faceCount ++ ]; + + + } + + function getNextLineInPool() { + + if ( _lineCount === _linePoolLength ) { + + var line = new THREE.RenderableLine(); + _linePool.push( line ); + _linePoolLength ++; + _lineCount ++ + return line; + + } + + return _linePool[ _lineCount ++ ]; + + } + + function getNextSpriteInPool() { + + if ( _spriteCount === _spritePoolLength ) { + + var sprite = new THREE.RenderableSprite(); + _spritePool.push( sprite ); + _spritePoolLength ++; + _spriteCount ++ + return sprite; + + } + + return _spritePool[ _spriteCount ++ ]; + + } + + // + + function painterSort( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else if ( a.id !== b.id ) { + + return a.id - b.id; + + } else { + + return 0; + + } + + } + + function clipLine( s1, s2 ) { + + var alpha1 = 0, alpha2 = 1, + + // Calculate the boundary coordinate of each vertex for the near and far clip planes, + // Z = -1 and Z = +1, respectively. + bc1near = s1.z + s1.w, + bc2near = s2.z + s2.w, + bc1far = - s1.z + s1.w, + bc2far = - s2.z + s2.w; + + if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { + + // Both vertices lie entirely within all clip planes. + return true; + + } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) { + + // Both vertices lie entirely outside one of the clip planes. + return false; + + } else { + + // The line segment spans at least one clip plane. + + if ( bc1near < 0 ) { + + // v1 lies outside the near plane, v2 inside + alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + + } else if ( bc2near < 0 ) { + + // v2 lies outside the near plane, v1 inside + alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + + } + + if ( bc1far < 0 ) { + + // v1 lies outside the far plane, v2 inside + alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + + } else if ( bc2far < 0 ) { + + // v2 lies outside the far plane, v2 inside + alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + + } + + if ( alpha2 < alpha1 ) { + + // The line segment spans two boundaries, but is outside both of them. + // (This can't happen when we're only clipping against just near/far but good + // to leave the check here for future usage if other clip planes are added.) + return false; + + } else { + + // Update the s1 and s2 vertices to match the clipped line segment. + s1.lerp( s2, alpha1 ); + s2.lerp( s1, 1 - alpha2 ); + + return true; + + } + + } + + } + +}; diff --git a/gz3d/client/js/include/SSAOShader.js b/gz3d/client/js/include/SSAOShader.js index 4dee71ea7166dca4be859db11311828f575033b2..31c47ceac3772353039d17498bf88d978faa6699 100644 --- a/gz3d/client/js/include/SSAOShader.js +++ b/gz3d/client/js/include/SSAOShader.js @@ -8,7 +8,6 @@ * original technique is made by ArKano22 (http://www.gamedev.net/topic/550699-ssao-no-halo-artifacts/) * - modifications * - modified to use RGBA packed depth texture (use clear color 1,1,1,1 for depth pass) - * - made fog more compatible with three.js linear fog * - refactoring and optimizations */ @@ -21,12 +20,9 @@ THREE.SSAOShader = { "size": { type: "v2", value: new THREE.Vector2( 512, 512 ) }, "cameraNear": { type: "f", value: 1 }, "cameraFar": { type: "f", value: 100 }, - "fogNear": { type: "f", value: 5 }, - "fogFar": { type: "f", value: 100 }, - "fogEnabled": { type: "i", value: 0 }, "onlyAO": { type: "i", value: 0 }, - "aoClamp": { type: "f", value: 0.3 }, - "lumInfluence": { type: "f", value: 0.9 } + "aoClamp": { type: "f", value: 0.5 }, + "lumInfluence": { type: "f", value: 0.5 } }, @@ -49,10 +45,6 @@ THREE.SSAOShader = { "uniform float cameraNear;", "uniform float cameraFar;", - "uniform float fogNear;", - "uniform float fogFar;", - - "uniform bool fogEnabled;", // attenuate AO with linear fog "uniform bool onlyAO;", // use only ambient occlusion pass? "uniform vec2 size;", // texture width, height @@ -89,9 +81,6 @@ THREE.SSAOShader = { "const float diffArea = 0.4;", // self-shadowing reduction "const float gDisplace = 0.4;", // gauss bell center - "const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );", - // "const vec3 onlyAOColor = vec3( 1.0, 1.0, 1.0 );", - // RGBA depth @@ -129,15 +118,6 @@ THREE.SSAOShader = { "}", - "float doFog() {", - - "float zdepth = unpackDepth( texture2D( tDepth, vUv ) );", - "float depth = -cameraFar * cameraNear / ( zdepth * cameraFarMinusNear - cameraFar );", - - "return smoothstep( fogNear, fogFar, depth );", - - "}", - "float readDepth( const in vec2 coord ) {", // "return ( 2.0 * cameraNear ) / ( cameraFar + cameraNear - unpackDepth( texture2D( tDepth, coord ) ) * ( cameraFar - cameraNear ) );", @@ -206,10 +186,7 @@ THREE.SSAOShader = { "float w = ( 1.0 / width ) / tt + ( noise.x * ( 1.0 - noise.x ) );", "float h = ( 1.0 / height ) / tt + ( noise.y * ( 1.0 - noise.y ) );", - "float pw;", - "float ph;", - - "float ao;", + "float ao = 0.0;", "float dz = 1.0 / float( samples );", "float z = 1.0 - dz / 2.0;", @@ -219,8 +196,8 @@ THREE.SSAOShader = { "float r = sqrt( 1.0 - z );", - "pw = cos( l ) * r;", - "ph = sin( l ) * r;", + "float pw = cos( l ) * r;", + "float ph = sin( l ) * r;", "ao += calcAO( depth, pw * w, ph * h );", "z = z - dz;", "l = l + DL;", @@ -230,12 +207,6 @@ THREE.SSAOShader = { "ao /= float( samples );", "ao = 1.0 - ao;", - "if ( fogEnabled ) {", - - "ao = mix( ao, 1.0, doFog() );", - - "}", - "vec3 color = texture2D( tDiffuse, vUv ).rgb;", "vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );", @@ -246,7 +217,7 @@ THREE.SSAOShader = { "if ( onlyAO ) {", - "final = onlyAOColor * vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // ambient occlusion only + "final = vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // ambient occlusion only "}", diff --git a/gz3d/client/js/include/ShaderPass.js b/gz3d/client/js/include/ShaderPass.js index e8531f41058d37dffc6afb939dfbd588c482f1d0..eb3e33e4b82862ad1c441bfab9699a0714e793c9 100644 --- a/gz3d/client/js/include/ShaderPass.js +++ b/gz3d/client/js/include/ShaderPass.js @@ -10,6 +10,7 @@ THREE.ShaderPass = function ( shader, textureID ) { this.material = new THREE.ShaderMaterial( { + defines: shader.defines || {}, uniforms: this.uniforms, vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader @@ -22,6 +23,13 @@ THREE.ShaderPass = function ( shader, textureID ) { this.needsSwap = true; this.clear = false; + + this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); + this.scene = new THREE.Scene(); + + this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null ); + this.scene.add( this.quad ); + }; THREE.ShaderPass.prototype = { @@ -34,15 +42,15 @@ THREE.ShaderPass.prototype = { } - THREE.EffectComposer.quad.material = this.material; + this.quad.material = this.material; if ( this.renderToScreen ) { - renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); + renderer.render( this.scene, this.camera ); } else { - renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, this.clear ); + renderer.render( this.scene, this.camera, writeBuffer, this.clear ); } diff --git a/gz3d/client/js/include/ThreeBackwardsCompatibility.js b/gz3d/client/js/include/ThreeBackwardsCompatibility.js new file mode 100644 index 0000000000000000000000000000000000000000..2260fda4553c64db2d18d1fde332fc23dac8ce31 --- /dev/null +++ b/gz3d/client/js/include/ThreeBackwardsCompatibility.js @@ -0,0 +1,22 @@ +/** + * Created by Sandro Weber (webers@in.tum.de) on 07.08.15. + */ + + +/** + * getDescendants() was removed in r68, this reimplements it to ensure compatibility + * all getDescendants() calls could eventually be replaced with Object3D.traverse(function(node){...}); + */ +THREE.Object3D.prototype.getDescendants = function ( array ) { + if ( array === undefined ) array = []; + + Array.prototype.push.apply( array, this.children ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].getDescendants( array ); + + } + + return array; +}; \ No newline at end of file diff --git a/gz3d/client/js/include/TrackballControls.js b/gz3d/client/js/include/TrackballControls.js index 3fb0f512b51570b17fc870e167ae66be30392cca..4525da14a1d3e5782d59080094c2ff01df226168 100644 --- a/gz3d/client/js/include/TrackballControls.js +++ b/gz3d/client/js/include/TrackballControls.js @@ -1,11 +1,14 @@ /** * @author Eberhard Graether / http://egraether.com/ + * @author Mark Lundin / http://mark-lundin.com + * @author Simone Manini / http://daron1337.github.io + * @author Luca Antiga / http://lantiga.github.io */ THREE.TrackballControls = function ( object, domElement ) { var _this = this; - var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 }; + var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; this.object = object; this.domElement = ( domElement !== undefined ) ? domElement : document; @@ -23,7 +26,6 @@ THREE.TrackballControls = function ( object, domElement ) { this.noRotate = false; this.noZoom = false; this.noPan = false; - this.noRoll = false; this.staticMoving = false; this.dynamicDampingFactor = 0.2; @@ -37,6 +39,8 @@ THREE.TrackballControls = function ( object, domElement ) { this.target = new THREE.Vector3(); + var EPS = 0.000001; + var lastPosition = new THREE.Vector3(); var _state = STATE.NONE, @@ -44,8 +48,11 @@ THREE.TrackballControls = function ( object, domElement ) { _eye = new THREE.Vector3(), - _rotateStart = new THREE.Vector3(), - _rotateEnd = new THREE.Vector3(), + _movePrev = new THREE.Vector2(), + _moveCurr = new THREE.Vector2(), + + _lastAxis = new THREE.Vector3(), + _lastAngle = 0, _zoomStart = new THREE.Vector2(), _zoomEnd = new THREE.Vector2(), @@ -65,6 +72,8 @@ THREE.TrackballControls = function ( object, domElement ) { // events var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; // methods @@ -80,7 +89,13 @@ THREE.TrackballControls = function ( object, domElement ) { } else { - this.screen = this.domElement.getBoundingClientRect(); + var box = this.domElement.getBoundingClientRect(); + // adjustments come from similar code in the jquery offset() function + var d = this.domElement.ownerDocument.documentElement; + this.screen.left = box.left + window.pageXOffset - d.clientLeft; + this.screen.top = box.top + window.pageYOffset - d.clientTop; + this.screen.width = box.width; + this.screen.height = box.height; } @@ -96,101 +111,110 @@ THREE.TrackballControls = function ( object, domElement ) { }; - this.getMouseOnScreen = function ( clientX, clientY ) { + var getMouseOnScreen = ( function () { - return new THREE.Vector2( - ( clientX - _this.screen.left ) / _this.screen.width, - ( clientY - _this.screen.top ) / _this.screen.height - ); - - }; + var vector = new THREE.Vector2(); - this.getMouseProjectionOnBall = function ( clientX, clientY ) { + return function ( pageX, pageY ) { - var mouseOnBall = new THREE.Vector3( - ( clientX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5), - ( _this.screen.height * 0.5 + _this.screen.top - clientY ) / (_this.screen.height*.5), - 0.0 - ); + vector.set( + ( pageX - _this.screen.left ) / _this.screen.width, + ( pageY - _this.screen.top ) / _this.screen.height + ); - var length = mouseOnBall.length(); + return vector; - if ( _this.noRoll ) { + }; - if ( length < Math.SQRT1_2 ) { + }() ); - mouseOnBall.z = Math.sqrt( 1.0 - length*length ); + var getMouseOnCircle = ( function () { - } else { + var vector = new THREE.Vector2(); - mouseOnBall.z = .5 / length; - - } + return function ( pageX, pageY ) { - } else if ( length > 1.0 ) { + vector.set( + ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ), + ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional + ); - mouseOnBall.normalize(); + return vector; + }; - } else { + }() ); - mouseOnBall.z = Math.sqrt( 1.0 - length * length ); + this.rotateCamera = (function() { - } + var axis = new THREE.Vector3(), + quaternion = new THREE.Quaternion(), + eyeDirection = new THREE.Vector3(), + objectUpDirection = new THREE.Vector3(), + objectSidewaysDirection = new THREE.Vector3(), + moveDirection = new THREE.Vector3(), + angle; - _eye.copy( _this.object.position ).sub( _this.target ); + return function () { - var projection = _this.object.up.clone().setLength( mouseOnBall.y ); - projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) ); - projection.add( _eye.setLength( mouseOnBall.z ) ); + moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); + angle = moveDirection.length(); - return projection; + if ( angle ) { - }; + _eye.copy( _this.object.position ).sub( _this.target ); - this.rotateCamera = function () { + eyeDirection.copy( _eye ).normalize(); + objectUpDirection.copy( _this.object.up ).normalize(); + objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); - var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); + objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); + objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); - if ( angle ) { + moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); - var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(), - quaternion = new THREE.Quaternion(); + axis.crossVectors( moveDirection, _eye ).normalize(); - angle *= _this.rotateSpeed; + angle *= _this.rotateSpeed; + quaternion.setFromAxisAngle( axis, angle ); - quaternion.setFromAxisAngle( axis, -angle ); + _eye.applyQuaternion( quaternion ); + _this.object.up.applyQuaternion( quaternion ); - _eye.applyQuaternion( quaternion ); - _this.object.up.applyQuaternion( quaternion ); + _lastAxis.copy( axis ); + _lastAngle = angle; - _rotateEnd.applyQuaternion( quaternion ); + } - if ( _this.staticMoving ) { + else if ( !_this.staticMoving && _lastAngle ) { - _rotateStart.copy( _rotateEnd ); + _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor ); + _eye.copy( _this.object.position ).sub( _this.target ); + quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); + _eye.applyQuaternion( quaternion ); + _this.object.up.applyQuaternion( quaternion ); - } else { + } - quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); - _rotateStart.applyQuaternion( quaternion ); + _movePrev.copy( _moveCurr ); - } + }; - } + }()); - }; this.zoomCamera = function () { - if ( _state === STATE.TOUCH_ZOOM ) { + var factor; + + if ( _state === STATE.TOUCH_ZOOM_PAN ) { - var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; + factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; _touchZoomDistanceStart = _touchZoomDistanceEnd; _eye.multiplyScalar( factor ); } else { - var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; + factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; if ( factor !== 1.0 && factor > 0.0 ) { @@ -212,33 +236,40 @@ THREE.TrackballControls = function ( object, domElement ) { }; - this.panCamera = function () { + this.panCamera = (function() { - var mouseChange = _panEnd.clone().sub( _panStart ); + var mouseChange = new THREE.Vector2(), + objectUp = new THREE.Vector3(), + pan = new THREE.Vector3(); - if ( mouseChange.lengthSq() ) { + return function () { - mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); + mouseChange.copy( _panEnd ).sub( _panStart ); - var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x ); - pan.add( _this.object.up.clone().setLength( mouseChange.y ) ); + if ( mouseChange.lengthSq() ) { - _this.object.position.add( pan ); - _this.target.add( pan ); + mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); - if ( _this.staticMoving ) { + pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); + pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); - _panStart = _panEnd; + _this.object.position.add( pan ); + _this.target.add( pan ); - } else { + if ( _this.staticMoving ) { - _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); + _panStart.copy( _panEnd ); - } + } else { - } + _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); - }; + } + + } + }; + + }()); this.checkDistances = function () { @@ -288,7 +319,7 @@ THREE.TrackballControls = function ( object, domElement ) { _this.object.lookAt( _this.target ); - if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) { + if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { _this.dispatchEvent( changeEvent ); @@ -372,24 +403,26 @@ THREE.TrackballControls = function ( object, domElement ) { if ( _state === STATE.ROTATE && !_this.noRotate ) { - _rotateStart = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); - _rotateEnd.copy(_rotateStart) + _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); + _movePrev.copy(_moveCurr); } else if ( _state === STATE.ZOOM && !_this.noZoom ) { - _zoomStart = _this.getMouseOnScreen( event.clientX, event.clientY ); + _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); _zoomEnd.copy(_zoomStart); } else if ( _state === STATE.PAN && !_this.noPan ) { - _panStart = _this.getMouseOnScreen( event.clientX, event.clientY ); - _panEnd.copy(_panStart) + _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); + _panEnd.copy(_panStart); } document.addEventListener( 'mousemove', mousemove, false ); document.addEventListener( 'mouseup', mouseup, false ); + _this.dispatchEvent( startEvent ); + } function mousemove( event ) { @@ -401,15 +434,16 @@ THREE.TrackballControls = function ( object, domElement ) { if ( _state === STATE.ROTATE && !_this.noRotate ) { - _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY ); + _movePrev.copy(_moveCurr); + _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); } else if ( _state === STATE.ZOOM && !_this.noZoom ) { - _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); } else if ( _state === STATE.PAN && !_this.noPan ) { - _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY ); + _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); } @@ -426,6 +460,7 @@ THREE.TrackballControls = function ( object, domElement ) { document.removeEventListener( 'mousemove', mousemove ); document.removeEventListener( 'mouseup', mouseup ); + _this.dispatchEvent( endEvent ); } @@ -449,6 +484,8 @@ THREE.TrackballControls = function ( object, domElement ) { } _zoomStart.y += delta * 0.01; + _this.dispatchEvent( startEvent ); + _this.dispatchEvent( endEvent ); } @@ -460,25 +497,28 @@ THREE.TrackballControls = function ( object, domElement ) { case 1: _state = STATE.TOUCH_ROTATE; - _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); + _movePrev.copy(_moveCurr); break; case 2: - _state = STATE.TOUCH_ZOOM; + _state = STATE.TOUCH_ZOOM_PAN; var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); - break; - case 3: - _state = STATE.TOUCH_PAN; - _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; + var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; + _panStart.copy( getMouseOnScreen( x, y ) ); + _panEnd.copy( _panStart ); break; default: _state = STATE.NONE; } + _this.dispatchEvent( startEvent ); + } @@ -492,17 +532,18 @@ THREE.TrackballControls = function ( object, domElement ) { switch ( event.touches.length ) { case 1: - _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + _movePrev.copy(_moveCurr); + _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); break; case 2: var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ) - break; + _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); - case 3: - _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; + var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; + _panEnd.copy( getMouseOnScreen( x, y ) ); break; default: @@ -519,20 +560,23 @@ THREE.TrackballControls = function ( object, domElement ) { switch ( event.touches.length ) { case 1: - _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + _movePrev.copy(_moveCurr); + _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); break; case 2: _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; - break; - case 3: - _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; + var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; + _panEnd.copy( getMouseOnScreen( x, y ) ); + _panStart.copy( _panEnd ); break; } _state = STATE.NONE; + _this.dispatchEvent( endEvent ); } @@ -552,6 +596,10 @@ THREE.TrackballControls = function ( object, domElement ) { this.handleResize(); + // force an update at start + this.update(); + }; THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); +THREE.TrackballControls.prototype.constructor = THREE.TrackballControls; diff --git a/gz3d/client/js/include/TransformControls.js b/gz3d/client/js/include/TransformControls.js index 7688c0be17b0b8b3bb34459a21ecdc0619b62c53..a87b41a5dc8e8b36e7a8e1596d6c3c5ab604cf3e 100644 --- a/gz3d/client/js/include/TransformControls.js +++ b/gz3d/client/js/include/TransformControls.js @@ -1,658 +1,781 @@ /** * @author arodic / https://github.com/arodic */ + /*jshint sub:true*/ - //"use strict"; +(function () { -THREE.TransformControls = function ( camera, domElement, doc ) { + 'use strict'; - // TODO: Make non-uniform scale and rotate play nice in hierarchies - // TODO: ADD RXYZ contol + var GizmoMaterial = function ( parameters ) { - this.camera = camera; - this.domElement = ( domElement !== undefined ) ? domElement : document; - this.document = ( doc !== undefined ) ? doc : document; + THREE.MeshBasicMaterial.call( this ); - this.object = undefined; + this.depthTest = false; + this.depthWrite = false; + this.side = THREE.FrontSide; + this.transparent = true; - this.active = false; - this.hovered = false; + this.setValues( parameters ); - this.mode = 'translate'; - this.space = 'world'; - this.scale = 1; + this.oldColor = this.color.clone(); + this.oldOpacity = this.opacity; - this.snapDist = null; - this.modifierAxis = new THREE.Vector3( 1, 1, 1 ); - this.gizmo = new THREE.Object3D(); + this.highlight = function( highlighted ) { - var scope = this; + if ( highlighted ) { - var changeEvent = { type: 'change' }; + this.color.setRGB( 1, 1, 0 ); + this.opacity = 1; - var showPickers = false; // debug + } else { - var ray = new THREE.Raycaster(); - var projector = new THREE.Projector(); - var pointerVector = new THREE.Vector3(); + this.color.copy( this.oldColor ); + this.opacity = this.oldOpacity; - var point = new THREE.Vector3(); - var offset = new THREE.Vector3(); + } - var rotation = new THREE.Vector3(); - var offsetRotation = new THREE.Vector3(); - var scale = 1; + }; - var lookAtMatrix = new THREE.Matrix4(); - var eye = new THREE.Vector3() + }; - var tempMatrix = new THREE.Matrix4(); - var tempVector = new THREE.Vector3(); - var tempQuaternion = new THREE.Quaternion(); - var unitX = new THREE.Vector3( 1, 0, 0 ); - var unitY = new THREE.Vector3( 0, 1, 0 ); - var unitZ = new THREE.Vector3( 0, 0, 1 ); + GizmoMaterial.prototype = Object.create( THREE.MeshBasicMaterial.prototype ); + GizmoMaterial.prototype.constructor = GizmoMaterial; - var quaternionXYZ = new THREE.Quaternion(); - var quaternionX = new THREE.Quaternion(); - var quaternionY = new THREE.Quaternion(); - var quaternionZ = new THREE.Quaternion(); - var quaternionE = new THREE.Quaternion(); + var GizmoLineMaterial = function ( parameters ) { - var oldPosition = new THREE.Vector3(); - var oldScale = new THREE.Vector3(); - var oldRotationMatrix = new THREE.Matrix4(); + THREE.LineBasicMaterial.call( this ); - var parentRotationMatrix = new THREE.Matrix4(); - var parentScale = new THREE.Vector3(); + this.depthTest = false; + this.depthWrite = false; + this.transparent = true; + this.linewidth = 1; - var worldPosition = new THREE.Vector3(); -// var worldRotation = new THREE.Euler(); - var worldRotation = new THREE.Vector3(); - var worldRotationMatrix = new THREE.Matrix4(); - var camPosition = new THREE.Vector3(); -// var camRotation = new THREE.Euler(); - var camRotation = new THREE.Vector3(); + this.setValues( parameters ); - var displayAxes = {}; - var pickerAxes = {}; - var intersectionPlanes = {}; - var intersectionPlaneList = ['XY','YZ','XZ','XYZE']; // E - var currentPlane = 'XY'; + this.oldColor = this.color.clone(); + this.oldOpacity = this.opacity; - // intersection planes - { + this.highlight = function( highlighted ) { - var planes = new THREE.Object3D(); - this.gizmo.add(planes); + if ( highlighted ) { - for ( var i in intersectionPlaneList ){ + this.color.setRGB( 1, 1, 0 ); + this.opacity = 1; - intersectionPlanes[intersectionPlaneList[i]] = new THREE.Mesh( new THREE.PlaneGeometry( 500, 500 ) ); - intersectionPlanes[intersectionPlaneList[i]].material.side = THREE.DoubleSide; - intersectionPlanes[intersectionPlaneList[i]].visible = false; - planes.add(intersectionPlanes[intersectionPlaneList[i]]); + } else { - } + this.color.copy( this.oldColor ); + this.opacity = this.oldOpacity; - intersectionPlanes['YZ'].rotation.set( 0, Math.PI/2, 0 ); - intersectionPlanes['XZ'].rotation.set( -Math.PI/2, 0, 0 ); - bakeTransformations(intersectionPlanes['YZ']); - bakeTransformations(intersectionPlanes['XZ']); - - } - - // gizmo geometry - { - - displayAxes["translate"] = new THREE.Object3D(); - displayAxes["rotate"] = new THREE.Object3D(); - displayAxes["scale"] = new THREE.Object3D(); - this.gizmo.add( displayAxes["translate"] ); - this.gizmo.add( displayAxes["rotate"] ); - this.gizmo.add( displayAxes["scale"] ); - - pickerAxes["translate"] = new THREE.Object3D(); - pickerAxes["rotate"] = new THREE.Object3D(); - pickerAxes["scale"] = new THREE.Object3D(); - this.gizmo.add( pickerAxes["translate"] ); - this.gizmo.add( pickerAxes["rotate"] ); - this.gizmo.add( pickerAxes["scale"] ); - - var HandleMaterial = function ( color, opacity ) { - var material = new THREE.MeshBasicMaterial(); - material.color = color; - material.side = THREE.DoubleSide; - material.depthTest = false; - material.depthWrite = false; - material.opacity = opacity !== undefined ? opacity : 1; - material.transparent = true; - return material; - } + } - var LineMaterial = function ( color, opacity ) { - var material = new THREE.LineBasicMaterial(); - material.color = color; - material.depthTest = false; - material.depthWrite = false; - material.opacity = opacity !== undefined ? opacity : 1; - material.transparent = true; - return material; - } + }; - // materials by color - var white = new THREE.Color( 0xffffff ); - var gray = new THREE.Color( 0x808080 ); - var red = new THREE.Color( 0xff0000 ); - var green = new THREE.Color( 0x00ff00 ); - var blue = new THREE.Color( 0x0000ff ); - var cyan = new THREE.Color( 0x00ffff ); - var magenta = new THREE.Color( 0xff00ff ); - var yellow = new THREE.Color( 0xffff00 ); - - var geometry, mesh; - - // Line axes - - geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), - new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), - new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 1 ) - ); - geometry.colors.push( - red, red, green, green, blue, blue - ); - material = new THREE.LineBasicMaterial( { - vertexColors: THREE.VertexColors, - depthTest: false, - depthWrite: false, - transparent: true - } ); - mesh = new THREE.Line( geometry, material, THREE.LinePieces ); - displayAxes['translate'].add( mesh ); - displayAxes['scale'].add( mesh.clone() ); - - // Translate handles - - mesh = new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), HandleMaterial( white, 0.25 ) ); - mesh.name = 'TXYZ'; - displayAxes['translate'].add( mesh ); - pickerAxes['translate'].add( mesh.clone() ); - - geometry = new THREE.PlaneGeometry( 0.3, 0.3 ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( yellow, 0.25 ) ); - mesh.position.set( 0.15, 0.15, 0 ); - bakeTransformations( mesh ); - mesh.name = 'TXY'; - displayAxes['translate'].add( mesh ); - pickerAxes['translate'].add( mesh.clone() ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( cyan, 0.25 ) ); - mesh.position.set( 0, 0.15, 0.15 ); - mesh.rotation.y = Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TYZ'; - displayAxes['translate'].add( mesh ); - pickerAxes['translate'].add( mesh.clone() ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( magenta, 0.25 ) ); - mesh.position.set( 0.15, 0, 0.15 ); - mesh.rotation.x = Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TXZ'; - displayAxes['translate'].add( mesh ); - pickerAxes['translate'].add( mesh.clone() ); - - geometry = new THREE.CylinderGeometry( 0, 0.05, 0.2, 4, 1, true ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( red ) ); - mesh.position.x = 1.1; - mesh.rotation.z = -Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TX'; - displayAxes['translate'].add( mesh ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( green ) ); - mesh.position.y = 1.1; - bakeTransformations( mesh ); - mesh.name = 'TY'; - displayAxes['translate'].add( mesh ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) ); - mesh.position.z = 1.1; - mesh.rotation.x = Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TZ'; - displayAxes['translate'].add( mesh ); - - geometry = new THREE.CylinderGeometry( 0.2, 0.1, 0.8, 4, 1, false ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( red ) ); - mesh.position.x = 0.7; - mesh.rotation.z = -Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TX'; - pickerAxes['translate'].add( mesh ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( green ) ); - mesh.position.y = 0.7; - bakeTransformations( mesh ); - mesh.name = 'TY'; - pickerAxes['translate'].add( mesh ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) ); - mesh.position.z = 0.7; - mesh.rotation.x = Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'TZ'; - pickerAxes['translate'].add( mesh ); - - // scale manipulators - - geometry = new THREE.CubeGeometry( 0.125, 0.125, 0.125 ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( white, 0.25 ) ); - mesh.name = 'SXYZ'; - displayAxes['scale'].add( mesh ); - pickerAxes['scale'].add( mesh.clone() ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( red ) ); - mesh.position.set( 1.05, 0, 0 ); - bakeTransformations( mesh ); - mesh.name = 'SX'; - displayAxes['scale'].add( mesh ); - pickerAxes['scale'].add( mesh.clone() ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( green ) ); - mesh.position.set( 0, 1.05, 0 ); - bakeTransformations( mesh ); - mesh.name = 'SY'; - displayAxes['scale'].add( mesh ); - pickerAxes['scale'].add( mesh.clone() ); - - mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) ); - mesh.position.set( 0, 0, 1.05 ); - bakeTransformations( mesh ); - mesh.name = 'SZ'; - displayAxes['scale'].add( mesh ); - pickerAxes['scale'].add( mesh.clone() ); - - // rotate manipulators - - var Circle = function ( radius, facing, arc ) { - - geometry = new THREE.Geometry(); - arc = arc ? arc : 1; - for ( var i = 0; i <= 64 * arc; ++i ) { - if ( facing == 'x' ) geometry.vertices.push( new THREE.Vector3( 0, Math.cos( i / 32 * Math.PI ), Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) ); - if ( facing == 'y' ) geometry.vertices.push( new THREE.Vector3( Math.cos( i / 32 * Math.PI ), 0, Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) ); - if ( facing == 'z' ) geometry.vertices.push( new THREE.Vector3( Math.sin( i / 32 * Math.PI ), Math.cos( i / 32 * Math.PI ), 0 ).multiplyScalar(radius) ); - } + }; - return geometry; - } + GizmoLineMaterial.prototype = Object.create( THREE.LineBasicMaterial.prototype ); + GizmoLineMaterial.prototype.constructor = GizmoLineMaterial; - mesh = new THREE.Line( Circle( 1, 'x', 0.5 ), LineMaterial( red ) ); - mesh.name = 'RX'; - displayAxes['rotate'].add( mesh ); + THREE.TransformGizmo = function () { - mesh = new THREE.Line( Circle( 1, 'y', 0.5 ), LineMaterial( green ) ); - mesh.name = 'RY'; - displayAxes['rotate'].add( mesh ); + var scope = this; + var showPickers = false; //debug + var showActivePlane = false; //debug - mesh = new THREE.Line( Circle( 1, 'z', 0.5 ), LineMaterial( blue ) ); - mesh.name = 'RZ'; - displayAxes['rotate'].add( mesh ); + this.init = function () { - mesh = new THREE.Line( Circle( 1, 'z' ), LineMaterial( gray ) ); - mesh.name = 'RXYZE'; - displayAxes['rotate'].add( mesh ); + THREE.Object3D.call( this ); - mesh = new THREE.Line( Circle( 1.25, 'z' ), LineMaterial( yellow, 0.25 ) ); - mesh.name = 'RE'; - displayAxes['rotate'].add( mesh ); + this.handles = new THREE.Object3D(); + this.pickers = new THREE.Object3D(); + this.planes = new THREE.Object3D(); - geometry = new THREE.TorusGeometry( 1, 0.15, 4, 6, Math.PI ); + this.add(this.handles); + this.add(this.pickers); + this.add(this.planes); - mesh = new THREE.Mesh( geometry, HandleMaterial( red ) ); - mesh.rotation.z = -Math.PI/2; - mesh.rotation.y = -Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'RX'; - pickerAxes['rotate'].add( mesh ); + //// PLANES - mesh = new THREE.Mesh( geometry, HandleMaterial( green ) ); - mesh.rotation.z = Math.PI; - mesh.rotation.x = -Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'RY'; - pickerAxes['rotate'].add( mesh ); + var planeGeometry = new THREE.PlaneBufferGeometry( 50, 50, 2, 2 ); + var planeMaterial = new THREE.MeshBasicMaterial( { wireframe: true } ); + planeMaterial.side = THREE.DoubleSide; - mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) ); - mesh.rotation.z = -Math.PI/2; - bakeTransformations( mesh ); - mesh.name = 'RZ'; - pickerAxes['rotate'].add( mesh ); + var planes = { + "XY": new THREE.Mesh( planeGeometry, planeMaterial ), + "YZ": new THREE.Mesh( planeGeometry, planeMaterial ), + "XZ": new THREE.Mesh( planeGeometry, planeMaterial ), + "XYZE": new THREE.Mesh( planeGeometry, planeMaterial ) + }; - mesh = new THREE.Mesh( new THREE.SphereGeometry( 0.95, 12, 12 ), HandleMaterial( white, 0.25 ) ); - mesh.name = 'RXYZE'; - pickerAxes['rotate'].add( mesh ); + this.activePlane = planes["XYZE"]; - intersectionPlanes['SPHERE'] = new THREE.Mesh( new THREE.SphereGeometry( 0.95, 12, 12 ) ); - intersectionPlanes['SPHERE'].visible = false; - planes.add(intersectionPlanes['SPHERE']); + planes["YZ"].rotation.set( 0, Math.PI / 2, 0 ); + planes["XZ"].rotation.set( -Math.PI / 2, 0, 0 ); - mesh = new THREE.Mesh( new THREE.TorusGeometry( 1.30, 0.15, 4, 12 ), HandleMaterial( yellow, 0.25 ) ); - mesh.name = 'RE'; - pickerAxes['rotate'].add( mesh ); + for (var i in planes) { + planes[i].name = i; + this.planes.add(planes[i]); + this.planes[i] = planes[i]; + planes[i].visible = false; + } - mesh = null; + //// HANDLES AND PICKERS - } + var setupGizmos = function( gizmoMap, parent ) { - this.attach = function ( object ) { + for ( var name in gizmoMap ) { - this.object = object; - this.setMode( scope.mode ); + for ( i = gizmoMap[name].length; i --;) { - this.domElement.addEventListener( 'mousedown', onMouseDown, false ); - this.domElement.addEventListener( 'mousemove', onMouseHover, false ); - this.document.addEventListener( 'keydown', onKeyDown, false ); + var object = gizmoMap[name][i][0]; + var position = gizmoMap[name][i][1]; + var rotation = gizmoMap[name][i][2]; - } + object.name = name; - this.detach = function ( object ) { + if ( position ) object.position.set( position[0], position[1], position[2] ); + if ( rotation ) object.rotation.set( rotation[0], rotation[1], rotation[2] ); - this.object = undefined; - this.hovered = false; + parent.add( object ); - this.hide(); + } - this.domElement.removeEventListener( 'mousedown', onMouseDown, false ); - this.domElement.removeEventListener( 'mousemove', onMouseHover, false ); - this.document.removeEventListener( 'keydown', onKeyDown, false ); + } - } + }; - this.update = function () { + setupGizmos(this.handleGizmos, this.handles); + setupGizmos(this.pickerGizmos, this.pickers); - if ( this.object === undefined ) return; + // reset Transformations - this.object.updateMatrixWorld(); - worldPosition.getPositionFromMatrix( this.object.matrixWorld ); - // worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( this.object.matrixWorld ) ); + this.traverse(function ( child ) { + if (child instanceof THREE.Mesh) { + child.updateMatrix(); - this.camera.updateMatrixWorld(); - camPosition.getPositionFromMatrix( this.camera.matrixWorld ); - // camRotation.setFromRotationMatrix( tempMatrix.extractRotation( this.camera.matrixWorld ) ); + var tempGeometry = child.geometry.clone(); + tempGeometry.applyMatrix( child.matrix ); + child.geometry = tempGeometry; - scale = worldPosition.distanceTo( camPosition ) / 6 * this.scale; - this.gizmo.position.copy( worldPosition ) - this.gizmo.scale.set( scale, scale, scale ); + child.position.set( 0, 0, 0 ); + child.rotation.set( 0, 0, 0 ); + child.scale.set( 1, 1, 1 ); + } + }); + + }; + + this.hide = function () { + this.traverse(function( child ) { + child.visible = false; + }); + }; + + this.show = function () { + this.traverse(function( child ) { + child.visible = true; + if (child.parent == scope.pickers ) child.visible = showPickers; + if (child.parent == scope.planes ) child.visible = false; + }); + this.activePlane.visible = showActivePlane; + }; + + this.highlight = function ( axis ) { + this.traverse(function( child ) { + if ( child.material && child.material.highlight ) { + if ( child.name == axis ) { + child.material.highlight( true ); + } else { + child.material.highlight( false ); + } + } + }); + }; - for ( var i in this.gizmo.children ) { + }; - for ( var j in this.gizmo.children[i].children ) { + THREE.TransformGizmo.prototype = Object.create( THREE.Object3D.prototype ); + THREE.TransformGizmo.prototype.constructor = THREE.TransformGizmo; - var object = this.gizmo.children[i].children[j]; - var name = object.name; + THREE.TransformGizmo.prototype.update = function ( rotation, eye ) { - if ( name.search('E') != -1 ){ + var vec1 = new THREE.Vector3( 0, 0, 0 ); + var vec2 = new THREE.Vector3( 0, 1, 0 ); + var lookAtMatrix = new THREE.Matrix4(); - lookAtMatrix.lookAt( camPosition, worldPosition, tempVector.set( 0, 1, 0 )); - object.rotation.setFromRotationMatrix( lookAtMatrix ); + this.traverse(function(child) { + if ( child.name.search("E") != -1 ) { + child.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( eye, vec1, vec2 ) ); + } else if ( child.name.search("X") != -1 || child.name.search("Y") != -1 || child.name.search("Z") != -1 ) { + child.quaternion.setFromEuler( rotation ); + } + }); - } else { + }; - eye.copy( camPosition ).sub( worldPosition ).normalize(); + THREE.TransformGizmoTranslate = function () { + + THREE.TransformGizmo.call( this ); + + var arrowGeometry = new THREE.Geometry(); + var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) ); + mesh.position.y = 0.5; + mesh.updateMatrix(); + + arrowGeometry.merge( mesh.geometry, mesh.matrix ); + + var lineXGeometry = new THREE.Geometry(); + lineXGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ) ); + + var lineYGeometry = new THREE.Geometry(); + lineYGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + + var lineZGeometry = new THREE.Geometry(); + lineZGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 1 ) ); + + this.handleGizmos = { + X: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ], + [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] + ], + Y: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], + [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] + ], + Z: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], + [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] + ], + XYZ: [ + [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, 0, 0 ] ] + ], + XY: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.15, 0.15, 0 ] ] + ], + YZ: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ] ] + ], + XZ: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.15, 0, 0.15 ], [ -Math.PI / 2, 0, 0 ] ] + ] + }; + + this.pickerGizmos = { + X: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ), [ 0.6, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ] + ], + Y: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ), [ 0, 0.6, 0 ] ] + ], + Z: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] + ], + XYZ: [ + [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.2, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ] + ], + XY: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.2, 0.2, 0 ] ] + ], + YZ: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.2, 0.2 ], [ 0, Math.PI / 2, 0 ] ] + ], + XZ: [ + [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.2, 0, 0.2 ], [ -Math.PI / 2, 0, 0 ] ] + ] + }; + + this.setActivePlane = function ( axis, eye ) { + + var tempMatrix = new THREE.Matrix4(); + eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); + + if ( axis == "X" ) { + this.activePlane = this.planes[ "XY" ]; + if ( Math.abs(eye.y) > Math.abs(eye.z) ) this.activePlane = this.planes[ "XZ" ]; + } - if ( this.space == 'local' ) { + if ( axis == "Y" ) { + this.activePlane = this.planes[ "XY" ]; + if ( Math.abs(eye.x) > Math.abs(eye.z) ) this.activePlane = this.planes[ "YZ" ]; + } - // tempQuaternion.setFromEuler( worldRotation ); - tempQuaternion.setFromRotationMatrix( tempMatrix.extractRotation( this.object.matrixWorld ) ); + if ( axis == "Z" ) { + this.activePlane = this.planes[ "XZ" ]; + if ( Math.abs(eye.x) > Math.abs(eye.y) ) this.activePlane = this.planes[ "YZ" ]; + } - if ( name.search('R') != -1 ){ + if ( axis == "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; - tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix ); - eye.applyProjection( tempMatrix ); + if ( axis == "XY" ) this.activePlane = this.planes[ "XY" ]; - if ( name == 'RX' ) { - quaternionX.setFromAxisAngle( unitX, Math.atan2( -eye.y, eye.z ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - } + if ( axis == "YZ" ) this.activePlane = this.planes[ "YZ" ]; - if ( name == 'RY' ) { - quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); - } + if ( axis == "XZ" ) this.activePlane = this.planes[ "XZ" ]; - if ( name == 'RZ' ) { - quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); - } + this.hide(); + this.show(); - } + }; - object.quaternion.copy( tempQuaternion ); + this.init(); - } else if ( this.space == 'world' ) { + }; - object.rotation.set( 0, 0, 0 ); + THREE.TransformGizmoTranslate.prototype = Object.create( THREE.TransformGizmo.prototype ); + THREE.TransformGizmoTranslate.prototype.constructor = THREE.TransformGizmoTranslate; - if ( name == 'RX' ) object.rotation.x = Math.atan2( -eye.y, eye.z ); - if ( name == 'RY' ) object.rotation.y = Math.atan2( eye.x, eye.z ); - if ( name == 'RZ' ) object.rotation.z = Math.atan2( eye.y, eye.x ); + THREE.TransformGizmoRotate = function () { - } + THREE.TransformGizmo.call( this ); - } + var CircleGeometry = function ( radius, facing, arc ) { + var geometry = new THREE.Geometry(); + arc = arc ? arc : 1; + for ( var i = 0; i <= 64 * arc; ++ i ) { + if ( facing == 'x' ) geometry.vertices.push( new THREE.Vector3( 0, Math.cos( i / 32 * Math.PI ), Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) ); + if ( facing == 'y' ) geometry.vertices.push( new THREE.Vector3( Math.cos( i / 32 * Math.PI ), 0, Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) ); + if ( facing == 'z' ) geometry.vertices.push( new THREE.Vector3( Math.sin( i / 32 * Math.PI ), Math.cos( i / 32 * Math.PI ), 0 ).multiplyScalar(radius) ); } - } + return geometry; + }; + + this.handleGizmos = { + X: [ + [ new THREE.Line( new CircleGeometry(1,'x',0.5), new GizmoLineMaterial( { color: 0xff0000 } ) ) ] + ], + Y: [ + [ new THREE.Line( new CircleGeometry(1,'y',0.5), new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] + ], + Z: [ + [ new THREE.Line( new CircleGeometry(1,'z',0.5), new GizmoLineMaterial( { color: 0x0000ff } ) ) ] + ], + E: [ + [ new THREE.Line( new CircleGeometry(1.25,'z',1), new GizmoLineMaterial( { color: 0xcccc00 } ) ) ] + ], + XYZE: [ + [ new THREE.Line( new CircleGeometry(1,'z',1), new GizmoLineMaterial( { color: 0x787878 } ) ) ] + ] + }; + + this.pickerGizmos = { + X: [ + [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new GizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, -Math.PI / 2, -Math.PI / 2 ] ] + ], + Y: [ + [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new GizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ] ] + ], + Z: [ + [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new GizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ] + ], + E: [ + [ new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.12, 2, 24 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ) ] + ], + XYZE: [ + [ new THREE.Mesh( new THREE.Geometry() ) ]// TODO + ] + }; + + this.setActivePlane = function ( axis ) { + + if ( axis == "E" ) this.activePlane = this.planes[ "XYZE" ]; + + if ( axis == "X" ) this.activePlane = this.planes[ "YZ" ]; + + if ( axis == "Y" ) this.activePlane = this.planes[ "XZ" ]; + + if ( axis == "Z" ) this.activePlane = this.planes[ "XY" ]; + + this.hide(); + this.show(); + + }; + + this.update = function ( rotation, eye2 ) { + + THREE.TransformGizmo.prototype.update.apply( this, arguments ); + + var group = { + handles: this["handles"], + pickers: this["pickers"], + }; + + var tempMatrix = new THREE.Matrix4(); + var worldRotation = new THREE.Euler( 0, 0, 1 ); + var tempQuaternion = new THREE.Quaternion(); + var unitX = new THREE.Vector3( 1, 0, 0 ); + var unitY = new THREE.Vector3( 0, 1, 0 ); + var unitZ = new THREE.Vector3( 0, 0, 1 ); + var quaternionX = new THREE.Quaternion(); + var quaternionY = new THREE.Quaternion(); + var quaternionZ = new THREE.Quaternion(); + var eye = eye2.clone(); + + worldRotation.copy( this.planes["XY"].rotation ); + tempQuaternion.setFromEuler( worldRotation ); + + tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix ); + eye.applyMatrix4( tempMatrix ); + + this.traverse(function(child) { + + tempQuaternion.setFromEuler( worldRotation ); + + if ( child.name == "X" ) { + quaternionX.setFromAxisAngle( unitX, Math.atan2( -eye.y, eye.z ) ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); + child.quaternion.copy( tempQuaternion ); + } + + if ( child.name == "Y" ) { + quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); + child.quaternion.copy( tempQuaternion ); + } - } + if ( child.name == "Z" ) { + quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); + child.quaternion.copy( tempQuaternion ); + } - this.hide = function () { + }); - for ( var i in displayAxes ) { + }; - for ( var j in displayAxes[i].children ) { + this.init(); - displayAxes[i].children[j].visible = false; + }; + THREE.TransformGizmoRotate.prototype = Object.create( THREE.TransformGizmo.prototype ); + THREE.TransformGizmoRotate.prototype.constructor = THREE.TransformGizmoRotate; + + THREE.TransformGizmoScale = function () { + + THREE.TransformGizmo.call( this ); + + var arrowGeometry = new THREE.Geometry(); + var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) ); + mesh.position.y = 0.5; + mesh.updateMatrix(); + + arrowGeometry.merge( mesh.geometry, mesh.matrix ); + + var lineXGeometry = new THREE.Geometry(); + lineXGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ) ); + + var lineYGeometry = new THREE.Geometry(); + lineYGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + + var lineZGeometry = new THREE.Geometry(); + lineZGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 1 ) ); + + this.handleGizmos = { + X: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ], + [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] + ], + Y: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], + [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] + ], + Z: [ + [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], + [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] + ], + XYZ: [ + [ new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ] + ] + }; + + this.pickerGizmos = { + X: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ), [ 0.6, 0, 0 ], [ 0, 0, -Math.PI / 2 ] ] + ], + Y: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ), [ 0, 0.6, 0 ] ] + ], + Z: [ + [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new GizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] + ], + XYZ: [ + [ new THREE.Mesh( new THREE.BoxGeometry( 0.4, 0.4, 0.4 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ] + ] + }; + + this.setActivePlane = function ( axis, eye ) { + + var tempMatrix = new THREE.Matrix4(); + eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); + + if ( axis == "X" ) { + this.activePlane = this.planes[ "XY" ]; + if ( Math.abs(eye.y) > Math.abs(eye.z) ) this.activePlane = this.planes[ "XZ" ]; } - } + if ( axis == "Y" ) { + this.activePlane = this.planes[ "XY" ]; + if ( Math.abs(eye.x) > Math.abs(eye.z) ) this.activePlane = this.planes[ "YZ" ]; + } - for ( var i in pickerAxes ) { + if ( axis == "Z" ) { + this.activePlane = this.planes[ "XZ" ]; + if ( Math.abs(eye.x) > Math.abs(eye.y) ) this.activePlane = this.planes[ "YZ" ]; + } - for ( var j in pickerAxes[i].children ) { + if ( axis == "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; - pickerAxes[i].children[j].visible = false; + this.hide(); + this.show(); - } + }; - } + this.init(); - } + }; - this.setMode = function ( value ) { + THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype ); + THREE.TransformGizmoScale.prototype.constructor = THREE.TransformGizmoScale; - scope.mode = value; + THREE.TransformControls = function ( camera, domElement ) { - this.hide(); + // TODO: Make non-uniform scale and rotate play nice in hierarchies + // TODO: ADD RXYZ contol - if ( scope.mode == 'scale' ) scope.space = 'local'; + THREE.Object3D.call( this ); - for ( var i in displayAxes[this.mode].children ) { + domElement = ( domElement !== undefined ) ? domElement : document; - displayAxes[this.mode].children[i].visible = true; + this.gizmo = {}; + this.gizmo["translate"] = new THREE.TransformGizmoTranslate(); + this.gizmo["rotate"] = new THREE.TransformGizmoRotate(); + this.gizmo["scale"] = new THREE.TransformGizmoScale(); - } + this.add(this.gizmo["translate"]); + this.add(this.gizmo["rotate"]); + this.add(this.gizmo["scale"]); - for ( var i in pickerAxes[this.mode].children ) { + this.gizmo["translate"].hide(); + this.gizmo["rotate"].hide(); + this.gizmo["scale"].hide(); - pickerAxes[this.mode].children[i].visible = showPickers; + this.object = undefined; + this.snap = null; + this.space = "world"; + this.size = 1; + this.axis = null; - } + var scope = this; - scope.update(); + var _dragging = false; + var _mode = "translate"; + var _plane = "XY"; - } + var changeEvent = { type: "change" }; + var mouseDownEvent = { type: "mouseDown" }; + var mouseUpEvent = { type: "mouseUp", mode: _mode }; + var objectChangeEvent = { type: "objectChange" }; - this.setIntersectionPlane = function () { + var ray = new THREE.Raycaster(); + var pointerVector = new THREE.Vector3(); - eye.copy( camPosition ).sub( worldPosition ).normalize(); + var point = new THREE.Vector3(); + var offset = new THREE.Vector3(); - if ( this.space == 'local' ) { + var rotation = new THREE.Vector3(); + var offsetRotation = new THREE.Vector3(); + var scale = 1; - eye.applyMatrix4( tempMatrix.getInverse( scope.object.matrixWorld ) ); + var lookAtMatrix = new THREE.Matrix4(); + var eye = new THREE.Vector3(); - } + var tempMatrix = new THREE.Matrix4(); + var tempVector = new THREE.Vector3(); + var tempQuaternion = new THREE.Quaternion(); + var unitX = new THREE.Vector3( 1, 0, 0 ); + var unitY = new THREE.Vector3( 0, 1, 0 ); + var unitZ = new THREE.Vector3( 0, 0, 1 ); - if ( isActive("X") ) { + var quaternionXYZ = new THREE.Quaternion(); + var quaternionX = new THREE.Quaternion(); + var quaternionY = new THREE.Quaternion(); + var quaternionZ = new THREE.Quaternion(); + var quaternionE = new THREE.Quaternion(); - if ( eye.y > eye.z ) currentPlane = 'XZ'; - else currentPlane = 'XY'; + var oldPosition = new THREE.Vector3(); + var oldScale = new THREE.Vector3(); + var oldRotationMatrix = new THREE.Matrix4(); - } + var parentRotationMatrix = new THREE.Matrix4(); + var parentScale = new THREE.Vector3(); - if ( isActive("Y") ) { + var worldPosition = new THREE.Vector3(); + var worldRotation = new THREE.Euler(); + var worldRotationMatrix = new THREE.Matrix4(); + var camPosition = new THREE.Vector3(); + var camRotation = new THREE.Euler(); - if ( eye.x > eye.z ) currentPlane = 'YZ'; - else currentPlane = 'XY'; + domElement.addEventListener( "mousedown", onPointerDown, false ); + domElement.addEventListener( "touchstart", onPointerDown, false ); - } + domElement.addEventListener( "mousemove", onPointerHover, false ); + domElement.addEventListener( "touchmove", onPointerHover, false ); - if ( isActive("Z") ) { + domElement.addEventListener( "mousemove", onPointerMove, false ); + domElement.addEventListener( "touchmove", onPointerMove, false ); - if ( eye.x > eye.y ) currentPlane = 'YZ'; - else currentPlane = 'XZ'; + domElement.addEventListener( "mouseup", onPointerUp, false ); + domElement.addEventListener( "mouseout", onPointerUp, false ); + domElement.addEventListener( "touchend", onPointerUp, false ); + domElement.addEventListener( "touchcancel", onPointerUp, false ); + domElement.addEventListener( "touchleave", onPointerUp, false ); - } + this.attach = function ( object ) { - if ( isActive("XY") ) { + scope.object = object; - currentPlane = 'XY'; + this.gizmo["translate"].hide(); + this.gizmo["rotate"].hide(); + this.gizmo["scale"].hide(); + this.gizmo[_mode].show(); - } + scope.update(); - if ( isActive("YZ") ) { + }; - currentPlane = 'YZ'; + this.detach = function ( object ) { - } + scope.object = undefined; + this.axis = null; - if ( isActive("XZ") ) { + this.gizmo["translate"].hide(); + this.gizmo["rotate"].hide(); + this.gizmo["scale"].hide(); - currentPlane = 'XZ'; + }; - } + this.setMode = function ( mode ) { - if ( isActive("XYZ") || isActive("E") ) { + _mode = mode ? mode : _mode; - currentPlane = 'XYZE'; + if ( _mode == "scale" ) scope.space = "local"; - } + this.gizmo["translate"].hide(); + this.gizmo["rotate"].hide(); + this.gizmo["scale"].hide(); + this.gizmo[_mode].show(); - if ( isActive("RX") ) { + this.update(); + scope.dispatchEvent( changeEvent ); - currentPlane = 'YZ'; + }; - } + this.setSnap = function ( snap ) { - if ( isActive("RY") ) { + scope.snap = snap; - currentPlane = 'XZ'; + }; - } + this.setSize = function ( size ) { - if ( isActive("RZ") ) { + scope.size = size; + this.update(); + scope.dispatchEvent( changeEvent ); - currentPlane = 'XY'; + }; - } + this.setSpace = function ( space ) { - if ( isActive("RXYZ") ) { + scope.space = space; + this.update(); + scope.dispatchEvent( changeEvent ); - currentPlane = 'SPHERE'; + }; - } + this.update = function () { - } + if ( scope.object === undefined ) return; - var hovered = null; - var hoveredColor = new THREE.Color(); + scope.object.updateMatrixWorld(); + worldPosition.setFromMatrixPosition( scope.object.matrixWorld ); + worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.object.matrixWorld ) ); - function onMouseHover( event ) { + camera.updateMatrixWorld(); + camPosition.setFromMatrixPosition( camera.matrixWorld ); + camRotation.setFromRotationMatrix( tempMatrix.extractRotation( camera.matrixWorld ) ); - event.preventDefault(); + scale = worldPosition.distanceTo( camPosition ) / 6 * scope.size; + this.position.copy( worldPosition ); + this.scale.set( scale, scale, scale ); - if ( event.button === 0 && scope.active === false ) { + eye.copy( camPosition ).sub( worldPosition ).normalize(); - var intersect = intersectObjects( event, pickerAxes[scope.mode].children ); + if ( scope.space == "local" ) + this.gizmo[_mode].update( worldRotation, eye ); - if ( intersect ) { + else if ( scope.space == "world" ) + this.gizmo[_mode].update( new THREE.Euler(), eye ); - if ( hovered !== intersect.object ) { + this.gizmo[_mode].highlight( scope.axis ); - if ( hovered !== null ) { + }; - hovered.material.color.copy( hoveredColor ); + function onPointerHover( event ) { - } + if ( scope.object === undefined || _dragging === true ) return; - hovered = intersect.object; - hoveredColor.copy( hovered.material.color ); + event.preventDefault(); - hovered.material.color.offsetHSL( 0, 0, -0.3 ); + var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; - scope.dispatchEvent( changeEvent ); + var intersect = intersectObjects( pointer, scope.gizmo[_mode].pickers.children ); - } + var axis = null; - scope.hovered = true; + if ( intersect ) { - } else if ( hovered !== null ) { + axis = intersect.object.name; - hovered.material.color.copy( hoveredColor ); + } - hovered = null; + if ( scope.axis !== axis ) { + scope.axis = axis; + scope.update(); scope.dispatchEvent( changeEvent ); - scope.hovered = false; - } } - scope.document.addEventListener( 'mousemove', onMouseMove, false ); - scope.document.addEventListener( 'mouseup', onMouseUp, false ); + function onPointerDown( event ) { - }; + if ( scope.object === undefined || _dragging === true ) return; - function onMouseDown( event ) { + event.preventDefault(); + event.stopPropagation(); - event.preventDefault(); + var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; - if ( event.button === 0 ) { + if ( pointer.button === 0 || pointer.button === undefined ) { - var intersect = intersectObjects( event, pickerAxes[scope.mode].children ); + var intersect = intersectObjects( pointer, scope.gizmo[_mode].pickers.children ); - if ( intersect ) { + if ( intersect ) { - scope.active = intersect.object.name; + scope.dispatchEvent( mouseDownEvent ); - scope.update(); - scope.setIntersectionPlane(); + scope.axis = intersect.object.name; + + scope.update(); + + eye.copy( camPosition ).sub( worldPosition ).normalize(); - var planeIntersect = intersectObjects( event, [intersectionPlanes[currentPlane]] ); + scope.gizmo[_mode].setActivePlane( scope.axis, eye ); - if ( planeIntersect ) { + var planeIntersect = intersectObjects( pointer, [ scope.gizmo[_mode].activePlane ] ); oldPosition.copy( scope.object.position ); oldScale.copy( scope.object.scale ); @@ -661,7 +784,7 @@ THREE.TransformControls = function ( camera, domElement, doc ) { worldRotationMatrix.extractRotation( scope.object.matrixWorld ); parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld ); - parentScale.getScaleFromMatrix( tempMatrix.getInverse( scope.object.parent.matrixWorld ) ); + parentScale.setFromMatrixScale( tempMatrix.getInverse( scope.object.parent.matrixWorld ) ); offset.copy( planeIntersect.point ); @@ -669,173 +792,168 @@ THREE.TransformControls = function ( camera, domElement, doc ) { } - } + _dragging = true; - scope.document.addEventListener( 'mousemove', onMouseMove, false ); - scope.document.addEventListener( 'mouseup', onMouseUp, false ); + } - }; + function onPointerMove( event ) { - function onMouseMove( event ) { + if ( scope.object === undefined || scope.axis === null || _dragging === false ) return; - if ( scope.active ) { + event.preventDefault(); + event.stopPropagation(); - var planeIntersect = intersectObjects( event, [intersectionPlanes[currentPlane]] ); + var pointer = event.changedTouches ? event.changedTouches[0] : event; - if ( planeIntersect ) { + var planeIntersect = intersectObjects( pointer, [ scope.gizmo[_mode].activePlane ] ); - point.copy( planeIntersect.point ); + point.copy( planeIntersect.point ); - if ( ( scope.mode == 'translate' ) && isActive("T") ) { + if ( _mode == "translate" ) { - point.sub( offset ); - point.multiply(parentScale); + point.sub( offset ); + point.multiply(parentScale); - if ( scope.space == 'local' ) { + if ( scope.space == "local" ) { - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); + point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0; - if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0; - if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0; - if ( isActive("XYZ") ) point.set( 0, 0, 0 ); + if ( scope.axis.search("X") == -1 ) point.x = 0; + if ( scope.axis.search("Y") == -1 ) point.y = 0; + if ( scope.axis.search("Z") == -1 ) point.z = 0; - point.applyMatrix4( oldRotationMatrix ); + point.applyMatrix4( oldRotationMatrix ); - scope.object.position.copy( oldPosition ); - scope.object.position.add( point ); + scope.object.position.copy( oldPosition ); + scope.object.position.add( point ); - } + } - if ( scope.space == 'world' || isActive("XYZ") ) { + if ( scope.space == "world" || scope.axis.search("XYZ") != -1 ) { - if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0; - if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0; - if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0; + if ( scope.axis.search("X") == -1 ) point.x = 0; + if ( scope.axis.search("Y") == -1 ) point.y = 0; + if ( scope.axis.search("Z") == -1 ) point.z = 0; - point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) ); + point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) ); - scope.object.position.copy( oldPosition ); - scope.object.position.add( point ); + scope.object.position.copy( oldPosition ); + scope.object.position.add( point ); - if ( scope.snapDist ) { - if ( isActive("X") ) scope.object.position.x = Math.round( scope.object.position.x / scope.snapDist ) * scope.snapDist; - if ( isActive("Y") ) scope.object.position.y = Math.round( scope.object.position.y / scope.snapDist ) * scope.snapDist; - if ( isActive("Z") ) scope.object.position.z = Math.round( scope.object.position.z / scope.snapDist ) * scope.snapDist; - } + } - } + if ( scope.snap !== null ) { - } else if ( ( scope.mode == 'scale') && isActive("S") ) { + if ( scope.axis.search("X") != -1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.snap ) * scope.snap; + if ( scope.axis.search("Y") != -1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.snap ) * scope.snap; + if ( scope.axis.search("Z") != -1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.snap ) * scope.snap; - point.sub( offset ); - point.multiply(parentScale); + } - if ( scope.space == 'local' ) { + } else if ( _mode == "scale" ) { - if ( isActive("XYZ")) { + point.sub( offset ); + point.multiply(parentScale); - scale = 1 + ( ( point.y ) / 50 ); + if ( scope.space == "local" ) { - scope.object.scale.x = oldScale.x * scale; - scope.object.scale.y = oldScale.y * scale; - scope.object.scale.z = oldScale.z * scale; + if ( scope.axis == "XYZ") { - } else { + scale = 1 + ( ( point.y ) / 50 ); - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); + scope.object.scale.x = oldScale.x * scale; + scope.object.scale.y = oldScale.y * scale; + scope.object.scale.z = oldScale.z * scale; - if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0; - if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0; - if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0; + } else { - if ( isActive("X") ) scope.object.scale.x = oldScale.x * ( 1 + point.x / 50 ); - if ( isActive("Y") ) scope.object.scale.y = oldScale.y * ( 1 + point.y / 50 ); - if ( isActive("Z") ) scope.object.scale.z = oldScale.z * ( 1 + point.z / 50 ); + point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - } + if ( scope.axis == "X" ) scope.object.scale.x = oldScale.x * ( 1 + point.x / 50 ); + if ( scope.axis == "Y" ) scope.object.scale.y = oldScale.y * ( 1 + point.y / 50 ); + if ( scope.axis == "Z" ) scope.object.scale.z = oldScale.z * ( 1 + point.z / 50 ); } - } else if ( ( scope.mode == 'rotate' ) && isActive("R") ) { + } - point.sub( worldPosition ); - point.multiply(parentScale); - tempVector.copy(offset).sub( worldPosition ); - tempVector.multiply(parentScale); + } else if ( _mode == "rotate" ) { - if ( scope.active == "RE" ) { + point.sub( worldPosition ); + point.multiply(parentScale); + tempVector.copy(offset).sub( worldPosition ); + tempVector.multiply(parentScale); - point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); - tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); + if ( scope.axis == "E" ) { - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); + point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); + tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); + rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); + offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z ); - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); + tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); + quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z ); + quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - scope.object.quaternion.copy( tempQuaternion ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - } else if ( scope.active == "RXYZE" ) { + scope.object.quaternion.copy( tempQuaternion ); - quaternionE.setFromEuler( point.clone().cross(tempVector).normalize() ); // rotation axis + } else if ( scope.axis == "XYZE" ) { - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo(tempVector) ); - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); + quaternionE.setFromEuler( point.clone().cross(tempVector).normalize() ); // rotation axis - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); + tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); + quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo(tempVector) ); + quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - scope.object.quaternion.copy( tempQuaternion ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - } else if ( scope.space == 'local' ) { + scope.object.quaternion.copy( tempQuaternion ); - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); + } else if ( scope.space == "local" ) { - tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); + point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); + tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - quaternionXYZ.setFromRotationMatrix( oldRotationMatrix ); - quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); - quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); - quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); + rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); + offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - if ( scope.active == "RX" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX ); - if ( scope.active == "RY" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY ); - if ( scope.active == "RZ" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ ); + quaternionXYZ.setFromRotationMatrix( oldRotationMatrix ); + quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); + quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); + quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); - scope.object.quaternion.copy( quaternionXYZ ); + if ( scope.axis == "X" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX ); + if ( scope.axis == "Y" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY ); + if ( scope.axis == "Z" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ ); - } else if ( scope.space == 'world' ) { + scope.object.quaternion.copy( quaternionXYZ ); - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); + } else if ( scope.space == "world" ) { - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); + rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); + offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); - quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); - quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); + tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - if ( scope.active == "RX" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - if ( scope.active == "RY" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); - if ( scope.active == "RZ" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); + quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); + quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); + quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); + quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); + if ( scope.axis == "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); + if ( scope.axis == "Y" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); + if ( scope.axis == "Z" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); - scope.object.quaternion.copy( tempQuaternion ); + tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - } + scope.object.quaternion.copy( tempQuaternion ); } @@ -843,104 +961,40 @@ THREE.TransformControls = function ( camera, domElement, doc ) { scope.update(); scope.dispatchEvent( changeEvent ); + scope.dispatchEvent( objectChangeEvent ); } - } - - function onMouseUp( event ) { - - scope.active = false; - - scope.document.removeEventListener( 'mousemove', onMouseMove, false ); - scope.document.removeEventListener( 'mouseup', onMouseUp, false ); + function onPointerUp( event ) { - } - - function onKeyDown( event ) { - - var currentMode = scope.mode; - var currentSpace = scope.space; - var currentScale = scope.scale; - - if ( event.keyCode == 84 ) { // T - - if ( scope.mode == 'translate' ) scope.space = ( scope.space == 'world' ) ? 'local' : 'world'; - scope.mode = 'translate'; - - } - - if ( event.keyCode == 82 ) { // R - - if ( scope.mode == 'rotate' ) scope.space = ( scope.space == 'world' ) ? 'local' : 'world'; - scope.mode = 'rotate'; + if ( _dragging && ( scope.axis !== null ) ) { + mouseUpEvent.mode = _mode; + scope.dispatchEvent( mouseUpEvent ) + } + _dragging = false; + onPointerHover( event ); } - /*if ( event.keyCode == 82 ) { // R - - scope.mode = 'scale'; - scope.space = 'local'; - - }*/ - - if ( event.keyCode == 187 || event.keyCode == 107 ) { // +,=,num+ + function intersectObjects( pointer, objects ) { - scope.scale += 0.1 + var rect = domElement.getBoundingClientRect(); + var x = ( pointer.clientX - rect.left ) / rect.width; + var y = ( pointer.clientY - rect.top ) / rect.height; - } + pointerVector.set( ( x * 2 ) - 1, - ( y * 2 ) + 1, 0.5 ); + pointerVector.unproject( camera ); - if ( event.keyCode == 189 || event.keyCode == 109) { // -,_,num- + ray.set( camPosition, pointerVector.sub( camPosition ).normalize() ); - scope.scale -= 0.1 - scope.scale = Math.max( scope.scale, 0.1 ); + var intersections = ray.intersectObjects( objects, true ); + return intersections[0] ? intersections[0] : false; } - if ( scope.mode !== currentMode || scope.space !== currentSpace || scope.scale !== currentScale ) { - - scope.setMode( scope.mode ); - scope.dispatchEvent( changeEvent ); - - } - - } - - function intersectObjects( event, objects ) { - - pointerVector.set( - ( event.layerX / scope.domElement.offsetWidth ) * 2 - 1, - - ( event.layerY / scope.domElement.offsetHeight ) * 2 + 1, - 0.5 - ); - - projector.unprojectVector( pointerVector, scope.camera ); - ray.set( camPosition, pointerVector.sub( camPosition ).normalize() ); - - var intersections = ray.intersectObjects( objects, true ); - return intersections[0] ? intersections[0] : false; - - } - - function isActive( name ) { - - if ( scope.active.search( name ) != -1 ) return true; - else return false; - - } - - function bakeTransformations( object ) { - - var tempGeometry = new THREE.Geometry(); - THREE.GeometryUtils.merge( tempGeometry, object ); - object.geometry = tempGeometry; - object.position.set( 0, 0, 0 ); - object.rotation.set( 0, 0, 0 ); - object.scale.set( 1, 1, 1 ); - - } - -}; + }; -THREE.TransformControls.prototype = Object.create( THREE.EventDispatcher.prototype ); + THREE.TransformControls.prototype = Object.create( THREE.Object3D.prototype ); + THREE.TransformControls.prototype.constructor = THREE.TransformControls; +}()); diff --git a/gz3d/client/js/include/three.js b/gz3d/client/js/include/three.js index 8a94595e7e862de89c65ee4652552334534984c9..ae4b1beb2216c664ebc07a22c21d6c9e9262514c 100644 --- a/gz3d/client/js/include/three.js +++ b/gz3d/client/js/include/three.js @@ -1,100 +1,43 @@ +// File:src/Three.js + /** * @author mrdoob / http://mrdoob.com/ - * @author Larry Battle / http://bateru.com/news - * @author bhouston / http://exocortex.com */ -var THREE = { REVISION: '62' }; - -self.console = self.console || { - - info: function () {}, - log: function () {}, - debug: function () {}, - warn: function () {}, - error: function () {} - -}; - -String.prototype.trim = String.prototype.trim || function () { - - return this.replace( /^\s+|\s+$/g, '' ); - -}; - -// based on https://github.com/documentcloud/underscore/blob/bf657be243a075b5e72acc8a83e6f12a564d8f55/underscore.js#L767 -THREE.extend = function ( obj, source ) { - - // ECMAScript5 compatibility based on: http://www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible/ - if ( Object.keys ) { - - var keys = Object.keys( source ); - - for (var i = 0, il = keys.length; i < il; i++) { - - var prop = keys[i]; - Object.defineProperty( obj, prop, Object.getOwnPropertyDescriptor( source, prop ) ); - - } - - } else { - - var safeHasOwnProperty = {}.hasOwnProperty; - - for ( var prop in source ) { - - if ( safeHasOwnProperty.call( source, prop ) ) { - - obj[prop] = source[prop]; - - } - - } - - } - - return obj; +var THREE = { REVISION: '71' }; -}; +// browserify support -// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ -// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating +if ( typeof module === 'object' ) { -// requestAnimationFrame polyfill by Erik Möller -// fixes from Paul Irish and Tino Zijdel -// using 'self' instead of 'window' for compatibility with both NodeJS and IE10. -( function () { + module.exports = THREE; - var lastTime = 0; - var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; +} - for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { +// polyfills - self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; - self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; +if ( Math.sign === undefined ) { - } + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign - if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { + Math.sign = function ( x ) { - self.requestAnimationFrame = function ( callback ) { + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x; - var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); - var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); - lastTime = currTime + timeToCall; - return id; + }; - }; +} - } - if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { +// set the default log handlers +THREE.log = function() { console.log.apply( console, arguments ); } +THREE.warn = function() { console.warn.apply( console, arguments ); } +THREE.error = function() { console.error.apply( console, arguments ); } - self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; - } +// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button -}() ); +THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; // GL STATE CONSTANTS @@ -148,6 +91,8 @@ THREE.CustomBlending = 5; THREE.AddEquation = 100; THREE.SubtractEquation = 101; THREE.ReverseSubtractEquation = 102; +THREE.MinEquation = 103; +THREE.MaxEquation = 104; // custom blending destination factors @@ -181,13 +126,15 @@ THREE.AddOperation = 2; // Mapping modes -THREE.UVMapping = function () {}; +THREE.UVMapping = 300; + +THREE.CubeReflectionMapping = 301; +THREE.CubeRefractionMapping = 302; -THREE.CubeReflectionMapping = function () {}; -THREE.CubeRefractionMapping = function () {}; +THREE.EquirectangularReflectionMapping = 303; +THREE.EquirectangularRefractionMapping = 304; -THREE.SphericalReflectionMapping = function () {}; -THREE.SphericalRefractionMapping = function () {}; +THREE.SphericalReflectionMapping = 305; // Wrapping modes @@ -213,6 +160,7 @@ THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; +THREE.HalfFloatType = 1025; // Pixel types @@ -228,31 +176,80 @@ THREE.RGBFormat = 1020; THREE.RGBAFormat = 1021; THREE.LuminanceFormat = 1022; THREE.LuminanceAlphaFormat = 1023; +// THREE.RGBEFormat handled as THREE.RGBAFormat in shaders +THREE.RGBEFormat = THREE.RGBAFormat; //1024; -// Compressed texture formats +// DDS / ST3C Compressed texture formats THREE.RGB_S3TC_DXT1_Format = 2001; THREE.RGBA_S3TC_DXT1_Format = 2002; THREE.RGBA_S3TC_DXT3_Format = 2003; THREE.RGBA_S3TC_DXT5_Format = 2004; -/* -// Potential future PVRTC compressed texture formats + +// PVRTC compressed texture formats + THREE.RGB_PVRTC_4BPPV1_Format = 2100; THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; -*/ + + +// DEPRECATED + +THREE.Projector = function () { + + THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + + this.projectVector = function ( vector, camera ) { + + THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + vector.project( camera ); + + }; + + this.unprojectVector = function ( vector, camera ) { + + THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + vector.unproject( camera ); + + }; + + this.pickingRay = function ( vector, camera ) { + + THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + + }; + +}; + +THREE.CanvasRenderer = function () { + + THREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); + + this.domElement = document.createElement( 'canvas' ); + this.clear = function () {}; + this.render = function () {}; + this.setClearColor = function () {}; + this.setSize = function () {}; + +}; + +// File:src/math/Color.js /** * @author mrdoob / http://mrdoob.com/ */ -THREE.Color = function ( value ) { +THREE.Color = function ( color ) { - if ( value !== undefined ) this.set( value ); + if ( arguments.length === 3 ) { - return this; + return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); + + } + + return this.set( color ) }; @@ -415,21 +412,27 @@ THREE.Color.prototype = { }, - copyGammaToLinear: function ( color ) { + copyGammaToLinear: function ( color, gammaFactor ) { - this.r = color.r * color.r; - this.g = color.g * color.g; - this.b = color.b * color.b; + if ( gammaFactor === undefined ) gammaFactor = 2.0; + + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); return this; }, - copyLinearToGamma: function ( color ) { + copyLinearToGamma: function ( color, gammaFactor ) { + + if ( gammaFactor === undefined ) gammaFactor = 2.0; - this.r = Math.sqrt( color.r ); - this.g = Math.sqrt( color.g ); - this.b = Math.sqrt( color.b ); + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); return this; @@ -469,54 +472,50 @@ THREE.Color.prototype = { }, - getHSL: function () { - - var hsl = { h: 0, s: 0, l: 0 }; + getHSL: function ( optionalTarget ) { - return function () { - - // h,s,l ranges are in 0.0 - 1.0 - - var r = this.r, g = this.g, b = this.b; + // h,s,l ranges are in 0.0 - 1.0 - var max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); + var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; - var hue, saturation; - var lightness = ( min + max ) / 2.0; + var r = this.r, g = this.g, b = this.b; - if ( min === max ) { + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); - hue = 0; - saturation = 0; + var hue, saturation; + var lightness = ( min + max ) / 2.0; - } else { + if ( min === max ) { - var delta = max - min; + hue = 0; + saturation = 0; - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + } else { - switch ( max ) { + var delta = max - min; - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - } + switch ( max ) { - hue /= 6; + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; } - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; + hue /= 6; - return hsl; + } - }; + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; - }(), + return hsl; + + }, getStyle: function () { @@ -612,10 +611,16 @@ THREE.Color.prototype = { }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this.r, this.g, this.b ]; + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + return array; }, clone: function () { @@ -626,30 +631,32 @@ THREE.Color.prototype = { }; -THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF, -"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2, -"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50, -"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B, -"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B, -"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F, -"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3, -"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222, -"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700, -"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4, -"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00, -"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3, -"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA, -"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32, -"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3, -"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC, -"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD, -"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6, -"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9, -"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F, -"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE, -"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, -"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, -"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; +THREE.ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, +'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, +'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, +'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, +'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, +'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, +'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, +'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, +'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, +'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, +'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, +'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, +'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, +'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, +'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, +'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, +'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, +'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, +'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, +'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, +'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, +'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, +'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, +'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; + +// File:src/math/Quaternion.js /** * @author mikael emtinger / http://gomo.se/ @@ -673,18 +680,6 @@ THREE.Quaternion.prototype = { _x: 0,_y: 0, _z: 0, _w: 0, - _euler: undefined, - - _updateEuler: function ( callback ) { - - if ( this._euler !== undefined ) { - - this._euler.setFromQuaternion( this, undefined, false ); - - } - - }, - get x () { return this._x; @@ -694,7 +689,7 @@ THREE.Quaternion.prototype = { set x ( value ) { this._x = value; - this._updateEuler(); + this.onChangeCallback(); }, @@ -707,7 +702,7 @@ THREE.Quaternion.prototype = { set y ( value ) { this._y = value; - this._updateEuler(); + this.onChangeCallback(); }, @@ -720,7 +715,7 @@ THREE.Quaternion.prototype = { set z ( value ) { this._z = value; - this._updateEuler(); + this.onChangeCallback(); }, @@ -733,7 +728,7 @@ THREE.Quaternion.prototype = { set w ( value ) { this._w = value; - this._updateEuler(); + this.onChangeCallback(); }, @@ -744,7 +739,7 @@ THREE.Quaternion.prototype = { this._z = z; this._w = w; - this._updateEuler(); + this.onChangeCallback(); return this; @@ -752,12 +747,12 @@ THREE.Quaternion.prototype = { copy: function ( quaternion ) { - this._x = quaternion._x; - this._y = quaternion._y; - this._z = quaternion._z; - this._w = quaternion._w; + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - this._updateEuler(); + this.onChangeCallback(); return this; @@ -767,7 +762,7 @@ THREE.Quaternion.prototype = { if ( euler instanceof THREE.Euler === false ) { - throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } // http://www.mathworks.com/matlabcentral/fileexchange/ @@ -825,7 +820,7 @@ THREE.Quaternion.prototype = { } - if ( update !== false ) this._updateEuler(); + if ( update !== false ) this.onChangeCallback(); return this; @@ -833,8 +828,9 @@ THREE.Quaternion.prototype = { setFromAxisAngle: function ( axis, angle ) { - // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - // axis have to be normalized + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + + // assumes axis is normalized var halfAngle = angle / 2, s = Math.sin( halfAngle ); @@ -843,7 +839,7 @@ THREE.Quaternion.prototype = { this._z = axis.z * s; this._w = Math.cos( halfAngle ); - this._updateEuler(); + this.onChangeCallback(); return this; @@ -857,9 +853,9 @@ THREE.Quaternion.prototype = { var te = m.elements, - m11 = te[0], m12 = te[4], m13 = te[8], - m21 = te[1], m22 = te[5], m23 = te[9], - m31 = te[2], m32 = te[6], m33 = te[10], + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], trace = m11 + m22 + m33, s; @@ -877,19 +873,19 @@ THREE.Quaternion.prototype = { s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - this._w = (m32 - m23 ) / s; + this._w = ( m32 - m23 ) / s; this._x = 0.25 * s; - this._y = (m12 + m21 ) / s; - this._z = (m13 + m31 ) / s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; } else if ( m22 > m33 ) { s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - this._w = (m13 - m31 ) / s; - this._x = (m12 + m21 ) / s; + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; this._y = 0.25 * s; - this._z = (m23 + m32 ) / s; + this._z = ( m23 + m32 ) / s; } else { @@ -902,12 +898,61 @@ THREE.Quaternion.prototype = { } - this._updateEuler(); + this.onChangeCallback(); return this; }, + setFromUnitVectors: function () { + + // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final + + // assumes direction vectors vFrom and vTo are normalized + + var v1, r; + + var EPS = 0.000001; + + return function ( vFrom, vTo ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + r = vFrom.dot( vTo ) + 1; + + if ( r < EPS ) { + + r = 0; + + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + + v1.set( - vFrom.y, vFrom.x, 0 ); + + } else { + + v1.set( 0, - vFrom.z, vFrom.y ); + + } + + } else { + + v1.crossVectors( vFrom, vTo ); + + } + + this._x = v1.x; + this._y = v1.y; + this._z = v1.z; + this._w = r; + + this.normalize(); + + return this; + + } + + }(), + inverse: function () { this.conjugate().normalize(); @@ -918,16 +963,22 @@ THREE.Quaternion.prototype = { conjugate: function () { - this._x *= -1; - this._y *= -1; - this._z *= -1; + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - this._updateEuler(); + this.onChangeCallback(); return this; }, + dot: function ( v ) { + + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + + }, + lengthSq: function () { return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; @@ -962,6 +1013,8 @@ THREE.Quaternion.prototype = { } + this.onChangeCallback(); + return this; }, @@ -970,7 +1023,7 @@ THREE.Quaternion.prototype = { if ( p !== undefined ) { - console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } @@ -991,7 +1044,7 @@ THREE.Quaternion.prototype = { this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - this._updateEuler(); + this.onChangeCallback(); return this; @@ -999,13 +1052,16 @@ THREE.Quaternion.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, slerp: function ( qb, t ) { + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); + var x = this._x, y = this._y, z = this._z, w = this._w; // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ @@ -1014,12 +1070,12 @@ THREE.Quaternion.prototype = { if ( cosHalfTheta < 0 ) { - this._w = -qb._w; - this._x = -qb._x; - this._y = -qb._y; - this._z = -qb._z; + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - cosHalfTheta = -cosHalfTheta; + cosHalfTheta = - cosHalfTheta; } else { @@ -1060,7 +1116,7 @@ THREE.Quaternion.prototype = { this._y = ( y * ratioA + this._y * ratioB ); this._z = ( z * ratioA + this._z * ratioB ); - this._updateEuler(); + this.onChangeCallback(); return this; @@ -1072,25 +1128,45 @@ THREE.Quaternion.prototype = { }, - fromArray: function ( array ) { + fromArray: function ( array, offset ) { - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - this._w = array[ 3 ]; + if ( offset === undefined ) offset = 0; - this._updateEuler(); + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; + + this.onChangeCallback(); return this; }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this._x, this._y, this._z, this._w ]; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; + + return array; + + }, + + onChange: function ( callback ) { + + this.onChangeCallback = callback; + + return this; }, + onChangeCallback: function () {}, + clone: function () { return new THREE.Quaternion( this._x, this._y, this._z, this._w ); @@ -1105,6 +1181,8 @@ THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { } +// File:src/math/Vector2.js + /** * @author mrdoob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ @@ -1148,14 +1226,13 @@ THREE.Vector2.prototype = { }, - setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -1167,7 +1244,7 @@ THREE.Vector2.prototype = { case 0: return this.x; case 1: return this.y; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -1186,7 +1263,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -1198,19 +1275,19 @@ THREE.Vector2.prototype = { }, - addVectors: function ( a, b ) { + addScalar: function ( s ) { - this.x = a.x + b.x; - this.y = a.y + b.y; + this.x += s; + this.y += s; return this; }, - addScalar: function ( s ) { + addVectors: function ( a, b ) { - this.x += s; - this.y += s; + this.x = a.x + b.x; + this.y = a.y + b.y; return this; @@ -1220,7 +1297,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -1232,6 +1309,15 @@ THREE.Vector2.prototype = { }, + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + + return this; + + }, + subVectors: function ( a, b ) { this.x = a.x - b.x; @@ -1241,6 +1327,15 @@ THREE.Vector2.prototype = { }, + multiply: function ( v ) { + + this.x *= v.x; + this.y *= v.y; + + return this; + + }, + multiplyScalar: function ( s ) { this.x *= s; @@ -1250,6 +1345,15 @@ THREE.Vector2.prototype = { }, + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + + return this; + + }, + divideScalar: function ( scalar ) { if ( scalar !== 0 ) { @@ -1330,13 +1434,73 @@ THREE.Vector2.prototype = { } + return this; + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector2(); + max = new THREE.Vector2(); + + } + + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + return this; }, - negate: function() { + negate: function () { + + this.x = - this.x; + this.y = - this.y; - return this.multiplyScalar( - 1 ); + return this; }, @@ -1399,37 +1563,68 @@ THREE.Vector2.prototype = { }, - equals: function( v ) { + lerpVectors: function ( v1, v2, alpha ) { + + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + return this; + + }, + + equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) ); }, - fromArray: function ( array ) { + fromArray: function ( array, offset ) { - this.x = array[ 0 ]; - this.y = array[ 1 ]; + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; return this; }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this.x, this.y ]; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + + return array; }, - clone: function () { + fromAttribute: function ( attribute, index, offset ) { - return new THREE.Vector2( this.x, this.y ); + if ( offset === undefined ) offset = 0; - } + index = index * attribute.itemSize + offset; -}; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; -/** - * @author mrdoob / http://mrdoob.com/ + return this; + + }, + + clone: function () { + + return new THREE.Vector2( this.x, this.y ); + + } + +}; + +// File:src/math/Vector3.js + +/** + * @author mrdoob / http://mrdoob.com/ * @author *kile / http://kile.stravaganza.org/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ @@ -1490,7 +1685,7 @@ THREE.Vector3.prototype = { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -1503,7 +1698,7 @@ THREE.Vector3.prototype = { case 0: return this.x; case 1: return this.y; case 2: return this.z; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -1523,7 +1718,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -1560,7 +1755,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -1572,6 +1767,16 @@ THREE.Vector3.prototype = { return this; }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + }, subVectors: function ( a, b ) { @@ -1587,7 +1792,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } @@ -1620,6 +1825,44 @@ THREE.Vector3.prototype = { }, + applyEuler: function () { + + var quaternion; + + return function ( euler ) { + + if ( euler instanceof THREE.Euler === false ) { + + THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + + } + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromEuler( euler ) ); + + return this; + + }; + + }(), + + applyAxisAngle: function () { + + var quaternion; + + return function ( axis, angle ) { + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + + return this; + + }; + + }(), + applyMatrix3: function ( m ) { var x = this.x; @@ -1628,9 +1871,9 @@ THREE.Vector3.prototype = { var e = m.elements; - this.x = e[0] * x + e[3] * y + e[6] * z; - this.y = e[1] * x + e[4] * y + e[7] * z; - this.z = e[2] * x + e[5] * y + e[8] * z; + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; + this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; return this; @@ -1644,9 +1887,9 @@ THREE.Vector3.prototype = { var e = m.elements; - this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; - this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; - this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ]; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ]; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ]; return this; @@ -1659,11 +1902,11 @@ THREE.Vector3.prototype = { var x = this.x, y = this.y, z = this.z; var e = m.elements; - var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide + var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide - this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; - this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; - this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; + this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d; + this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d; + this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d; return this; @@ -1685,18 +1928,48 @@ THREE.Vector3.prototype = { var ix = qw * x + qy * z - qz * y; var iy = qw * y + qz * x - qx * z; var iz = qw * z + qx * y - qy * x; - var iw = -qx * x - qy * y - qz * z; + var iw = - qx * x - qy * y - qz * z; // calculate result * inverse quat - this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; + this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; + this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; return this; }, + project: function () { + + var matrix; + + return function ( camera ) { + + if ( matrix === undefined ) matrix = new THREE.Matrix4(); + + matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); + return this.applyProjection( matrix ); + + }; + + }(), + + unproject: function () { + + var matrix; + + return function ( camera ) { + + if ( matrix === undefined ) matrix = new THREE.Matrix4(); + + matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); + return this.applyProjection( matrix ); + + }; + + }(), + transformDirection: function ( m ) { // input: THREE.Matrix4 affine matrix @@ -1706,9 +1979,9 @@ THREE.Vector3.prototype = { var e = m.elements; - this.x = e[0] * x + e[4] * y + e[8] * z; - this.y = e[1] * x + e[5] * y + e[9] * z; - this.z = e[2] * x + e[6] * y + e[10] * z; + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; this.normalize(); @@ -1834,9 +2107,75 @@ THREE.Vector3.prototype = { }, + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector3(); + max = new THREE.Vector3(); + + } + + min.set( minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + + return this; + + }, + negate: function () { - return this.multiplyScalar( - 1 ); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + + return this; }, @@ -1893,11 +2232,19 @@ THREE.Vector3.prototype = { }, + lerpVectors: function ( v1, v2, alpha ) { + + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + return this; + + }, + cross: function ( v, w ) { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } @@ -1925,13 +2272,64 @@ THREE.Vector3.prototype = { }, + projectOnVector: function () { + + var v1, dot; + + return function ( vector ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.copy( vector ).normalize(); + + dot = this.dot( v1 ); + + return this.copy( v1 ).multiplyScalar( dot ); + + }; + + }(), + + projectOnPlane: function () { + + var v1; + + return function ( planeNormal ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.copy( this ).projectOnVector( planeNormal ); + + return this.sub( v1 ); + + } + + }(), + + reflect: function () { + + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + var v1; + + return function ( normal ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + } + + }(), + angleTo: function ( v ) { var theta = this.dot( v ) / ( this.length() * v.length() ); // clamp, to handle numerical problems - return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); + return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) ); }, @@ -1953,162 +2351,130 @@ THREE.Vector3.prototype = { setEulerFromRotationMatrix: function ( m, order ) { - console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); + THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); }, setEulerFromQuaternion: function ( q, order ) { - console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); + THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); }, getPositionFromMatrix: function ( m ) { - this.x = m.elements[12]; - this.y = m.elements[13]; - this.z = m.elements[14]; + THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - return this; + return this.setFromMatrixPosition( m ); }, getScaleFromMatrix: function ( m ) { - var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length(); - var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length(); - var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; + THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - return this; + return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { - var offset = index * 4; - - var me = matrix.elements; - - this.x = me[ offset ]; - this.y = me[ offset + 1 ]; - this.z = me[ offset + 2 ]; - - return this; - - }, - - equals: function ( v ) { + THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + return this.setFromMatrixColumn( index, matrix ); }, - fromArray: function ( array ) { + setFromMatrixPosition: function ( m ) { - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; + this.x = m.elements[ 12 ]; + this.y = m.elements[ 13 ]; + this.z = m.elements[ 14 ]; return this; }, - toArray: function () { - - return [ this.x, this.y, this.z ]; - - }, - - clone: function () { - - return new THREE.Vector3( this.x, this.y, this.z ); - - } - -}; - -THREE.extend( THREE.Vector3.prototype, { - - applyEuler: function () { - - var quaternion = new THREE.Quaternion(); - - return function ( euler ) { - - if ( euler instanceof THREE.Euler === false ) { - - console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); - - } + setFromMatrixScale: function ( m ) { - this.applyQuaternion( quaternion.setFromEuler( euler ) ); + var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); + var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); + var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); - return this; + this.x = sx; + this.y = sy; + this.z = sz; - }; + return this; + }, - }(), + setFromMatrixColumn: function ( index, matrix ) { + + var offset = index * 4; - applyAxisAngle: function () { + var me = matrix.elements; - var quaternion = new THREE.Quaternion(); + this.x = me[ offset ]; + this.y = me[ offset + 1 ]; + this.z = me[ offset + 2 ]; - return function ( axis, angle ) { + return this; - this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + }, - return this; + equals: function ( v ) { - }; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - }(), + }, - projectOnVector: function () { + fromArray: function ( array, offset ) { - var v1 = new THREE.Vector3(); + if ( offset === undefined ) offset = 0; - return function ( vector ) { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; - v1.copy( vector ).normalize(); - var d = this.dot( v1 ); - return this.copy( v1 ).multiplyScalar( d ); + return this; - }; + }, - }(), + toArray: function ( array, offset ) { - projectOnPlane: function () { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - var v1 = new THREE.Vector3(); + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - return function ( planeNormal ) { + return array; - v1.copy( this ).projectOnVector( planeNormal ); + }, - return this.sub( v1 ); + fromAttribute: function ( attribute, index, offset ) { - } + if ( offset === undefined ) offset = 0; - }(), + index = index * attribute.itemSize + offset; - reflect: function () { + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; - var v1 = new THREE.Vector3(); + return this; - return function ( vector ) { + }, - v1.copy( this ).projectOnVector( vector ).multiplyScalar( 2 ); + clone: function () { - return this.subVectors( v1, this ); + return new THREE.Vector3( this.x, this.y, this.z ); - } + } - }() +}; -} ); +// File:src/math/Vector4.js /** * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -2182,7 +2548,7 @@ THREE.Vector4.prototype = { case 1: this.y = value; break; case 2: this.z = value; break; case 3: this.w = value; break; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -2196,7 +2562,7 @@ THREE.Vector4.prototype = { case 1: return this.y; case 2: return this.z; case 3: return this.w; - default: throw new Error( "index is out of range: " + index ); + default: throw new Error( 'index is out of range: ' + index ); } @@ -2217,7 +2583,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -2257,7 +2623,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -2271,9 +2637,20 @@ THREE.Vector4.prototype = { }, - subVectors: function ( a, b ) { + subScalar: function ( s ) { - this.x = a.x - b.x; + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; this.w = a.w - b.w; @@ -2302,10 +2679,10 @@ THREE.Vector4.prototype = { var e = m.elements; - this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; - this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; - this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; - this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; + this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; return this; @@ -2375,22 +2752,22 @@ THREE.Vector4.prototype = { te = m.elements, - m11 = te[0], m12 = te[4], m13 = te[8], - m21 = te[1], m22 = te[5], m23 = te[9], - m31 = te[2], m32 = te[6], m33 = te[10]; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; if ( ( Math.abs( m12 - m21 ) < epsilon ) - && ( Math.abs( m13 - m31 ) < epsilon ) - && ( Math.abs( m23 - m32 ) < epsilon ) ) { + && ( Math.abs( m13 - m31 ) < epsilon ) + && ( Math.abs( m23 - m32 ) < epsilon ) ) { // singularity found // first check for identity matrix which must have +1 for all terms // in leading diagonal and zero in other terms if ( ( Math.abs( m12 + m21 ) < epsilon2 ) - && ( Math.abs( m13 + m31 ) < epsilon2 ) - && ( Math.abs( m23 + m32 ) < epsilon2 ) - && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + && ( Math.abs( m13 + m31 ) < epsilon2 ) + && ( Math.abs( m23 + m32 ) < epsilon2 ) + && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { // this singularity is identity matrix so angle = 0 @@ -2470,8 +2847,8 @@ THREE.Vector4.prototype = { // as we have reached here there are no singularities so we can handle normally var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) - + ( m13 - m31 ) * ( m13 - m31 ) - + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize if ( Math.abs( s ) < 0.001 ) s = 1; @@ -2595,9 +2972,80 @@ THREE.Vector4.prototype = { }, - negate: function() { + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector4(); + max = new THREE.Vector4(); + + } + + min.set( minVal, minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + + return this; + + }, + + negate: function () { + + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - return this.multiplyScalar( -1 ); + return this; }, @@ -2656,26 +3104,59 @@ THREE.Vector4.prototype = { }, + lerpVectors: function ( v1, v2, alpha ) { + + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + + return this; + + }, + equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); }, - fromArray: function ( array ) { + fromArray: function ( array, offset ) { - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; - this.w = array[ 3 ]; + if ( offset === undefined ) offset = 0; + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; return this; }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; + + }, + + fromAttribute: function ( attribute, index, offset ) { - return [ this.x, this.y, this.z, this.w ]; + if ( offset === undefined ) offset = 0; + + index = index * attribute.itemSize + offset; + + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; + this.w = attribute.array[ index + 3 ]; + + return this; }, @@ -2687,6 +3168,8 @@ THREE.Vector4.prototype = { }; +// File:src/math/Euler.js + /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -2712,18 +3195,6 @@ THREE.Euler.prototype = { _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, - _quaternion: undefined, - - _updateQuaternion: function () { - - if ( this._quaternion !== undefined ) { - - this._quaternion.setFromEuler( this, false ); - - } - - }, - get x () { return this._x; @@ -2733,7 +3204,7 @@ THREE.Euler.prototype = { set x ( value ) { this._x = value; - this._updateQuaternion(); + this.onChangeCallback(); }, @@ -2746,7 +3217,7 @@ THREE.Euler.prototype = { set y ( value ) { this._y = value; - this._updateQuaternion(); + this.onChangeCallback(); }, @@ -2759,7 +3230,7 @@ THREE.Euler.prototype = { set z ( value ) { this._z = value; - this._updateQuaternion(); + this.onChangeCallback(); }, @@ -2772,7 +3243,7 @@ THREE.Euler.prototype = { set order ( value ) { this._order = value; - this._updateQuaternion(); + this.onChangeCallback(); }, @@ -2783,7 +3254,7 @@ THREE.Euler.prototype = { this._z = z; this._order = order || this._order; - this._updateQuaternion(); + this.onChangeCallback(); return this; @@ -2796,34 +3267,28 @@ THREE.Euler.prototype = { this._z = euler._z; this._order = euler._order; - this._updateQuaternion(); + this.onChangeCallback(); return this; }, - setFromRotationMatrix: function ( m, order ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - // clamp, to handle numerical problems - - function clamp( x ) { + setFromRotationMatrix: function ( m, order, update ) { - return Math.min( Math.max( x, -1 ), 1 ); + var clamp = THREE.Math.clamp; - } + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements; - var m11 = te[0], m12 = te[4], m13 = te[8]; - var m21 = te[1], m22 = te[5], m23 = te[9]; - var m31 = te[2], m32 = te[6], m33 = te[10]; + var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; + var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; + var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; order = order || this._order; if ( order === 'XYZ' ) { - this._y = Math.asin( clamp( m13 ) ); + this._y = Math.asin( clamp( m13, - 1, 1 ) ); if ( Math.abs( m13 ) < 0.99999 ) { @@ -2839,7 +3304,7 @@ THREE.Euler.prototype = { } else if ( order === 'YXZ' ) { - this._x = Math.asin( - clamp( m23 ) ); + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); if ( Math.abs( m23 ) < 0.99999 ) { @@ -2855,7 +3320,7 @@ THREE.Euler.prototype = { } else if ( order === 'ZXY' ) { - this._x = Math.asin( clamp( m32 ) ); + this._x = Math.asin( clamp( m32, - 1, 1 ) ); if ( Math.abs( m32 ) < 0.99999 ) { @@ -2871,7 +3336,7 @@ THREE.Euler.prototype = { } else if ( order === 'ZYX' ) { - this._y = Math.asin( - clamp( m31 ) ); + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); if ( Math.abs( m31 ) < 0.99999 ) { @@ -2887,7 +3352,7 @@ THREE.Euler.prototype = { } else if ( order === 'YZX' ) { - this._z = Math.asin( clamp( m21 ) ); + this._z = Math.asin( clamp( m21, - 1, 1 ) ); if ( Math.abs( m21 ) < 0.99999 ) { @@ -2903,7 +3368,7 @@ THREE.Euler.prototype = { } else if ( order === 'XZY' ) { - this._z = Math.asin( - clamp( m12 ) ); + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); if ( Math.abs( m12 ) < 0.99999 ) { @@ -2919,86 +3384,37 @@ THREE.Euler.prototype = { } else { - console.warn( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) + THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) } this._order = order; - this._updateQuaternion(); + if ( update !== false ) this.onChangeCallback(); return this; }, - setFromQuaternion: function ( q, order, update ) { - - // q is assumed to be normalized - - // clamp, to handle numerical problems - - function clamp( x ) { - - return Math.min( Math.max( x, -1 ), 1 ); - - } - - // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m - - var sqx = q.x * q.x; - var sqy = q.y * q.y; - var sqz = q.z * q.z; - var sqw = q.w * q.w; - - order = order || this._order; - - if ( order === 'XYZ' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ) ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); - - } else if ( order === 'YXZ' ) { + setFromQuaternion: function () { - this._x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ) ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); + var matrix; - } else if ( order === 'ZXY' ) { - - this._x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ) ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); - - } else if ( order === 'ZYX' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ) ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); - - } else if ( order === 'YZX' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ) ) ); + return function ( q, order, update ) { - } else if ( order === 'XZY' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ) ) ); - - } else { + if ( matrix === undefined ) matrix = new THREE.Matrix4(); + matrix.makeRotationFromQuaternion( q ); + this.setFromRotationMatrix( matrix, order, update ); - console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order ) + return this; - } + }; - this._order = order; + }(), - if ( update !== false ) this._updateQuaternion(); + setFromVector3: function ( v, order ) { - return this; + return this.set( v.x, v.y, v.z, order || this._order ); }, @@ -3015,9 +3431,14 @@ THREE.Euler.prototype = { }; - }(), + equals: function ( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + }, + fromArray: function ( array ) { this._x = array[ 0 ]; @@ -3025,24 +3446,49 @@ THREE.Euler.prototype = { this._z = array[ 2 ]; if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - this._updateQuaternion(); + this.onChangeCallback(); return this; }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this._x, this._y, this._z, this._order ]; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + return array; }, - equals: function ( euler ) { + toVector3: function ( optionalResult ) { - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + if ( optionalResult ) { + + return optionalResult.set( this._x, this._y, this._z ); + + } else { + + return new THREE.Vector3( this._x, this._y, this._z ); + + } + + }, + + onChange: function ( callback ) { + + this.onChangeCallback = callback; + + return this; }, + onChangeCallback: function () {}, + clone: function () { return new THREE.Euler( this._x, this._y, this._z, this._order ); @@ -3051,6 +3497,8 @@ THREE.Euler.prototype = { }; +// File:src/math/Line3.js + /** * @author bhouston / http://exocortex.com */ @@ -3118,7 +3566,7 @@ THREE.Line3.prototype = { }, - closestPointToPointParameter: function() { + closestPointToPointParameter: function () { var startP = new THREE.Vector3(); var startEnd = new THREE.Vector3(); @@ -3178,6 +3626,8 @@ THREE.Line3.prototype = { }; +// File:src/math/Box2.js + /** * @author bhouston / http://exocortex.com */ @@ -3185,7 +3635,7 @@ THREE.Line3.prototype = { THREE.Box2 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity ); }; @@ -3204,42 +3654,11 @@ THREE.Box2.prototype = { setFromPoints: function ( points ) { - if ( points.length > 0 ) { - - var point = points[ 0 ]; - - this.min.copy( point ); - this.max.copy( point ); - - for ( var i = 1, il = points.length; i < il; i ++ ) { - - point = points[ i ]; - - if ( point.x < this.min.x ) { - - this.min.x = point.x; - - } else if ( point.x > this.max.x ) { - - this.max.x = point.x; - - } - - if ( point.y < this.min.y ) { - - this.min.y = point.y; - - } else if ( point.y > this.max.y ) { - - this.max.y = point.y; - - } - - } + this.makeEmpty(); - } else { + for ( var i = 0, il = points.length; i < il; i ++ ) { - this.makeEmpty(); + this.expandByPoint( points[ i ] ) } @@ -3275,7 +3694,7 @@ THREE.Box2.prototype = { makeEmpty: function () { this.min.x = this.min.y = Infinity; - this.max.x = this.max.y = -Infinity; + this.max.x = this.max.y = - Infinity; return this; @@ -3321,7 +3740,7 @@ THREE.Box2.prototype = { expandByScalar: function ( scalar ) { - this.min.addScalar( -scalar ); + this.min.addScalar( - scalar ); this.max.addScalar( scalar ); return this; @@ -3353,12 +3772,14 @@ THREE.Box2.prototype = { }, - getParameter: function ( point ) { + getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. - return new THREE.Vector2( + var result = optionalTarget || new THREE.Vector2(); + + return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ) ); @@ -3441,6 +3862,8 @@ THREE.Box2.prototype = { }; +// File:src/math/Box3.js + /** * @author bhouston / http://exocortex.com * @author WestLangley / http://github.com/WestLangley @@ -3449,7 +3872,7 @@ THREE.Box2.prototype = { THREE.Box3 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity ); }; @@ -3466,58 +3889,13 @@ THREE.Box3.prototype = { }, - addPoint: function ( point ) { - - if ( point.x < this.min.x ) { - - this.min.x = point.x; - - } else if ( point.x > this.max.x ) { - - this.max.x = point.x; - - } - - if ( point.y < this.min.y ) { - - this.min.y = point.y; - - } else if ( point.y > this.max.y ) { - - this.max.y = point.y; - - } - - if ( point.z < this.min.z ) { - - this.min.z = point.z; - - } else if ( point.z > this.max.z ) { - - this.max.z = point.z; - - } - - }, - setFromPoints: function ( points ) { - if ( points.length > 0 ) { - - var point = points[ 0 ]; - - this.min.copy( point ); - this.max.copy( point ); - - for ( var i = 1, il = points.length; i < il; i ++ ) { - - this.addPoint( points[ i ] ) - - } + this.makeEmpty(); - } else { + for ( var i = 0, il = points.length; i < il; i ++ ) { - this.makeEmpty(); + this.expandByPoint( points[ i ] ) } @@ -3525,7 +3903,7 @@ THREE.Box3.prototype = { }, - setFromCenterAndSize: function() { + setFromCenterAndSize: function () { var v1 = new THREE.Vector3(); @@ -3542,14 +3920,14 @@ THREE.Box3.prototype = { }(), - setFromObject: function() { + setFromObject: function () { // Computes the world-axis-aligned bounding box of an object (including its children), // accounting for both the object's, and childrens', world transforms var v1 = new THREE.Vector3(); - return function( object ) { + return function ( object ) { var scope = this; @@ -3559,17 +3937,37 @@ THREE.Box3.prototype = { object.traverse( function ( node ) { - if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { + var geometry = node.geometry; + + if ( geometry !== undefined ) { + + if ( geometry instanceof THREE.Geometry ) { + + var vertices = geometry.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - var vertices = node.geometry.vertices; + v1.copy( vertices[ i ] ); - for ( var i = 0, il = vertices.length; i < il; i++ ) { + v1.applyMatrix4( node.matrixWorld ); - v1.copy( vertices[ i ] ); + scope.expandByPoint( v1 ); - v1.applyMatrix4( node.matrixWorld ); + } + + } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) { + + var positions = geometry.attributes[ 'position' ].array; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - scope.expandByPoint( v1 ); + v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + v1.applyMatrix4( node.matrixWorld ); + + scope.expandByPoint( v1 ); + + } } @@ -3595,7 +3993,7 @@ THREE.Box3.prototype = { makeEmpty: function () { this.min.x = this.min.y = this.min.z = Infinity; - this.max.x = this.max.y = this.max.z = -Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; return this; @@ -3643,7 +4041,7 @@ THREE.Box3.prototype = { expandByScalar: function ( scalar ) { - this.min.addScalar( -scalar ); + this.min.addScalar( - scalar ); this.max.addScalar( scalar ); return this; @@ -3678,12 +4076,14 @@ THREE.Box3.prototype = { }, - getParameter: function ( point ) { + getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. - return new THREE.Vector3( + var result = optionalTarget || new THREE.Vector3(); + + return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ), ( point.z - this.min.z ) / ( this.max.z - this.min.z ) @@ -3714,7 +4114,7 @@ THREE.Box3.prototype = { }, - distanceToPoint: function() { + distanceToPoint: function () { var v1 = new THREE.Vector3(); @@ -3727,7 +4127,7 @@ THREE.Box3.prototype = { }(), - getBoundingSphere: function() { + getBoundingSphere: function () { var v1 = new THREE.Vector3(); @@ -3762,7 +4162,7 @@ THREE.Box3.prototype = { }, - applyMatrix4: function() { + applyMatrix4: function () { var points = [ new THREE.Vector3(), @@ -3778,14 +4178,14 @@ THREE.Box3.prototype = { return function ( matrix ) { // NOTE: I am using a binary pattern to specify all 2^3 combinations below - points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 this.makeEmpty(); this.setFromPoints( points ); @@ -3819,23 +4219,30 @@ THREE.Box3.prototype = { }; +// File:src/math/Matrix3.js + /** * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://exocortex.com */ -THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { +THREE.Matrix3 = function () { - this.elements = new Float32Array(9); + this.elements = new Float32Array( [ - this.set( + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, - n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, - n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 + ] ); + + if ( arguments.length > 0 ) { + + THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); + + } - ); }; THREE.Matrix3.prototype = { @@ -3846,9 +4253,9 @@ THREE.Matrix3.prototype = { var te = this.elements; - te[0] = n11; te[3] = n12; te[6] = n13; - te[1] = n21; te[4] = n22; te[7] = n23; - te[2] = n31; te[5] = n32; te[8] = n33; + te[ 0 ] = n11; te[ 3 ] = n12; te[ 6 ] = n13; + te[ 1 ] = n21; te[ 4 ] = n22; te[ 7 ] = n23; + te[ 2 ] = n31; te[ 5 ] = n32; te[ 8 ] = n33; return this; @@ -3874,9 +4281,9 @@ THREE.Matrix3.prototype = { this.set( - me[0], me[3], me[6], - me[1], me[4], me[7], - me[2], me[5], me[8] + me[ 0 ], me[ 3 ], me[ 6 ], + me[ 1 ], me[ 4 ], me[ 7 ], + me[ 2 ], me[ 5 ], me[ 8 ] ); @@ -3886,32 +4293,42 @@ THREE.Matrix3.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, - multiplyVector3Array: function() { + multiplyVector3Array: function ( a ) { + + THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + + applyToVector3Array: function () { var v1 = new THREE.Vector3(); - return function ( a ) { + return function ( array, offset, length ) { + + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - for ( var i = 0, il = a.length; i < il; i += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; + v1.x = array[ j ]; + v1.y = array[ j + 1 ]; + v1.z = array[ j + 2 ]; - v1.applyMatrix3(this); + v1.applyMatrix3( this ); - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; + array[ j ] = v1.x; + array[ j + 1 ] = v1.y; + array[ j + 2 ] = v1.z; } - return a; + return array; }; @@ -3921,9 +4338,9 @@ THREE.Matrix3.prototype = { var te = this.elements; - te[0] *= s; te[3] *= s; te[6] *= s; - te[1] *= s; te[4] *= s; te[7] *= s; - te[2] *= s; te[5] *= s; te[8] *= s; + te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; + te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; + te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; return this; @@ -3933,11 +4350,11 @@ THREE.Matrix3.prototype = { var te = this.elements; - var a = te[0], b = te[1], c = te[2], - d = te[3], e = te[4], f = te[5], - g = te[6], h = te[7], i = te[8]; + var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], + d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], + g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; }, @@ -3949,15 +4366,15 @@ THREE.Matrix3.prototype = { var me = matrix.elements; var te = this.elements; - te[ 0 ] = me[10] * me[5] - me[6] * me[9]; - te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; - te[ 2 ] = me[6] * me[1] - me[2] * me[5]; - te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; - te[ 4 ] = me[10] * me[0] - me[2] * me[8]; - te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; - te[ 6 ] = me[9] * me[4] - me[5] * me[8]; - te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; - te[ 8 ] = me[5] * me[0] - me[1] * me[4]; + te[ 0 ] = me[ 10 ] * me[ 5 ] - me[ 6 ] * me[ 9 ]; + te[ 1 ] = - me[ 10 ] * me[ 1 ] + me[ 2 ] * me[ 9 ]; + te[ 2 ] = me[ 6 ] * me[ 1 ] - me[ 2 ] * me[ 5 ]; + te[ 3 ] = - me[ 10 ] * me[ 4 ] + me[ 6 ] * me[ 8 ]; + te[ 4 ] = me[ 10 ] * me[ 0 ] - me[ 2 ] * me[ 8 ]; + te[ 5 ] = - me[ 6 ] * me[ 0 ] + me[ 2 ] * me[ 4 ]; + te[ 6 ] = me[ 9 ] * me[ 4 ] - me[ 5 ] * me[ 8 ]; + te[ 7 ] = - me[ 9 ] * me[ 0 ] + me[ 1 ] * me[ 8 ]; + te[ 8 ] = me[ 5 ] * me[ 0 ] - me[ 1 ] * me[ 4 ]; var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; @@ -3973,7 +4390,7 @@ THREE.Matrix3.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } @@ -3993,14 +4410,34 @@ THREE.Matrix3.prototype = { var tmp, m = this.elements; - tmp = m[1]; m[1] = m[3]; m[3] = tmp; - tmp = m[2]; m[2] = m[6]; m[6] = tmp; - tmp = m[5]; m[5] = m[7]; m[7] = tmp; + tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; + tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; + tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; return this; }, + flattenToArrayOffset: function ( array, offset ) { + + var te = this.elements; + + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; + + return array; + + }, + getNormalMatrix: function ( m ) { // input: THREE.Matrix4 @@ -4029,22 +4466,36 @@ THREE.Matrix3.prototype = { }, - clone: function () { + fromArray: function ( array ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { var te = this.elements; - return new THREE.Matrix3( + return [ + te[ 0 ], te[ 1 ], te[ 2 ], + te[ 3 ], te[ 4 ], te[ 5 ], + te[ 6 ], te[ 7 ], te[ 8 ] + ]; + + }, - te[0], te[3], te[6], - te[1], te[4], te[7], - te[2], te[5], te[8] + clone: function () { - ); + return new THREE.Matrix3().fromArray( this.elements ); } }; +// File:src/math/Matrix4.js + /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -4058,20 +4509,22 @@ THREE.Matrix3.prototype = { * @author WestLangley / http://github.com/WestLangley */ +THREE.Matrix4 = function () { + + this.elements = new Float32Array( [ -THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - this.elements = new Float32Array( 16 ); + ] ); - // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix - // we should not support semi specification of Matrix4, it is just weird. + if ( arguments.length > 0 ) { - var te = this.elements; + THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; - te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; - te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; - te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; + } }; @@ -4083,10 +4536,10 @@ THREE.Matrix4.prototype = { var te = this.elements; - te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; - te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; - te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; - te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; return this; @@ -4117,7 +4570,7 @@ THREE.Matrix4.prototype = { extractPosition: function ( m ) { - console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); + THREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, @@ -4127,38 +4580,63 @@ THREE.Matrix4.prototype = { var te = this.elements; var me = m.elements; - te[12] = me[12]; - te[13] = me[13]; - te[14] = me[14]; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; return this; }, - extractRotation: function () { + extractBasis: function ( xAxis, yAxis, zAxis ) { + + var te = this.elements; + + xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] ); + yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] ); + zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] ); + + return this; + + }, + + makeBasis: function ( xAxis, yAxis, zAxis ) { - var v1 = new THREE.Vector3(); + this.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + + return this; + + }, + + extractRotation: function () { + + var v1 = new THREE.Vector3(); return function ( m ) { var te = this.elements; var me = m.elements; - var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); - var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); - var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); + var scaleX = 1 / v1.set( me[ 0 ], me[ 1 ], me[ 2 ] ).length(); + var scaleY = 1 / v1.set( me[ 4 ], me[ 5 ], me[ 6 ] ).length(); + var scaleZ = 1 / v1.set( me[ 8 ], me[ 9 ], me[ 10 ] ).length(); - te[0] = me[0] * scaleX; - te[1] = me[1] * scaleX; - te[2] = me[2] * scaleX; + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; - te[4] = me[4] * scaleY; - te[5] = me[5] * scaleY; - te[6] = me[6] * scaleY; + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; - te[8] = me[8] * scaleZ; - te[9] = me[9] * scaleZ; - te[10] = me[10] * scaleZ; + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; return this; @@ -4170,7 +4648,7 @@ THREE.Matrix4.prototype = { if ( euler instanceof THREE.Euler === false ) { - console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); + THREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } @@ -4185,110 +4663,110 @@ THREE.Matrix4.prototype = { var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = c * e; - te[4] = - c * f; - te[8] = d; + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - te[1] = af + be * d; - te[5] = ae - bf * d; - te[9] = - b * c; + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - te[2] = bf - ae * d; - te[6] = be + af * d; - te[10] = a * c; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; } else if ( euler.order === 'YXZ' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; - te[0] = ce + df * b; - te[4] = de * b - cf; - te[8] = a * d; + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - te[1] = a * f; - te[5] = a * e; - te[9] = - b; + te[ 1 ] = a * f; + te[ 5 ] = a * e; + te[ 9 ] = - b; - te[2] = cf * b - de; - te[6] = df + ce * b; - te[10] = a * c; + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; } else if ( euler.order === 'ZXY' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; - te[0] = ce - df * b; - te[4] = - a * f; - te[8] = de + cf * b; + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - te[1] = cf + de * b; - te[5] = a * e; - te[9] = df - ce * b; + te[ 1 ] = cf + de * b; + te[ 5 ] = a * e; + te[ 9 ] = df - ce * b; - te[2] = - a * d; - te[6] = b; - te[10] = a * c; + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; } else if ( euler.order === 'ZYX' ) { var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = c * e; - te[4] = be * d - af; - te[8] = ae * d + bf; + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - te[1] = c * f; - te[5] = bf * d + ae; - te[9] = af * d - be; + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - te[2] = - d; - te[6] = b * c; - te[10] = a * c; + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; } else if ( euler.order === 'YZX' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - te[0] = c * e; - te[4] = bd - ac * f; - te[8] = bc * f + ad; + te[ 0 ] = c * e; + te[ 4 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; - te[1] = f; - te[5] = a * e; - te[9] = - b * e; + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - te[2] = - d * e; - te[6] = ad * f + bc; - te[10] = ac - bd * f; + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; } else if ( euler.order === 'XZY' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - te[0] = c * e; - te[4] = - f; - te[8] = d * e; + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - te[1] = ac * f + bd; - te[5] = a * e; - te[9] = ad * f - bc; + te[ 1 ] = ac * f + bd; + te[ 5 ] = a * e; + te[ 9 ] = ad * f - bc; - te[2] = bc * f - ad; - te[6] = b * e; - te[10] = bd * f + ac; + te[ 2 ] = bc * f - ad; + te[ 6 ] = b * e; + te[ 10 ] = bd * f + ac; } // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; return this; @@ -4296,7 +4774,7 @@ THREE.Matrix4.prototype = { setRotationFromQuaternion: function ( q ) { - console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); + THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); return this.makeRotationFromQuaternion( q ); @@ -4312,34 +4790,34 @@ THREE.Matrix4.prototype = { var yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2; - te[0] = 1 - ( yy + zz ); - te[4] = xy - wz; - te[8] = xz + wy; + te[ 0 ] = 1 - ( yy + zz ); + te[ 4 ] = xy - wz; + te[ 8 ] = xz + wy; - te[1] = xy + wz; - te[5] = 1 - ( xx + zz ); - te[9] = yz - wx; + te[ 1 ] = xy + wz; + te[ 5 ] = 1 - ( xx + zz ); + te[ 9 ] = yz - wx; - te[2] = xz - wy; - te[6] = yz + wx; - te[10] = 1 - ( xx + yy ); + te[ 2 ] = xz - wy; + te[ 6 ] = yz + wx; + te[ 10 ] = 1 - ( xx + yy ); // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; return this; }, - lookAt: function() { + lookAt: function () { var x = new THREE.Vector3(); var y = new THREE.Vector3(); @@ -4369,9 +4847,9 @@ THREE.Matrix4.prototype = { y.crossVectors( z, x ); - te[0] = x.x; te[4] = y.x; te[8] = z.x; - te[1] = x.y; te[5] = y.y; te[9] = z.y; - te[2] = x.z; te[6] = y.z; te[10] = z.z; + te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x; + te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y; + te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z; return this; @@ -4383,7 +4861,7 @@ THREE.Matrix4.prototype = { if ( n !== undefined ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } @@ -4398,35 +4876,35 @@ THREE.Matrix4.prototype = { var be = b.elements; var te = this.elements; - var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; - var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; - var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; - var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; + var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; - var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; - var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; - var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; + var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return this; @@ -4438,10 +4916,10 @@ THREE.Matrix4.prototype = { this.multiplyMatrices( a, b ); - r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; - r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; - r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; - r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; + r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ]; + r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ]; + r[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ]; + r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ]; return this; @@ -4451,10 +4929,10 @@ THREE.Matrix4.prototype = { var te = this.elements; - te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; - te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; - te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; - te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; return this; @@ -4462,39 +4940,49 @@ THREE.Matrix4.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, - multiplyVector3Array: function() { + multiplyVector3Array: function ( a ) { + + THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); + + }, + + applyToVector3Array: function () { var v1 = new THREE.Vector3(); - return function ( a ) { + return function ( array, offset, length ) { + + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - for ( var i = 0, il = a.length; i < il; i += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; + v1.x = array[ j ]; + v1.y = array[ j + 1 ]; + v1.z = array[ j + 2 ]; - v1.applyProjection( this ); + v1.applyMatrix4( this ); - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; + array[ j ] = v1.x; + array[ j + 1 ] = v1.y; + array[ j + 2 ] = v1.z; } - return a; + return array; }; @@ -4502,7 +4990,7 @@ THREE.Matrix4.prototype = { rotateAxis: function ( v ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); @@ -4510,7 +4998,7 @@ THREE.Matrix4.prototype = { crossVector: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, @@ -4519,46 +5007,46 @@ THREE.Matrix4.prototype = { var te = this.elements; - var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; - var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; - var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; - var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; + var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; //TODO: make this more efficient //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) return ( n41 * ( - +n14 * n23 * n32 - -n13 * n24 * n32 - -n14 * n22 * n33 - +n12 * n24 * n33 - +n13 * n22 * n34 - -n12 * n23 * n34 + + n14 * n23 * n32 + - n13 * n24 * n32 + - n14 * n22 * n33 + + n12 * n24 * n33 + + n13 * n22 * n34 + - n12 * n23 * n34 ) + n42 * ( - +n11 * n23 * n34 - -n11 * n24 * n33 - +n14 * n21 * n33 - -n13 * n21 * n34 - +n13 * n24 * n31 - -n14 * n23 * n31 + + n11 * n23 * n34 + - n11 * n24 * n33 + + n14 * n21 * n33 + - n13 * n21 * n34 + + n13 * n24 * n31 + - n14 * n23 * n31 ) + n43 * ( - +n11 * n24 * n32 - -n11 * n22 * n34 - -n14 * n21 * n32 - +n12 * n21 * n34 - +n14 * n22 * n31 - -n12 * n24 * n31 + + n11 * n24 * n32 + - n11 * n22 * n34 + - n14 * n21 * n32 + + n12 * n21 * n34 + + n14 * n22 * n31 + - n12 * n24 * n31 ) + n44 * ( - -n13 * n22 * n31 - -n11 * n23 * n32 - +n11 * n22 * n33 - +n13 * n21 * n32 - -n12 * n21 * n33 - +n12 * n23 * n31 + - n13 * n22 * n31 + - n11 * n23 * n32 + + n11 * n22 * n33 + + n13 * n21 * n32 + - n12 * n21 * n33 + + n12 * n23 * n31 ) ); @@ -4570,67 +5058,56 @@ THREE.Matrix4.prototype = { var te = this.elements; var tmp; - tmp = te[1]; te[1] = te[4]; te[4] = tmp; - tmp = te[2]; te[2] = te[8]; te[8] = tmp; - tmp = te[6]; te[6] = te[9]; te[9] = tmp; + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - tmp = te[3]; te[3] = te[12]; te[12] = tmp; - tmp = te[7]; te[7] = te[13]; te[13] = tmp; - tmp = te[11]; te[11] = te[14]; te[14] = tmp; + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; return this; }, - flattenToArray: function ( flat ) { + flattenToArrayOffset: function ( array, offset ) { var te = this.elements; - flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; - flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; - flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; - flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; - return flat; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - }, - - flattenToArrayOffset: function( flat, offset ) { - - var te = this.elements; - flat[ offset ] = te[0]; - flat[ offset + 1 ] = te[1]; - flat[ offset + 2 ] = te[2]; - flat[ offset + 3 ] = te[3]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; - flat[ offset + 4 ] = te[4]; - flat[ offset + 5 ] = te[5]; - flat[ offset + 6 ] = te[6]; - flat[ offset + 7 ] = te[7]; + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - flat[ offset + 8 ] = te[8]; - flat[ offset + 9 ] = te[9]; - flat[ offset + 10 ] = te[10]; - flat[ offset + 11 ] = te[11]; + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - flat[ offset + 12 ] = te[12]; - flat[ offset + 13 ] = te[13]; - flat[ offset + 14 ] = te[14]; - flat[ offset + 15 ] = te[15]; - - return flat; + return array; }, - getPosition: function() { + getPosition: function () { var v1 = new THREE.Vector3(); return function () { - console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; - return v1.set( te[12], te[13], te[14] ); + return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); }; @@ -4640,9 +5117,9 @@ THREE.Matrix4.prototype = { var te = this.elements; - te[12] = v.x; - te[13] = v.y; - te[14] = v.z; + te[ 12 ] = v.x; + te[ 13 ] = v.y; + te[ 14 ] = v.z; return this; @@ -4654,33 +5131,33 @@ THREE.Matrix4.prototype = { var te = this.elements; var me = m.elements; - var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; - var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; - var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; - var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; - - te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; - te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; - te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; - te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; - te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; - te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; - te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; - te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; - te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; - te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; - te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; - te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; - te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; - te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; - te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; - te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; + var n11 = me[ 0 ], n12 = me[ 4 ], n13 = me[ 8 ], n14 = me[ 12 ]; + var n21 = me[ 1 ], n22 = me[ 5 ], n23 = me[ 9 ], n24 = me[ 13 ]; + var n31 = me[ 2 ], n32 = me[ 6 ], n33 = me[ 10 ], n34 = me[ 14 ]; + var n41 = me[ 3 ], n42 = me[ 7 ], n43 = me[ 11 ], n44 = me[ 15 ]; + + te[ 0 ] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; + te[ 4 ] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; + te[ 8 ] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; + te[ 12 ] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + te[ 1 ] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44; + te[ 5 ] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44; + te[ 9 ] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44; + te[ 13 ] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34; + te[ 2 ] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44; + te[ 6 ] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44; + te[ 10 ] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44; + te[ 14 ] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34; + te[ 3 ] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43; + te[ 7 ] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43; + te[ 11 ] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43; + te[ 15 ] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33; var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; if ( det == 0 ) { - var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { @@ -4688,7 +5165,7 @@ THREE.Matrix4.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } @@ -4705,31 +5182,31 @@ THREE.Matrix4.prototype = { translate: function ( v ) { - console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); + THREE.error( 'THREE.Matrix4: .translate() has been removed.' ); }, rotateX: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' ); }, rotateY: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' ); }, rotateZ: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); }, rotateByAxis: function ( axis, angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); + THREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); }, @@ -4738,10 +5215,10 @@ THREE.Matrix4.prototype = { var te = this.elements; var x = v.x, y = v.y, z = v.z; - te[0] *= x; te[4] *= y; te[8] *= z; - te[1] *= x; te[5] *= y; te[9] *= z; - te[2] *= x; te[6] *= y; te[10] *= z; - te[3] *= x; te[7] *= y; te[11] *= z; + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; @@ -4751,9 +5228,9 @@ THREE.Matrix4.prototype = { var te = this.elements; - var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; - var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; - var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; + var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); @@ -4781,7 +5258,7 @@ THREE.Matrix4.prototype = { this.set( 1, 0, 0, 0, - 0, c, -s, 0, + 0, c, - s, 0, 0, s, c, 0, 0, 0, 0, 1 @@ -4799,7 +5276,7 @@ THREE.Matrix4.prototype = { c, 0, s, 0, 0, 1, 0, 0, - -s, 0, c, 0, + - s, 0, c, 0, 0, 0, 0, 1 ); @@ -4814,7 +5291,7 @@ THREE.Matrix4.prototype = { this.set( - c, -s, 0, 0, + c, - s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 @@ -4882,13 +5359,19 @@ THREE.Matrix4.prototype = { var te = this.elements; - var sx = vector.set( te[0], te[1], te[2] ).length(); - var sy = vector.set( te[4], te[5], te[6] ).length(); - var sz = vector.set( te[8], te[9], te[10] ).length(); + var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if ( det < 0 ) { + sx = - sx; + } - position.x = te[12]; - position.y = te[13]; - position.z = te[14]; + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; // scale the rotation part @@ -4898,17 +5381,17 @@ THREE.Matrix4.prototype = { var invSY = 1 / sy; var invSZ = 1 / sz; - matrix.elements[0] *= invSX; - matrix.elements[1] *= invSX; - matrix.elements[2] *= invSX; + matrix.elements[ 0 ] *= invSX; + matrix.elements[ 1 ] *= invSX; + matrix.elements[ 2 ] *= invSX; - matrix.elements[4] *= invSY; - matrix.elements[5] *= invSY; - matrix.elements[6] *= invSY; + matrix.elements[ 4 ] *= invSY; + matrix.elements[ 5 ] *= invSY; + matrix.elements[ 6 ] *= invSY; - matrix.elements[8] *= invSZ; - matrix.elements[9] *= invSZ; - matrix.elements[10] *= invSZ; + matrix.elements[ 8 ] *= invSZ; + matrix.elements[ 9 ] *= invSZ; + matrix.elements[ 10 ] *= invSZ; quaternion.setFromRotationMatrix( matrix ); @@ -4933,10 +5416,10 @@ THREE.Matrix4.prototype = { var c = - ( far + near ) / ( far - near ); var d = - 2 * far * near / ( far - near ); - te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; - te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; - te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; - te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; return this; @@ -4964,10 +5447,10 @@ THREE.Matrix4.prototype = { var y = ( top + bottom ) / h; var z = ( far + near ) / p; - te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; - te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; - te[2] = 0; te[6] = 0; te[10] = -2/p; te[14] = -z; - te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; + te[ 0 ] = 2 / w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 / h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 / p; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; return this; @@ -4996,21 +5479,14 @@ THREE.Matrix4.prototype = { clone: function () { - var te = this.elements; - - return new THREE.Matrix4( - - te[0], te[4], te[8], te[12], - te[1], te[5], te[9], te[13], - te[2], te[6], te[10], te[14], - te[3], te[7], te[11], te[15] - - ); + return new THREE.Matrix4().fromArray( this.elements ); } }; +// File:src/math/Ray.js + /** * @author bhouston / http://exocortex.com */ @@ -5106,123 +5582,133 @@ THREE.Ray.prototype = { }(), - distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + distanceSqToSegment: function () { + + var segCenter = new THREE.Vector3(); + var segDir = new THREE.Vector3(); + var diff = new THREE.Vector3(); + + return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + + // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp + // It returns the min distance between the ray and the segment + // defined by v0 and v1 + // It can also set two optional targets : + // - The closest point on the ray + // - The closest point on the segment + + segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + segDir.copy( v1 ).sub( v0 ).normalize(); + diff.copy( this.origin ).sub( segCenter ); + + var segExtent = v0.distanceTo( v1 ) * 0.5; + var a01 = - this.direction.dot( segDir ); + var b0 = diff.dot( this.direction ); + var b1 = - diff.dot( segDir ); + var c = diff.lengthSq(); + var det = Math.abs( 1 - a01 * a01 ); + var s0, s1, sqrDist, extDet; - // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment + if ( det > 0 ) { - var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); - var segDir = v1.clone().sub( v0 ).normalize(); - var segExtent = v0.distanceTo( v1 ) * 0.5; - var diff = this.origin.clone().sub( segCenter ); - var a01 = - this.direction.dot( segDir ); - var b0 = diff.dot( this.direction ); - var b1 = - diff.dot( segDir ); - var c = diff.lengthSq(); - var det = Math.abs( 1 - a01 * a01 ); - var s0, s1, sqrDist, extDet; + // The ray and segment are not parallel. - if ( det >= 0 ) { + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - // The ray and segment are not parallel. + if ( s0 >= 0 ) { - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + if ( s1 >= - extDet ) { - if ( s0 >= 0 ) { + if ( s1 <= extDet ) { - if ( s1 >= - extDet ) { + // region 0 + // Minimum at interior points of ray and segment. - if ( s1 <= extDet ) { + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - // region 0 - // Minimum at interior points of ray and segment. + } else { + + // region 1 - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } } else { - // region 1 + // region 5 - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } else { - // region 5 + if ( s1 <= - extDet ) { - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + // region 4 - } + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } else { + } else if ( s1 <= extDet ) { - if ( s1 <= - extDet) { + // region 3 - // region 4 + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } else { - } else if ( s1 <= extDet ) { + // region 2 - // region 3 + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } - } else { + } - // region 2 + } else { - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + // Ray and segment are parallel. - } + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } - } else { - - // Ray and segment are parallel. + if ( optionalPointOnRay ) { - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - } - - if ( optionalPointOnRay ) { + } - optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); + if ( optionalPointOnSegment ) { - } + optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); - if ( optionalPointOnSegment ) { + } - optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); + return sqrDist; - } + }; - return sqrDist; + }(), - }, isIntersectionSphere: function ( sphere ) { @@ -5230,6 +5716,47 @@ THREE.Ray.prototype = { }, + intersectSphere: function () { + + // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/ + + var v1 = new THREE.Vector3(); + + return function ( sphere, optionalTarget ) { + + v1.subVectors( sphere.center, this.origin ); + + var tca = v1.dot( this.direction ); + + var d2 = v1.dot( v1 ) - tca * tca; + + var radius2 = sphere.radius * sphere.radius; + + if ( d2 > radius2 ) return null; + + var thc = Math.sqrt( radius2 - d2 ); + + // t0 = first intersect point - entrance on front of sphere + var t0 = tca - thc; + + // t1 = second intersect point - exit point on back of sphere + var t1 = tca + thc; + + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) return null; + + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, optionalTarget ); + + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, optionalTarget ); + + } + + }(), + isIntersectionPlane: function ( plane ) { // check if the ray lies on the plane first @@ -5246,7 +5773,7 @@ THREE.Ray.prototype = { if ( denominator * distToPoint < 0 ) { - return true + return true; } @@ -5262,7 +5789,7 @@ THREE.Ray.prototype = { if ( denominator == 0 ) { // line is coplanar, return origin - if( plane.distanceToPoint( this.origin ) == 0 ) { + if ( plane.distanceToPoint( this.origin ) == 0 ) { return 0; @@ -5303,69 +5830,69 @@ THREE.Ray.prototype = { return this.intersectBox( box, v ) !== null; - } + }; }(), - intersectBox: function ( box , optionalTarget ) { + intersectBox: function ( box, optionalTarget ) { // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ var tmin,tmax,tymin,tymax,tzmin,tzmax; - var invdirx = 1/this.direction.x, - invdiry = 1/this.direction.y, - invdirz = 1/this.direction.z; + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; var origin = this.origin; - if (invdirx >= 0) { + if ( invdirx >= 0 ) { - tmin = (box.min.x - origin.x) * invdirx; - tmax = (box.max.x - origin.x) * invdirx; + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; } else { - tmin = (box.max.x - origin.x) * invdirx; - tmax = (box.min.x - origin.x) * invdirx; + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; } - if (invdiry >= 0) { + if ( invdiry >= 0 ) { - tymin = (box.min.y - origin.y) * invdiry; - tymax = (box.max.y - origin.y) * invdiry; + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; } else { - tymin = (box.max.y - origin.y) * invdiry; - tymax = (box.min.y - origin.y) * invdiry; + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; } - if ((tmin > tymax) || (tymin > tmax)) return null; + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; // These lines also handle the case where tmin or tmax is NaN // (result of 0 * Infinity). x !== x returns true if x is NaN - if (tymin > tmin || tmin !== tmin ) tmin = tymin; + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - if (tymax < tmax || tmax !== tmax ) tmax = tymax; + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - if (invdirz >= 0) { + if ( invdirz >= 0 ) { - tzmin = (box.min.z - origin.z) * invdirz; - tzmax = (box.max.z - origin.z) * invdirz; + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; } else { - tzmin = (box.max.z - origin.z) * invdirz; - tzmax = (box.min.z - origin.z) * invdirz; + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; } - if ((tmin > tzmax) || (tzmin > tmax)) return null; + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - if (tzmin > tmin || tmin !== tmin ) tmin = tzmin; + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - if (tzmax < tmax || tmax !== tmax ) tmax = tzmax; + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; //return point closest to the ray (positive side) @@ -5375,7 +5902,7 @@ THREE.Ray.prototype = { }, - intersectTriangle: function() { + intersectTriangle: function () { // Compute the offset origin, edges, and normal. var diff = new THREE.Vector3(); @@ -5454,7 +5981,7 @@ THREE.Ray.prototype = { // Ray intersects triangle. return this.at( QdN / DdN, optionalTarget ); - } + }; }(), @@ -5482,6 +6009,8 @@ THREE.Ray.prototype = { }; +// File:src/math/Sphere.js + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -5506,12 +6035,11 @@ THREE.Sphere.prototype = { return this; }, - setFromPoints: function () { var box = new THREE.Box3(); - return function ( points, optionalCenter ) { + return function ( points, optionalCenter ) { var center = this.center; @@ -5537,7 +6065,7 @@ THREE.Sphere.prototype = { return this; - }; + }; }(), @@ -5636,6 +6164,8 @@ THREE.Sphere.prototype = { }; +// File:src/math/Frustum.js + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -5665,12 +6195,12 @@ THREE.Frustum.prototype = { var planes = this.planes; - planes[0].copy( p0 ); - planes[1].copy( p1 ); - planes[2].copy( p2 ); - planes[3].copy( p3 ); - planes[4].copy( p4 ); - planes[5].copy( p5 ); + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); return this; @@ -5680,9 +6210,9 @@ THREE.Frustum.prototype = { var planes = this.planes; - for( var i = 0; i < 6; i ++ ) { + for ( var i = 0; i < 6; i ++ ) { - planes[i].copy( frustum.planes[i] ); + planes[ i ].copy( frustum.planes[ i ] ); } @@ -5694,10 +6224,10 @@ THREE.Frustum.prototype = { var planes = this.planes; var me = m.elements; - var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; - var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; - var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; - var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; + var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); @@ -5733,7 +6263,7 @@ THREE.Frustum.prototype = { var planes = this.planes; var center = sphere.center; - var negRadius = -sphere.radius; + var negRadius = - sphere.radius; for ( var i = 0; i < 6; i ++ ) { @@ -5751,18 +6281,18 @@ THREE.Frustum.prototype = { }, - intersectsBox : function() { + intersectsBox: function () { var p1 = new THREE.Vector3(), p2 = new THREE.Vector3(); - return function( box ) { + return function ( box ) { var planes = this.planes; for ( var i = 0; i < 6 ; i ++ ) { - var plane = planes[i]; + var plane = planes[ i ]; p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; @@ -5815,6 +6345,8 @@ THREE.Frustum.prototype = { }; +// File:src/math/Plane.js + /** * @author bhouston / http://exocortex.com */ @@ -5857,7 +6389,7 @@ THREE.Plane.prototype = { }, - setFromCoplanarPoints: function() { + setFromCoplanarPoints: function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); @@ -5900,7 +6432,7 @@ THREE.Plane.prototype = { negate: function () { - this.constant *= -1; + this.constant *= - 1; this.normal.negate(); return this; @@ -5945,7 +6477,7 @@ THREE.Plane.prototype = { }, - intersectLine: function() { + intersectLine: function () { var v1 = new THREE.Vector3(); @@ -5960,7 +6492,7 @@ THREE.Plane.prototype = { if ( denominator == 0 ) { // line is coplanar, return origin - if( this.distanceToPoint( line.start ) == 0 ) { + if ( this.distanceToPoint( line.start ) == 0 ) { return result.copy( line.start ); @@ -5973,7 +6505,7 @@ THREE.Plane.prototype = { var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - if( t < 0 || t > 1 ) { + if ( t < 0 || t > 1 ) { return undefined; @@ -5993,17 +6525,18 @@ THREE.Plane.prototype = { }, - applyMatrix4: function() { + applyMatrix4: function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); + var m1 = new THREE.Matrix3(); return function ( matrix, optionalNormalMatrix ) { // compute new normal based on theory here: // http://www.songho.ca/opengl/gl_normaltransform.html - optionalNormalMatrix = optionalNormalMatrix || new THREE.Matrix3().getNormalMatrix( matrix ); - var newNormal = v1.copy( this.normal ).applyMatrix3( optionalNormalMatrix ); + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); var newCoplanarPoint = this.coplanarPoint( v2 ); newCoplanarPoint.applyMatrix4( matrix ); @@ -6038,6 +6571,8 @@ THREE.Plane.prototype = { }; +// File:src/math/Math.js + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -6045,14 +6580,12 @@ THREE.Plane.prototype = { THREE.Math = { - PI2: Math.PI * 2, - generateUUID: function () { // http://www.broofa.com/Tools/Math.uuid.htm - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); - var uuid = new Array(36); + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); + var uuid = new Array( 36 ); var rnd = 0, r; return function () { @@ -6069,15 +6602,15 @@ THREE.Math = { } else { - if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; + if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; r = rnd & 0xf; rnd = rnd >> 4; - uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + uuid[ i ] = chars[ ( i == 19 ) ? ( r & 0x3 ) | 0x8 : r ]; } } - return uuid.join(''); + return uuid.join( '' ); }; @@ -6114,9 +6647,9 @@ THREE.Math = { if ( x <= min ) return 0; if ( x >= max ) return 1; - x = ( x - min )/( max - min ); + x = ( x - min ) / ( max - min ); - return x*x*(3 - 2*x); + return x * x * ( 3 - 2 * x ); }, @@ -6125,9 +6658,9 @@ THREE.Math = { if ( x <= min ) return 0; if ( x >= max ) return 1; - x = ( x - min )/( max - min ); + x = ( x - min ) / ( max - min ); - return x*x*x*(x*(x*6 - 15) + 10); + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); }, @@ -6144,7 +6677,7 @@ THREE.Math = { randInt: function ( low, high ) { - return low + Math.floor( Math.random() * ( high - low + 1 ) ); + return Math.floor( this.randFloat( low, high ) ); }, @@ -6164,13 +6697,7 @@ THREE.Math = { }, - sign: function ( x ) { - - return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 ); - - }, - - degToRad: function() { + degToRad: function () { var degreeToRadiansFactor = Math.PI / 180; @@ -6182,7 +6709,7 @@ THREE.Math = { }(), - radToDeg: function() { + radToDeg: function () { var radianToDegreesFactor = 180 / Math.PI; @@ -6192,10 +6719,32 @@ THREE.Math = { }; - }() + }(), + + isPowerOfTwo: function ( value ) { + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + + }, + + nextPowerOfTwo: function ( value ) { + + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; + + return value; + + } }; +// File:src/math/Spline.js + /** * Spline from Tween.js, slightly optimized (and trashed) * http://sole.github.com/tween.js/examples/05_spline.html @@ -6212,11 +6761,11 @@ THREE.Spline = function ( points ) { point, intPoint, weight, w2, w3, pa, pb, pc, pd; - this.initFromArray = function( a ) { + this.initFromArray = function ( a ) { this.points = []; - for ( var i = 0; i < a.length; i++ ) { + for ( var i = 0; i < a.length; i ++ ) { this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; @@ -6282,7 +6831,7 @@ THREE.Spline = function ( points ) { chunkLengths[ 0 ] = 0; - if ( !nSubDivisions ) nSubDivisions = 100; + if ( ! nSubDivisions ) nSubDivisions = 100; nSamples = this.points.length * nSubDivisions; @@ -6323,7 +6872,7 @@ THREE.Spline = function ( points ) { var i, j, index, indexCurrent, indexNext, - linearDistance, realDistance, + realDistance, sampling, position, newpoints = [], tmpVec = new THREE.Vector3(), @@ -6331,7 +6880,7 @@ THREE.Spline = function ( points ) { newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); - for ( i = 1; i < this.points.length; i++ ) { + for ( i = 1; i < this.points.length; i ++ ) { //tmpVec.copy( this.points[ i - 1 ] ); //linearDistance = tmpVec.distanceTo( this.points[ i ] ); @@ -6343,7 +6892,7 @@ THREE.Spline = function ( points ) { indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); indexNext = i / ( this.points.length - 1 ); - for ( j = 1; j < sampling - 1; j++ ) { + for ( j = 1; j < sampling - 1; j ++ ) { index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); @@ -6373,6 +6922,8 @@ THREE.Spline = function ( points ) { }; +// File:src/math/Triangle.js + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -6386,7 +6937,7 @@ THREE.Triangle = function ( a, b, c ) { }; -THREE.Triangle.normal = function() { +THREE.Triangle.normal = function () { var v0 = new THREE.Vector3(); @@ -6399,7 +6950,7 @@ THREE.Triangle.normal = function() { result.cross( v0 ); var resultLengthSq = result.lengthSq(); - if( resultLengthSq > 0 ) { + if ( resultLengthSq > 0 ) { return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); @@ -6413,7 +6964,7 @@ THREE.Triangle.normal = function() { // static/instance method to calculate barycoordinates // based on: http://www.blackpawn.com/texts/pointinpoly/default.html -THREE.Triangle.barycoordFromPoint = function() { +THREE.Triangle.barycoordFromPoint = function () { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); @@ -6436,10 +6987,10 @@ THREE.Triangle.barycoordFromPoint = function() { var result = optionalTarget || new THREE.Vector3(); // colinear or singular triangle - if( denom == 0 ) { + if ( denom == 0 ) { // arbitrary location outside of triangle? // not sure if this is the best idea, maybe should be returning undefined - return result.set( -2, -1, -1 ); + return result.set( - 2, - 1, - 1 ); } var invDenom = 1 / denom; @@ -6453,7 +7004,7 @@ THREE.Triangle.barycoordFromPoint = function() { }(); -THREE.Triangle.containsPoint = function() { +THREE.Triangle.containsPoint = function () { var v1 = new THREE.Vector3(); @@ -6483,9 +7034,9 @@ THREE.Triangle.prototype = { setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - this.a.copy( points[i0] ); - this.b.copy( points[i1] ); - this.c.copy( points[i2] ); + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); return this; @@ -6501,7 +7052,7 @@ THREE.Triangle.prototype = { }, - area: function() { + area: function () { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); @@ -6564,27 +7115,7 @@ THREE.Triangle.prototype = { }; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Vertex = function ( v ) { - - console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') - return v; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.UV = function ( u, v ) { - - console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') - return new THREE.Vector2( u, v ); - -}; +// File:src/core/Clock.js /** * @author alteredq / http://alteredqualia.com/ @@ -6609,8 +7140,8 @@ THREE.Clock.prototype = { start: function () { this.startTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + ? self.performance.now() + : Date.now(); this.oldTime = this.startTime; this.running = true; @@ -6643,8 +7174,8 @@ THREE.Clock.prototype = { if ( this.running ) { var newTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + ? self.performance.now() + : Date.now(); diff = 0.001 * ( newTime - this.oldTime ); this.oldTime = newTime; @@ -6659,6 +7190,8 @@ THREE.Clock.prototype = { }; +// File:src/core/EventDispatcher.js + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -6719,53 +7252,56 @@ THREE.EventDispatcher.prototype = { if ( this._listeners === undefined ) return; var listeners = this._listeners; - var index = listeners[ type ].indexOf( listener ); + var listenerArray = listeners[ type ]; - if ( index !== - 1 ) { + if ( listenerArray !== undefined ) { - listeners[ type ].splice( index, 1 ); + var index = listenerArray.indexOf( listener ); - } + if ( index !== - 1 ) { - }, + listenerArray.splice( index, 1 ); - dispatchEvent: function () { + } - var array = []; + } - return function ( event ) { + }, - if ( this._listeners === undefined ) return; + dispatchEvent: function ( event ) { - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; + if ( this._listeners === undefined ) return; - if ( listenerArray !== undefined ) { + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; - event.target = this; + if ( listenerArray !== undefined ) { - var length = listenerArray.length; + event.target = this; - for ( var i = 0; i < length; i ++ ) { + var array = []; + var length = listenerArray.length; - array[ i ] = listenerArray[ i ]; + for ( var i = 0; i < length; i ++ ) { - } + array[ i ] = listenerArray[ i ]; - for ( var i = 0; i < length; i ++ ) { + } - array[ i ].call( this, event ); + for ( var i = 0; i < length; i ++ ) { - } + array[ i ].call( this, event ); } - }; + } - }() + } }; +// File:src/core/Raycaster.js + /** * @author mrdoob / http://mrdoob.com/ * @author bhouston / http://exocortex.com/ @@ -6782,15 +7318,15 @@ THREE.EventDispatcher.prototype = { this.near = near || 0; this.far = far || Infinity; - }; - - var sphere = new THREE.Sphere(); - var localRay = new THREE.Ray(); - var facePlane = new THREE.Plane(); - var intersectPoint = new THREE.Vector3(); - var matrixPosition = new THREE.Vector3(); + this.params = { + Sprite: {}, + Mesh: {}, + PointCloud: { threshold: 1 }, + LOD: {}, + Line: {} + }; - var inverseMatrix = new THREE.Matrix4(); + }; var descSort = function ( a, b ) { @@ -6798,506 +7334,229 @@ THREE.EventDispatcher.prototype = { }; - var vA = new THREE.Vector3(); - var vB = new THREE.Vector3(); - var vC = new THREE.Vector3(); + var intersectObject = function ( object, raycaster, intersects, recursive ) { - var intersectObject = function ( object, raycaster, intersects ) { + object.raycast( raycaster, intersects ); - if ( object instanceof THREE.Sprite ) { + if ( recursive === true ) { - matrixPosition.getPositionFromMatrix( object.matrixWorld ); - var distance = raycaster.ray.distanceToPoint( matrixPosition ); + var children = object.children; - if ( distance > object.scale.x ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - return intersects; + intersectObject( children[ i ], raycaster, intersects, true ); } - intersects.push( { - - distance: distance, - point: object.position, - face: null, - object: object - - } ); + } - } else if ( object instanceof THREE.LOD ) { + }; - matrixPosition.getPositionFromMatrix( object.matrixWorld ); - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + // - intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); + THREE.Raycaster.prototype = { - } else if ( object instanceof THREE.Mesh ) { + constructor: THREE.Raycaster, - var geometry = object.geometry; + precision: 0.0001, + linePrecision: 1, - // Checking boundingSphere distance to ray + set: function ( origin, direction ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + // direction is assumed to be normalized (for accurate distance calculations) - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); + this.ray.set( origin, direction ); - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + }, - return intersects; + setFromCamera: function ( coords, camera ) { - } + // camera is assumed _not_ to be a child of a transformed object - // Check boundingBox before continuing + if ( camera instanceof THREE.PerspectiveCamera ) { - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + this.ray.origin.copy( camera.position ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( camera.position ).normalize(); - if ( geometry.boundingBox !== null ) { + } else if ( camera instanceof THREE.OrthographicCamera ) { - if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { + this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - return intersects; + } else { - } + THREE.error( 'THREE.Raycaster: Unsupported camera type.' ); } - if ( geometry instanceof THREE.BufferGeometry ) { + }, - var material = object.material; + intersectObject: function ( object, recursive ) { - if ( material === undefined ) return intersects; - if ( geometry.dynamic === false ) return intersects; + var intersects = []; - var a, b, c; - var precision = raycaster.precision; + intersectObject( object, this, intersects, recursive ); - if ( geometry.attributes.index !== undefined ) { + intersects.sort( descSort ); - var offsets = geometry.offsets; - var indices = geometry.attributes.index.array; - var positions = geometry.attributes.position.array; - var offLength = geometry.offsets.length; + return intersects; - var fl = geometry.attributes.index.array.length / 3; + }, - for ( var oi = 0; oi < offLength; ++oi ) { + intersectObjects: function ( objects, recursive ) { - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; + var intersects = []; - for ( var i = start, il = start + count; i < il; i += 3 ) { + if ( objects instanceof Array === false ) { - a = index + indices[ i ]; - b = index + indices[ i + 1 ]; - c = index + indices[ i + 2 ]; + THREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); + } + for ( var i = 0, l = objects.length; i < l; i ++ ) { - if ( material.side === THREE.BackSide ) { + intersectObject( objects[ i ], this, intersects, recursive ); - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + } - } else { + intersects.sort( descSort ); - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + return intersects; - } + } - if ( intersectionPoint === null ) continue; + }; - intersectionPoint.applyMatrix4( object.matrixWorld ); +}( THREE ) ); - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); +// File:src/core/Object3D.js - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + */ - intersects.push( { +THREE.Object3D = function () { - distance: distance, - point: intersectionPoint, - face: null, - faceIndex: null, - object: object + Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } ); - } ); + this.uuid = THREE.Math.generateUUID(); - } + this.name = ''; + this.type = 'Object3D'; - } + this.parent = undefined; + this.children = []; - } else { + this.up = THREE.Object3D.DefaultUp.clone(); - var offsets = geometry.offsets; - var positions = geometry.attributes.position.array; - var offLength = geometry.offsets.length; + var position = new THREE.Vector3(); + var rotation = new THREE.Euler(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3( 1, 1, 1 ); - var fl = geometry.attributes.position.array.length; + var onRotationChange = function () { + quaternion.setFromEuler( rotation, false ); + }; - for ( var i = 0; i < fl; i += 3 ) { + var onQuaternionChange = function () { + rotation.setFromQuaternion( quaternion, undefined, false ); + }; - a = i; - b = i + 1; - c = i + 2; + rotation.onChange( onRotationChange ); + quaternion.onChange( onQuaternionChange ); - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); + Object.defineProperties( this, { + position: { + enumerable: true, + value: position + }, + rotation: { + enumerable: true, + value: rotation + }, + quaternion: { + enumerable: true, + value: quaternion + }, + scale: { + enumerable: true, + value: scale + } + } ); + this.rotationAutoUpdate = true; - if ( material.side === THREE.BackSide ) { + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + this.matrixAutoUpdate = true; + this.matrixWorldNeedsUpdate = false; - } else { + this.visible = true; - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + this.castShadow = false; + this.receiveShadow = false; - } + this.frustumCulled = true; + this.renderOrder = 0; - if ( intersectionPoint === null ) continue; + this.userData = {}; - intersectionPoint.applyMatrix4( object.matrixWorld ); +}; - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); +THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 ); - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; +THREE.Object3D.prototype = { - intersects.push( { + constructor: THREE.Object3D, - distance: distance, - point: intersectionPoint, - face: null, - faceIndex: null, - object: object + get eulerOrder () { - } ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - } + return this.rotation.order; - } + }, - } else if ( geometry instanceof THREE.Geometry ) { + set eulerOrder ( value ) { - var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - var objectMaterials = isFaceMaterial === true ? object.material.materials : null; + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - var a, b, c, d; - var precision = raycaster.precision; + this.rotation.order = value; - var vertices = geometry.vertices; + }, - for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + get useQuaternion () { - var face = geometry.faces[ f ]; + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; + }, - if ( material === undefined ) continue; + set useQuaternion ( value ) { - a = vertices[ face.a ]; - b = vertices[ face.b ]; - c = vertices[ face.c ]; + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - if ( material.side === THREE.BackSide ) { + }, - var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); + applyMatrix: function ( matrix ) { - } else { + this.matrix.multiplyMatrices( matrix, this.matrix ); - var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); + this.matrix.decompose( this.position, this.quaternion, this.scale ); - } + }, - if ( intersectionPoint === null ) continue; + setRotationFromAxisAngle: function ( axis, angle ) { - intersectionPoint.applyMatrix4( object.matrixWorld ); + // assumes axis is normalized - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + this.quaternion.setFromAxisAngle( axis, angle ); - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - face: face, - faceIndex: f, - object: object - - } ); - - } - - } - - } else if ( object instanceof THREE.Line ) { - - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - // Checking boundingSphere distance to ray - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - - return intersects; - - } - - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - /* if ( geometry instanceof THREE.BufferGeometry ) { - - } else */ if ( geometry instanceof THREE.Geometry ) { - - var vertices = geometry.vertices; - var nbVertices = vertices.length; - var interSegment = new THREE.Vector3(); - var interRay = new THREE.Vector3(); - var step = object.type === THREE.LineStrip ? 1 : 2; - - for ( var i = 0; i < nbVertices - 1; i = i + step ) { - - var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - - if ( distSq > precisionSq ) continue; - - var distance = localRay.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( object.matrixWorld ), - face: null, - faceIndex: null, - object: object - - } ); - - } - - } - - } - - }; - - var intersectDescendants = function ( object, raycaster, intersects ) { - - var descendants = object.getDescendants(); - - for ( var i = 0, l = descendants.length; i < l; i ++ ) { - - intersectObject( descendants[ i ], raycaster, intersects ); - - } - }; - - // - - THREE.Raycaster.prototype.precision = 0.0001; - THREE.Raycaster.prototype.linePrecision = 1; - - THREE.Raycaster.prototype.set = function ( origin, direction ) { - - this.ray.set( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - }; - - THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { - - var intersects = []; - - if ( recursive === true ) { - - intersectDescendants( object, this, intersects ); - - } - - intersectObject( object, this, intersects ); - - intersects.sort( descSort ); - - return intersects; - - }; - - THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { - - var intersects = []; - - for ( var i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects ); - - if ( recursive === true ) { - - intersectDescendants( objects[ i ], this, intersects ); - - } - - } - - intersects.sort( descSort ); - - return intersects; - - }; - -}( THREE ) ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Object3D = function () { - - this.id = THREE.Object3DIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.parent = undefined; - this.children = []; - - this.up = new THREE.Vector3( 0, 1, 0 ); - - this.position = new THREE.Vector3(); - this.rotation = new THREE.Euler(); - this.quaternion = new THREE.Quaternion(); - this.scale = new THREE.Vector3( 1, 1, 1 ); - - // keep rotation and quaternion in sync - - this.rotation._quaternion = this.quaternion; - this.quaternion._euler = this.rotation; - - this.renderDepth = null; - - this.rotationAutoUpdate = true; - - this.matrix = new THREE.Matrix4(); - this.matrixWorld = new THREE.Matrix4(); - - this.matrixAutoUpdate = true; - this.matrixWorldNeedsUpdate = true; - - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - - this.userData = {}; - -}; - - -THREE.Object3D.prototype = { - - constructor: THREE.Object3D, - - get eulerOrder () { - - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); - - return this.rotation.order; - - }, - - set eulerOrder ( value ) { - - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); - - this.rotation.order = value; - - }, - - get useQuaternion () { - - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - set useQuaternion ( value ) { - - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - applyMatrix: function () { - - var m1 = new THREE.Matrix4(); - - return function ( matrix ) { - - this.matrix.multiplyMatrices( matrix, this.matrix ); - - this.position.getPositionFromMatrix( this.matrix ); - - this.scale.getScaleFromMatrix( this.matrix ); - - m1.extractRotation( this.matrix ); - - this.quaternion.setFromRotationMatrix( m1 ); - - } - - }(), - - setRotationFromAxisAngle: function ( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - }, + }, setRotationFromEuler: function ( euler ) { @@ -7321,7 +7580,7 @@ THREE.Object3D.prototype = { }, - rotateOnAxis: function() { + rotateOnAxis: function () { // rotate object on axis in object space // axis is assumed to be normalized @@ -7385,9 +7644,7 @@ THREE.Object3D.prototype = { return function ( axis, distance ) { - v1.copy( axis ); - - v1.applyQuaternion( this.quaternion ); + v1.copy( axis ).applyQuaternion( this.quaternion ); this.position.add( v1.multiplyScalar( distance ) ); @@ -7399,7 +7656,7 @@ THREE.Object3D.prototype = { translate: function ( distance, axis ) { - console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); + THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); return this.translateOnAxis( axis, distance ); }, @@ -7476,10 +7733,22 @@ THREE.Object3D.prototype = { add: function ( object ) { + if ( arguments.length > 1 ) { + + for ( var i = 0; i < arguments.length; i ++ ) { + + this.add( arguments[ i ] ); + + } + + return this; + + }; + if ( object === this ) { - console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); - return; + THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; } @@ -7496,90 +7765,73 @@ THREE.Object3D.prototype = { this.children.push( object ); - // add to scene + } else { - var scene = this; + THREE.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - while ( scene.parent !== undefined ) { + } - scene = scene.parent; + return this; - } + }, - if ( scene !== undefined && scene instanceof THREE.Scene ) { + remove: function ( object ) { - scene.__addObject( object ); + if ( arguments.length > 1 ) { - } + for ( var i = 0; i < arguments.length; i ++ ) { - } + this.remove( arguments[ i ] ); - }, + } - remove: function ( object ) { + }; var index = this.children.indexOf( object ); if ( index !== - 1 ) { object.parent = undefined; + object.dispatchEvent( { type: 'removed' } ); this.children.splice( index, 1 ); - // remove from scene - - var scene = this; - - while ( scene.parent !== undefined ) { - - scene = scene.parent; - - } - - if ( scene !== undefined && scene instanceof THREE.Scene ) { - - scene.__removeObject( object ); - - } - } }, - traverse: function ( callback ) { + getChildByName: function ( name ) { - callback( this ); + THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + }, - this.children[ i ].traverse( callback ); + getObjectById: function ( id ) { - } + return this.getObjectByProperty( 'id', id ); }, - getObjectById: function ( id, recursive ) { - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; + getObjectByName: function ( name ) { - if ( child.id === id ) { + return this.getObjectByProperty( 'name', name ); - return child; + }, - } + getObjectByProperty: function ( name, value ) { - if ( recursive === true ) { + if ( this[ name ] === value ) return this; - child = child.getObjectById( id, recursive ); + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - if ( child !== undefined ) { + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); - return child; + if ( object !== undefined ) { - } + return object; } @@ -7589,56 +7841,123 @@ THREE.Object3D.prototype = { }, - getObjectByName: function ( name, recursive ) { + getWorldPosition: function ( optionalTarget ) { - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + var result = optionalTarget || new THREE.Vector3(); - var child = this.children[ i ]; + this.updateMatrixWorld( true ); - if ( child.name === name ) { + return result.setFromMatrixPosition( this.matrixWorld ); - return child; + }, - } + getWorldQuaternion: function () { - if ( recursive === true ) { + var position = new THREE.Vector3(); + var scale = new THREE.Vector3(); - child = child.getObjectByName( name, recursive ); + return function ( optionalTarget ) { - if ( child !== undefined ) { + var result = optionalTarget || new THREE.Quaternion(); - return child; + this.updateMatrixWorld( true ); - } + this.matrixWorld.decompose( position, result, scale ); - } + return result; } - return undefined; + }(), - }, + getWorldRotation: function () { - getChildByName: function ( name, recursive ) { + var quaternion = new THREE.Quaternion(); - console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name, recursive ); + return function ( optionalTarget ) { - }, + var result = optionalTarget || new THREE.Euler(); - getDescendants: function ( array ) { + this.getWorldQuaternion( quaternion ); - if ( array === undefined ) array = []; + return result.setFromQuaternion( quaternion, this.rotation.order, false ); - Array.prototype.push.apply( array, this.children ); + } + + }(), + + getWorldScale: function () { + + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); + + return function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + this.updateMatrixWorld( true ); + + this.matrixWorld.decompose( position, quaternion, result ); + + return result; + + } + + }(), + + getWorldDirection: function () { + + var quaternion = new THREE.Quaternion(); + + return function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + this.getWorldQuaternion( quaternion ); + + return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); + + } + + }(), + + raycast: function () {}, + + traverse: function ( callback ) { + + callback( this ); for ( var i = 0, l = this.children.length; i < l; i ++ ) { - this.children[ i ].getDescendants( array ); + this.children[ i ].traverse( callback ); } - return array; + }, + + traverseVisible: function ( callback ) { + + if ( this.visible === false ) return; + + callback( this ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].traverseVisible( callback ); + + } + + }, + + traverseAncestors: function ( callback ) { + + if ( this.parent ) { + + callback( this.parent ); + + this.parent.traverseAncestors( callback ); + + } }, @@ -7682,1123 +8001,1080 @@ THREE.Object3D.prototype = { }, - clone: function ( object, recursive ) { - - if ( object === undefined ) object = new THREE.Object3D(); - if ( recursive === undefined ) recursive = true; - - object.name = this.name; - - object.up.copy( this.up ); + toJSON: function () { - object.position.copy( this.position ); - object.quaternion.copy( this.quaternion ); - object.scale.copy( this.scale ); + var output = { + metadata: { + version: 4.3, + type: 'Object', + generator: 'ObjectExporter' + } + }; - object.renderDepth = this.renderDepth; + // - object.rotationAutoUpdate = this.rotationAutoUpdate; + var geometries = {}; - object.matrix.copy( this.matrix ); - object.matrixWorld.copy( this.matrixWorld ); + var parseGeometry = function ( geometry ) { - object.matrixAutoUpdate = this.matrixAutoUpdate; - object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + if ( output.geometries === undefined ) { - object.visible = this.visible; + output.geometries = []; - object.castShadow = this.castShadow; - object.receiveShadow = this.receiveShadow; + } - object.frustumCulled = this.frustumCulled; + if ( geometries[ geometry.uuid ] === undefined ) { - object.userData = JSON.parse( JSON.stringify( this.userData ) ); + var json = geometry.toJSON(); - if ( recursive === true ) { + delete json.metadata; - for ( var i = 0; i < this.children.length; i ++ ) { + geometries[ geometry.uuid ] = json; - var child = this.children[ i ]; - object.add( child.clone() ); + output.geometries.push( json ); } - } - - return object; - - } - -}; + return geometry.uuid; -THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); + }; -THREE.Object3DIdCount = 0; + // -/** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author julianwa / https://github.com/julianwa - */ + var materials = {}; -THREE.Projector = function () { + var parseMaterial = function ( material ) { - var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, - _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, - _face, _face3Count, _face3Pool = [], _face3PoolLength = 0, - _line, _lineCount, _linePool = [], _linePoolLength = 0, - _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + if ( output.materials === undefined ) { - _renderData = { objects: [], sprites: [], lights: [], elements: [] }, + output.materials = []; - _vector3 = new THREE.Vector3(), - _vector4 = new THREE.Vector4(), + } - _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), - _boundingBox = new THREE.Box3(), - _points3 = new Array( 3 ), - _points4 = new Array( 4 ), + if ( materials[ material.uuid ] === undefined ) { - _viewMatrix = new THREE.Matrix4(), - _viewProjectionMatrix = new THREE.Matrix4(), + var json = material.toJSON(); - _modelMatrix, - _modelViewProjectionMatrix = new THREE.Matrix4(), + delete json.metadata; - _normalMatrix = new THREE.Matrix3(), - _normalViewMatrix = new THREE.Matrix3(), + materials[ material.uuid ] = json; - _centroid = new THREE.Vector3(), + output.materials.push( json ); - _frustum = new THREE.Frustum(), + } - _clippedVertex1PositionScreen = new THREE.Vector4(), - _clippedVertex2PositionScreen = new THREE.Vector4(); + return material.uuid; - this.projectVector = function ( vector, camera ) { + }; - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + // - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + var parseObject = function ( object ) { - return vector.applyProjection( _viewProjectionMatrix ); + var data = {}; - }; + data.uuid = object.uuid; + data.type = object.type; - this.unprojectVector = function ( vector, camera ) { + if ( object.name !== '' ) data.name = object.name; + if ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData; + if ( object.visible !== true ) data.visible = object.visible; - camera.projectionMatrixInverse.getInverse( camera.projectionMatrix ); + if ( object instanceof THREE.PerspectiveCamera ) { - _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, camera.projectionMatrixInverse ); + data.fov = object.fov; + data.aspect = object.aspect; + data.near = object.near; + data.far = object.far; - return vector.applyProjection( _viewProjectionMatrix ); + } else if ( object instanceof THREE.OrthographicCamera ) { - }; + data.left = object.left; + data.right = object.right; + data.top = object.top; + data.bottom = object.bottom; + data.near = object.near; + data.far = object.far; - this.pickingRay = function ( vector, camera ) { + } else if ( object instanceof THREE.AmbientLight ) { - // set two vectors with opposing z values - vector.z = -1.0; - var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); + data.color = object.color.getHex(); - this.unprojectVector( vector, camera ); - this.unprojectVector( end, camera ); + } else if ( object instanceof THREE.DirectionalLight ) { - // find direction from vector to end - end.sub( vector ).normalize(); + data.color = object.color.getHex(); + data.intensity = object.intensity; - return new THREE.Raycaster( vector, end ); + } else if ( object instanceof THREE.PointLight ) { - }; + data.color = object.color.getHex(); + data.intensity = object.intensity; + data.distance = object.distance; + data.decay = object.decay; - var getObject = function ( object ) { + } else if ( object instanceof THREE.SpotLight ) { - _object = getNextObjectInPool(); - _object.id = object.id; - _object.object = object; + data.color = object.color.getHex(); + data.intensity = object.intensity; + data.distance = object.distance; + data.angle = object.angle; + data.exponent = object.exponent; + data.decay = object.decay; - if ( object.renderDepth !== null ) { + } else if ( object instanceof THREE.HemisphereLight ) { - _object.z = object.renderDepth; + data.color = object.color.getHex(); + data.groundColor = object.groundColor.getHex(); - } else { + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { - _vector3.getPositionFromMatrix( object.matrixWorld ); - _vector3.applyProjection( _viewProjectionMatrix ); - _object.z = _vector3.z; + data.geometry = parseGeometry( object.geometry ); + data.material = parseMaterial( object.material ); - } + if ( object instanceof THREE.Line ) data.mode = object.mode; - return _object; + } else if ( object instanceof THREE.Sprite ) { - }; + data.material = parseMaterial( object.material ); - var projectObject = function ( object ) { + } - if ( object.visible === false ) return; + data.matrix = object.matrix.toArray(); - if ( object instanceof THREE.Light ) { + if ( object.children.length > 0 ) { - _renderData.lights.push( object ); + data.children = []; - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) { + for ( var i = 0; i < object.children.length; i ++ ) { - if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + data.children.push( parseObject( object.children[ i ] ) ); - _renderData.objects.push( getObject( object ) ); + } } - } else if ( object instanceof THREE.Sprite ) { - - _renderData.sprites.push( getObject( object ) ); + return data; } - for ( var i = 0, l = object.children.length; i < l; i ++ ) { + output.object = parseObject( this ); - projectObject( object.children[ i ] ); + return output; - } + }, - }; + clone: function ( object, recursive ) { - var projectGraph = function ( root, sortObjects ) { + if ( object === undefined ) object = new THREE.Object3D(); + if ( recursive === undefined ) recursive = true; - _objectCount = 0; + object.name = this.name; - _renderData.objects.length = 0; - _renderData.sprites.length = 0; - _renderData.lights.length = 0; + object.up.copy( this.up ); - projectObject( root ); + object.position.copy( this.position ); + object.quaternion.copy( this.quaternion ); + object.scale.copy( this.scale ); - if ( sortObjects === true ) { + object.rotationAutoUpdate = this.rotationAutoUpdate; - _renderData.objects.sort( painterSort ); + object.matrix.copy( this.matrix ); + object.matrixWorld.copy( this.matrixWorld ); - } + object.matrixAutoUpdate = this.matrixAutoUpdate; + object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; - }; + object.visible = this.visible; - this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + object.castShadow = this.castShadow; + object.receiveShadow = this.receiveShadow; - var visible = false, - o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object, - geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs, - v1, v2, v3, v4, isFaceMaterial, objectMaterials; + object.frustumCulled = this.frustumCulled; - _face3Count = 0; - _lineCount = 0; - _spriteCount = 0; + object.userData = JSON.parse( JSON.stringify( this.userData ) ); - _renderData.elements.length = 0; + if ( recursive === true ) { - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - if ( camera.parent === undefined ) camera.updateMatrixWorld(); + for ( var i = 0; i < this.children.length; i ++ ) { - _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); + var child = this.children[ i ]; + object.add( child.clone() ); - _normalViewMatrix.getNormalMatrix( _viewMatrix ); + } - _frustum.setFromMatrix( _viewProjectionMatrix ); + } - projectGraph( scene, sortObjects ); + return object; - for ( o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + } - object = _renderData.objects[ o ].object; +}; - _modelMatrix = object.matrixWorld; +THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); - _vertexCount = 0; +THREE.Object3DIdCount = 0; - if ( object instanceof THREE.Mesh ) { +// File:src/core/Face3.js - geometry = object.geometry; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - vertices = geometry.vertices; - faces = geometry.faces; - faceVertexUvs = geometry.faceVertexUvs; +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { - _normalMatrix.getNormalMatrix( _modelMatrix ); + this.a = a; + this.b = b; + this.c = c; - isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - objectMaterials = isFaceMaterial === true ? object.material : null; + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : []; - for ( v = 0, vl = vertices.length; v < vl; v ++ ) { + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; - _vertex = getNextVertexInPool(); + this.vertexTangents = []; - _vertex.positionWorld.copy( vertices[ v ] ).applyMatrix4( _modelMatrix ); - _vertex.positionScreen.copy( _vertex.positionWorld ).applyMatrix4( _viewProjectionMatrix ); + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - var invW = 1 / _vertex.positionScreen.w; +}; - _vertex.positionScreen.x *= invW; - _vertex.positionScreen.y *= invW; - _vertex.positionScreen.z *= invW; +THREE.Face3.prototype = { - _vertex.visible = ! ( _vertex.positionScreen.x < -1 || _vertex.positionScreen.x > 1 || - _vertex.positionScreen.y < -1 || _vertex.positionScreen.y > 1 || - _vertex.positionScreen.z < -1 || _vertex.positionScreen.z > 1 ); + constructor: THREE.Face3, - } + clone: function () { - for ( f = 0, fl = faces.length; f < fl; f ++ ) { + var face = new THREE.Face3( this.a, this.b, this.c ); - face = faces[ f ]; + face.normal.copy( this.normal ); + face.color.copy( this.color ); - var material = isFaceMaterial === true - ? objectMaterials.materials[ face.materialIndex ] - : object.material; + face.materialIndex = this.materialIndex; - if ( material === undefined ) continue; + for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) { - var side = material.side; + face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - v1 = _vertexPool[ face.a ]; - v2 = _vertexPool[ face.b ]; - v3 = _vertexPool[ face.c ]; + } - _points3[ 0 ] = v1.positionScreen; - _points3[ 1 ] = v2.positionScreen; - _points3[ 2 ] = v3.positionScreen; + for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) { - if ( v1.visible === true || v2.visible === true || v3.visible === true || - _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) { + face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * - ( v2.positionScreen.y - v1.positionScreen.y ) - - ( v3.positionScreen.y - v1.positionScreen.y ) * - ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; + } - if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) { + for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) { - _face = getNextFace3InPool(); + face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); + } - } else { + return face; - continue; + } - } +}; - } else { +// File:src/core/Face4.js - continue; +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - _face.normalModel.copy( face.normal ); + THREE.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ) + return new THREE.Face3( a, b, c, normal, color, materialIndex ); - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { +}; - _face.normalModel.negate(); +// File:src/core/BufferAttribute.js - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); +THREE.BufferAttribute = function ( array, itemSize ) { - _face.normalModelView.copy( _face.normalModel ).applyMatrix3( _normalViewMatrix ); + this.array = array; + this.itemSize = itemSize; - _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix ); + this.needsUpdate = false; - faceVertexNormals = face.vertexNormals; +}; - for ( n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { +THREE.BufferAttribute.prototype = { - var normalModel = _face.vertexNormalsModel[ n ]; - normalModel.copy( faceVertexNormals[ n ] ); + constructor: THREE.BufferAttribute, - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + get length () { - normalModel.negate(); + return this.array.length; - } + }, - normalModel.applyMatrix3( _normalMatrix ).normalize(); + copyAt: function ( index1, attribute, index2 ) { - var normalModelView = _face.vertexNormalsModelView[ n ]; - normalModelView.copy( normalModel ).applyMatrix3( _normalViewMatrix ); + index1 *= this.itemSize; + index2 *= attribute.itemSize; - } + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - _face.vertexNormalsLength = faceVertexNormals.length; + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - for ( c = 0, cl = Math.min( faceVertexUvs.length, 3 ); c < cl; c ++ ) { + } - uvs = faceVertexUvs[ c ][ f ]; + return this; - if ( uvs === undefined ) continue; + }, - for ( u = 0, ul = uvs.length; u < ul; u ++ ) { + set: function ( value, offset ) { - _face.uvs[ c ][ u ] = uvs[ u ]; + if ( offset === undefined ) offset = 0; - } + this.array.set( value, offset ); - } + return this; - _face.color = face.color; - _face.material = material; + }, - _centroid.copy( _face.centroidModel ).applyProjection( _viewProjectionMatrix ); + setX: function ( index, x ) { - _face.z = _centroid.z; + this.array[ index * this.itemSize ] = x; - _renderData.elements.push( _face ); + return this; - } + }, - } else if ( object instanceof THREE.Line ) { + setY: function ( index, y ) { - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + this.array[ index * this.itemSize + 1 ] = y; - vertices = object.geometry.vertices; + return this; - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + }, - // Handle LineStrip and LinePieces - var step = object.type === THREE.LinePieces ? 2 : 1; + setZ: function ( index, z ) { - for ( v = 1, vl = vertices.length; v < vl; v ++ ) { + this.array[ index * this.itemSize + 2 ] = z; - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + return this; - if ( ( v + 1 ) % step > 0 ) continue; + }, - v2 = _vertexPool[ _vertexCount - 2 ]; + setXY: function ( index, x, y ) { - _clippedVertex1PositionScreen.copy( v1.positionScreen ); - _clippedVertex2PositionScreen.copy( v2.positionScreen ); + index *= this.itemSize; - if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + this.array[ index ] = x; + this.array[ index + 1 ] = y; - // Perform the perspective divide - _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); - _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + return this; - _line = getNextLineInPool(); + }, - _line.id = object.id; - _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); - _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + setXYZ: function ( index, x, y, z ) { - _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + index *= this.itemSize; - _line.material = object.material; + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; - if ( object.material.vertexColors === THREE.VertexColors ) { + return this; - _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); - _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); + }, - } + setXYZW: function ( index, x, y, z, w ) { - _renderData.elements.push( _line ); + index *= this.itemSize; - } + this.array[ index ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; - } + return this; - } + }, - } + clone: function () { - for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) { + return new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - object = _renderData.sprites[ o ].object; + } - _modelMatrix = object.matrixWorld; +}; - if ( object instanceof THREE.Sprite ) { +// - _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); - _vector4.applyMatrix4( _viewProjectionMatrix ); +THREE.Int8Attribute = function ( data, itemSize ) { - var invW = 1 / _vector4.w; + THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - _vector4.z *= invW; +}; - if ( _vector4.z > -1 && _vector4.z < 1 ) { +THREE.Uint8Attribute = function ( data, itemSize ) { - _sprite = getNextSpriteInPool(); - _sprite.id = object.id; - _sprite.x = _vector4.x * invW; - _sprite.y = _vector4.y * invW; - _sprite.z = _vector4.z; - _sprite.object = object; + THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - _sprite.rotation = object.rotation; +}; - _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); - _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); +THREE.Uint8ClampedAttribute = function ( data, itemSize ) { - _sprite.material = object.material; + THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - _renderData.elements.push( _sprite ); - } +}; - } +THREE.Int16Attribute = function ( data, itemSize ) { - } + THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - if ( sortElements === true ) _renderData.elements.sort( painterSort ); +}; - return _renderData; +THREE.Uint16Attribute = function ( data, itemSize ) { - }; + THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - // Pools +}; - function getNextObjectInPool() { +THREE.Int32Attribute = function ( data, itemSize ) { - if ( _objectCount === _objectPoolLength ) { + THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var object = new THREE.RenderableObject(); - _objectPool.push( object ); - _objectPoolLength ++; - _objectCount ++; - return object; +}; - } +THREE.Uint32Attribute = function ( data, itemSize ) { - return _objectPool[ _objectCount ++ ]; + THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - } +}; - function getNextVertexInPool() { +THREE.Float32Attribute = function ( data, itemSize ) { - if ( _vertexCount === _vertexPoolLength ) { + THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - var vertex = new THREE.RenderableVertex(); - _vertexPool.push( vertex ); - _vertexPoolLength ++; - _vertexCount ++; - return vertex; +}; - } +THREE.Float64Attribute = function ( data, itemSize ) { - return _vertexPool[ _vertexCount ++ ]; + THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + return new THREE.BufferAttribute( data, itemSize ); - } +}; - function getNextFace3InPool() { +// File:src/core/DynamicBufferAttribute.js - if ( _face3Count === _face3PoolLength ) { +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author mrdoob / http://mrdoob.com/ + */ - var face = new THREE.RenderableFace3(); - _face3Pool.push( face ); - _face3PoolLength ++; - _face3Count ++; - return face; +THREE.DynamicBufferAttribute = function ( array, itemSize ) { - } + THREE.BufferAttribute.call( this, array, itemSize ); - return _face3Pool[ _face3Count ++ ]; + this.updateRange = { offset: 0, count: -1 }; +}; - } +THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); +THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; - function getNextLineInPool() { +THREE.DynamicBufferAttribute.prototype.clone = function () { - if ( _lineCount === _linePoolLength ) { + return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize ); - var line = new THREE.RenderableLine(); - _linePool.push( line ); - _linePoolLength ++; - _lineCount ++ - return line; +}; - } +// File:src/core/BufferGeometry.js - return _linePool[ _lineCount ++ ]; +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.BufferGeometry = function () { - function getNextSpriteInPool() { + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - if ( _spriteCount === _spritePoolLength ) { + this.uuid = THREE.Math.generateUUID(); - var sprite = new THREE.RenderableSprite(); - _spritePool.push( sprite ); - _spritePoolLength ++; - _spriteCount ++ - return sprite; + this.name = ''; + this.type = 'BufferGeometry'; - } + this.attributes = {}; + this.attributesKeys = []; - return _spritePool[ _spriteCount ++ ]; + this.drawcalls = []; + this.offsets = this.drawcalls; // backwards compatibility - } + this.boundingBox = null; + this.boundingSphere = null; - // +}; - function painterSort( a, b ) { +THREE.BufferGeometry.prototype = { - if ( a.z !== b.z ) { + constructor: THREE.BufferGeometry, - return b.z - a.z; + addAttribute: function ( name, attribute ) { - } else if ( a.id !== b.id ) { + if ( attribute instanceof THREE.BufferAttribute === false ) { - return a.id - b.id; + THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - } else { + this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; - return 0; + return; } - } - - function clipLine( s1, s2 ) { - - var alpha1 = 0, alpha2 = 1, - - // Calculate the boundary coordinate of each vertex for the near and far clip planes, - // Z = -1 and Z = +1, respectively. - bc1near = s1.z + s1.w, - bc2near = s2.z + s2.w, - bc1far = - s1.z + s1.w, - bc2far = - s2.z + s2.w; + this.attributes[ name ] = attribute; + this.attributesKeys = Object.keys( this.attributes ); - if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { - - // Both vertices lie entirely within all clip planes. - return true; + }, - } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { + getAttribute: function ( name ) { - // Both vertices lie entirely outside one of the clip planes. - return false; + return this.attributes[ name ]; - } else { + }, - // The line segment spans at least one clip plane. + addDrawCall: function ( start, count, indexOffset ) { - if ( bc1near < 0 ) { + this.drawcalls.push( { - // v1 lies outside the near plane, v2 inside - alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + start: start, + count: count, + index: indexOffset !== undefined ? indexOffset : 0 - } else if ( bc2near < 0 ) { + } ); - // v2 lies outside the near plane, v1 inside - alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + }, - } + applyMatrix: function ( matrix ) { - if ( bc1far < 0 ) { + var position = this.attributes.position; - // v1 lies outside the far plane, v2 inside - alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + if ( position !== undefined ) { - } else if ( bc2far < 0 ) { + matrix.applyToVector3Array( position.array ); + position.needsUpdate = true; - // v2 lies outside the far plane, v2 inside - alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + } - } + var normal = this.attributes.normal; - if ( alpha2 < alpha1 ) { + if ( normal !== undefined ) { - // The line segment spans two boundaries, but is outside both of them. - // (This can't happen when we're only clipping against just near/far but good - // to leave the check here for future usage if other clip planes are added.) - return false; + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - } else { + normalMatrix.applyToVector3Array( normal.array ); + normal.needsUpdate = true; - // Update the s1 and s2 vertices to match the clipped line segment. - s1.lerp( s2, alpha1 ); - s2.lerp( s1, 1 - alpha2 ); + } - return true; + if ( this.boundingBox !== null ) { - } + this.computeBoundingBox(); } - } + if ( this.boundingSphere !== null ) { -}; + this.computeBoundingSphere(); -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { + }, - this.a = a; - this.b = b; - this.c = c; + center: function () { - this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); - this.vertexNormals = normal instanceof Array ? normal : [ ]; + this.computeBoundingBox(); - this.color = color instanceof THREE.Color ? color : new THREE.Color(); - this.vertexColors = color instanceof Array ? color : []; + var offset = this.boundingBox.center().negate(); - this.vertexTangents = []; + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + return offset; - this.centroid = new THREE.Vector3(); + }, -}; + fromGeometry: function ( geometry, settings ) { -THREE.Face3.prototype = { + settings = settings || { 'vertexColors': THREE.NoColors }; - constructor: THREE.Face3, + var vertices = geometry.vertices; + var faces = geometry.faces; + var faceVertexUvs = geometry.faceVertexUvs; + var vertexColors = settings.vertexColors; + var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3; - clone: function () { + var positions = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); - var face = new THREE.Face3( this.a, this.b, this.c ); + var normals = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); - face.normal.copy( this.normal ); - face.color.copy( this.color ); - face.centroid.copy( this.centroid ); + if ( vertexColors !== THREE.NoColors ) { - face.materialIndex = this.materialIndex; + var colors = new Float32Array( faces.length * 3 * 3 ); + this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - var i, il; - for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + } - return face; + if ( hasFaceVertexUv === true ) { - } + var uvs = new Float32Array( faces.length * 3 * 2 ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); -}; + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) { -THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { + var face = faces[ i ]; - console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') + var a = vertices[ face.a ]; + var b = vertices[ face.b ]; + var c = vertices[ face.c ]; - return new THREE.Face3( a, b, c, normal, color, materialIndex ); + positions[ i3 ] = a.x; + positions[ i3 + 1 ] = a.y; + positions[ i3 + 2 ] = a.z; -}; + positions[ i3 + 3 ] = b.x; + positions[ i3 + 4 ] = b.y; + positions[ i3 + 5 ] = b.z; -/** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author bhouston / http://exocortex.com - */ + positions[ i3 + 6 ] = c.x; + positions[ i3 + 7 ] = c.y; + positions[ i3 + 8 ] = c.z; -THREE.Geometry = function () { + if ( hasFaceVertexNormals === true ) { - this.id = THREE.GeometryIdCount ++; - this.uuid = THREE.Math.generateUUID(); + var na = face.vertexNormals[ 0 ]; + var nb = face.vertexNormals[ 1 ]; + var nc = face.vertexNormals[ 2 ]; - this.name = ''; + normals[ i3 ] = na.x; + normals[ i3 + 1 ] = na.y; + normals[ i3 + 2 ] = na.z; - this.vertices = []; - this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line + normals[ i3 + 3 ] = nb.x; + normals[ i3 + 4 ] = nb.y; + normals[ i3 + 5 ] = nb.z; - this.faces = []; + normals[ i3 + 6 ] = nc.x; + normals[ i3 + 7 ] = nc.y; + normals[ i3 + 8 ] = nc.z; - this.faceVertexUvs = [[]]; + } else { - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; + var n = face.normal; - this.skinWeights = []; - this.skinIndices = []; + normals[ i3 ] = n.x; + normals[ i3 + 1 ] = n.y; + normals[ i3 + 2 ] = n.z; - this.lineDistances = []; + normals[ i3 + 3 ] = n.x; + normals[ i3 + 4 ] = n.y; + normals[ i3 + 5 ] = n.z; - this.boundingBox = null; - this.boundingSphere = null; + normals[ i3 + 6 ] = n.x; + normals[ i3 + 7 ] = n.y; + normals[ i3 + 8 ] = n.z; - this.hasTangents = false; + } - this.dynamic = true; // the intermediate typed arrays will be deleted when set to false + if ( vertexColors === THREE.FaceColors ) { - // update flags + var fc = face.color; - this.verticesNeedUpdate = false; - this.elementsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.tangentsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; + colors[ i3 ] = fc.r; + colors[ i3 + 1 ] = fc.g; + colors[ i3 + 2 ] = fc.b; - this.buffersNeedUpdate = false; + colors[ i3 + 3 ] = fc.r; + colors[ i3 + 4 ] = fc.g; + colors[ i3 + 5 ] = fc.b; -}; + colors[ i3 + 6 ] = fc.r; + colors[ i3 + 7 ] = fc.g; + colors[ i3 + 8 ] = fc.b; -THREE.Geometry.prototype = { + } else if ( vertexColors === THREE.VertexColors ) { - constructor: THREE.Geometry, + var vca = face.vertexColors[ 0 ]; + var vcb = face.vertexColors[ 1 ]; + var vcc = face.vertexColors[ 2 ]; - applyMatrix: function ( matrix ) { + colors[ i3 ] = vca.r; + colors[ i3 + 1 ] = vca.g; + colors[ i3 + 2 ] = vca.b; - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + colors[ i3 + 3 ] = vcb.r; + colors[ i3 + 4 ] = vcb.g; + colors[ i3 + 5 ] = vcb.b; - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + colors[ i3 + 6 ] = vcc.r; + colors[ i3 + 7 ] = vcc.g; + colors[ i3 + 8 ] = vcc.b; - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); + } - } + if ( hasFaceVertexUv === true ) { - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + var uva = faceVertexUvs[ 0 ][ i ][ 0 ]; + var uvb = faceVertexUvs[ 0 ][ i ][ 1 ]; + var uvc = faceVertexUvs[ 0 ][ i ][ 2 ]; - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); + uvs[ i2 ] = uva.x; + uvs[ i2 + 1 ] = uva.y; - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + uvs[ i2 + 2 ] = uvb.x; + uvs[ i2 + 3 ] = uvb.y; - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + uvs[ i2 + 4 ] = uvc.x; + uvs[ i2 + 5 ] = uvc.y; } - face.centroid.applyMatrix4( matrix ); - } - if ( this.boundingBox instanceof THREE.Box3 ) { + this.computeBoundingSphere() - this.computeBoundingBox(); + return this; - } + }, - if ( this.boundingSphere instanceof THREE.Sphere ) { + computeBoundingBox: function () { - this.computeBoundingSphere(); + var vector = new THREE.Vector3(); - } + return function () { - }, + if ( this.boundingBox === null ) { - computeCentroids: function () { + this.boundingBox = new THREE.Box3(); - var f, fl, face; + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var positions = this.attributes.position.array; - face = this.faces[ f ]; - face.centroid.set( 0, 0, 0 ); + if ( positions ) { - face.centroid.add( this.vertices[ face.a ] ); - face.centroid.add( this.vertices[ face.b ] ); - face.centroid.add( this.vertices[ face.c ] ); - face.centroid.divideScalar( 3 ); + var bb = this.boundingBox; + bb.makeEmpty(); - } + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - }, + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + bb.expandByPoint( vector ); - computeFaceNormals: function () { + } - var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + } - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + if ( positions === undefined || positions.length === 0 ) { - var face = this.faces[ f ]; + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; + } - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - cb.normalize(); + THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); - face.normal.copy( cb ); + } } - }, - - computeVertexNormals: function ( areaWeighted ) { - - var v, vl, f, fl, face, vertices; + }(), - // create internal buffers for reuse when calling this method repeatedly - // (otherwise memory allocation / deallocation every frame is big resource hog) + computeBoundingSphere: function () { - if ( this.__tmpVertices === undefined ) { + var box = new THREE.Box3(); + var vector = new THREE.Vector3(); - this.__tmpVertices = new Array( this.vertices.length ); - vertices = this.__tmpVertices; + return function () { - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + if ( this.boundingSphere === null ) { - vertices[ v ] = new THREE.Vector3(); + this.boundingSphere = new THREE.Sphere(); } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var positions = this.attributes.position.array; - face = this.faces[ f ]; - face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + if ( positions ) { - } + box.makeEmpty(); - } else { + var center = this.boundingSphere.center; - vertices = this.__tmpVertices; + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + box.expandByPoint( vector ); - vertices[ v ].set( 0, 0, 0 ); + } - } + box.center( center ); - } + // hoping to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - if ( areaWeighted ) { + var maxRadiusSq = 0; - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - var vA, vB, vC, vD; - var cb = new THREE.Vector3(), ab = new THREE.Vector3(), - db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } - face = this.faces[ f ]; + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; + if ( isNaN( this.boundingSphere.radius ) ) { - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); + } } - } else { + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + }(), - face = this.faces[ f ]; + computeFaceNormals: function () { - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); + // backwards compatibility - } + }, - } + computeVertexNormals: function () { - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + var attributes = this.attributes; - vertices[ v ].normalize(); + if ( attributes.position ) { - } + var positions = attributes.position.array; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + if ( attributes.normal === undefined ) { - face = this.faces[ f ]; + this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) ); - face.vertexNormals[ 0 ].copy( vertices[ face.a ] ); - face.vertexNormals[ 1 ].copy( vertices[ face.b ] ); - face.vertexNormals[ 2 ].copy( vertices[ face.c ] ); + } else { - } + // reset existing normals to zero - }, + var normals = attributes.normal.array; - computeMorphNormals: function () { + for ( var i = 0, il = normals.length; i < il; i ++ ) { - var i, il, f, fl, face; + normals[ i ] = 0; - // save original normals - // - create temp variables on first access - // otherwise just copy (for faster repeated calls) + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } - face = this.faces[ f ]; + var normals = attributes.normal.array; - if ( ! face.__originalFaceNormal ) { + var vA, vB, vC, - face.__originalFaceNormal = face.normal.clone(); + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), - } else { + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); - face.__originalFaceNormal.copy( face.normal ); + // indexed elements - } + if ( attributes.index ) { - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + var indices = attributes.index.array; - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] ); - if ( ! face.__originalVertexNormals[ i ] ) { + for ( var j = 0, jl = offsets.length; j < jl; ++ j ) { - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; - } else { + for ( var i = start, il = start + count; i < il; i += 3 ) { - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + vA = ( index + indices[ i ] ) * 3; + vB = ( index + indices[ i + 1 ] ) * 3; + vC = ( index + indices[ i + 2 ] ) * 3; - } + pA.fromArray( positions, vA ); + pB.fromArray( positions, vB ); + pC.fromArray( positions, vC ); - } + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - } + normals[ vA ] += cb.x; + normals[ vA + 1 ] += cb.y; + normals[ vA + 2 ] += cb.z; - // use temp geometry to compute face and vertex normals for each morph + normals[ vB ] += cb.x; + normals[ vB + 1 ] += cb.y; + normals[ vB + 2 ] += cb.z; - var tmpGeo = new THREE.Geometry(); - tmpGeo.faces = this.faces; + normals[ vC ] += cb.x; + normals[ vC + 1 ] += cb.y; + normals[ vC + 2 ] += cb.z; - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + } - // create on first access + } - if ( ! this.morphNormals[ i ] ) { + } else { - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; + // non-indexed elements (unconnected triangle soup) - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + for ( var i = 0, il = positions.length; i < il; i += 9 ) { - var faceNormal, vertexNormals; + pA.fromArray( positions, i ); + pB.fromArray( positions, i + 3 ); + pC.fromArray( positions, i + 6 ); - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - face = this.faces[ f ]; + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; - faceNormal = new THREE.Vector3(); - vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; } } - var morphNormals = this.morphNormals[ i ]; + this.normalizeNormals(); - // set vertices to morph target + attributes.normal.needsUpdate = true; - tmpGeo.vertices = this.morphTargets[ i ].vertices; + } - // compute morph normals + }, - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); + computeTangents: function () { - // store morph normals + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) - var faceNormal, vertexNormals; + if ( this.attributes.index === undefined || + this.attributes.position === undefined || + this.attributes.normal === undefined || + this.attributes.uv === undefined ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + THREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); + return; - face = this.faces[ f ]; + } - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; + var indices = this.attributes.index.array; + var positions = this.attributes.position.array; + var normals = this.attributes.normal.array; + var uvs = this.attributes.uv.array; - faceNormal.copy( face.normal ); + var nVertices = positions.length / 3; - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + if ( this.attributes.tangent === undefined ) { - } + this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); } - // restore original normals + var tangents = this.attributes.tangent.array; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var tan1 = [], tan2 = []; - face = this.faces[ f ]; + for ( var k = 0; k < nVertices; k ++ ) { - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); } - }, - - computeTangents: function () { + var vA = new THREE.Vector3(), + vB = new THREE.Vector3(), + vC = new THREE.Vector3(), - // based on http://www.terathon.com/code/tangent.html - // tangents go to vertices + uvA = new THREE.Vector2(), + uvB = new THREE.Vector2(), + uvC = new THREE.Vector2(), - var f, fl, v, vl, i, il, vertexIndex, - face, uv, vA, vB, vC, uvA, uvB, uvC, x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r, t, test, - tan1 = [], tan2 = [], - sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), - tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), - n = new THREE.Vector3(), w; - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - tan1[ v ] = new THREE.Vector3(); - tan2[ v ] = new THREE.Vector3(); + s1, s2, t1, t2, r; - } + var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); - function handleTriangle( context, a, b, c, ua, ub, uc ) { + function handleTriangle( a, b, c ) { - vA = context.vertices[ a ]; - vB = context.vertices[ b ]; - vC = context.vertices[ c ]; + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - uvA = uv[ ua ]; - uvB = uv[ ub ]; - uvC = uv[ uc ]; + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); x1 = vB.x - vA.x; x2 = vC.x - vA.x; + y1 = vB.y - vA.y; y2 = vC.y - vA.y; + z1 = vB.z - vA.z; z2 = vC.z - vA.z; s1 = uvB.x - uvA.x; s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; t2 = uvC.y - uvA.y; r = 1.0 / ( s1 * t2 - s2 * t1 ); - sdir.set( ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r ); - tdir.set( ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); tan1[ a ].add( sdir ); tan1[ b ].add( sdir ); @@ -8810,218 +9086,369 @@ THREE.Geometry.prototype = { } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var i, il; + var j, jl; + var iA, iB, iC; - face = this.faces[ f ]; - uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents + if ( this.drawcalls.length === 0 ) { - handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); + this.addDrawCall( 0, indices.length, 0 ); } - var faceIndex = [ 'a', 'b', 'c', 'd' ]; + var drawcalls = this.drawcalls; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { - face = this.faces[ f ]; + var start = drawcalls[ j ].start; + var count = drawcalls[ j ].count; + var index = drawcalls[ j ].index; - for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { + for ( i = start, il = start + count; i < il; i += 3 ) { - n.copy( face.vertexNormals[ i ] ); + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; - vertexIndex = face[ faceIndex[ i ] ]; + handleTriangle( iA, iB, iC ); - t = tan1[ vertexIndex ]; + } - // Gram-Schmidt orthogonalize + } - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; - // Calculate handedness + function handleVertex( v ) { - tmp2.crossVectors( face.vertexNormals[ i ], t ); - test = tmp2.dot( tan2[ vertexIndex ] ); - w = (test < 0.0) ? -1.0 : 1.0; + n.fromArray( normals, v * 3 ); + n2.copy( n ); - face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); + t = tan1[ v ]; - } + // Gram-Schmidt orthogonalize - } + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - this.hasTangents = true; + // Calculate handedness - }, + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; - computeLineDistances: function ( ) { + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; - var d = 0; - var vertices = this.vertices; + } - for ( var i = 0, il = vertices.length; i < il; i ++ ) { + for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) { - if ( i > 0 ) { + var start = drawcalls[ j ].start; + var count = drawcalls[ j ].count; + var index = drawcalls[ j ].index; - d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); + for ( i = start, il = start + count; i < il; i += 3 ) { - } + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; - this.lineDistances[ i ] = d; + handleVertex( iA ); + handleVertex( iB ); + handleVertex( iC ); + + } } }, - computeBoundingBox: function () { + /* + Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. + This method will effectively rewrite the index buffer and remap all attributes to match the new indices. + WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. + size - Defaults to 65535, but allows for larger or smaller chunks. + */ + computeOffsets: function ( size ) { - if ( this.boundingBox === null ) { + if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit. - this.boundingBox = new THREE.Box3(); + var indices = this.attributes.index.array; + var vertices = this.attributes.position.array; - } + var facesCount = ( indices.length / 3 ); - this.boundingBox.setFromPoints( this.vertices ); + /* + console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); + console.log("Faces to process: "+(indices.length/3)); + console.log("Reordering "+verticesCount+" vertices."); + */ - }, + var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers + var indexPtr = 0; + var vertexPtr = 0; - computeBoundingSphere: function () { + var offsets = [ { start:0, count:0, index:0 } ]; + var offset = offsets[ 0 ]; - if ( this.boundingSphere === null ) { + var duplicatedVertices = 0; + var newVerticeMaps = 0; + var faceVertices = new Int32Array( 6 ); + var vertexMap = new Int32Array( vertices.length ); + var revVertexMap = new Int32Array( vertices.length ); + for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; } - this.boundingSphere = new THREE.Sphere(); + /* + Traverse every face and reorder vertices in the proper offsets of 65k. + We can have more than 65k entries in the index buffer per offset, but only reference 65k values. + */ + for ( var findex = 0; findex < facesCount; findex ++ ) { + newVerticeMaps = 0; + + for ( var vo = 0; vo < 3; vo ++ ) { + var vid = indices[ findex * 3 + vo ]; + if ( vertexMap[ vid ] == - 1 ) { + //Unmapped vertice + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = - 1; + newVerticeMaps ++; + } else if ( vertexMap[ vid ] < offset.index ) { + //Reused vertices from previous block (duplicate) + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = - 1; + duplicatedVertices ++; + } else { + //Reused vertice in the current block + faceVertices[ vo * 2 ] = vid; + faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ]; + } + } - } + var faceMax = vertexPtr + newVerticeMaps; + if ( faceMax > ( offset.index + size ) ) { + var new_offset = { start:indexPtr, count:0, index:vertexPtr }; + offsets.push( new_offset ); + offset = new_offset; - this.boundingSphere.setFromPoints( this.vertices ); + //Re-evaluate reused vertices in light of new offset. + for ( var v = 0; v < 6; v += 2 ) { + var new_vid = faceVertices[ v + 1 ]; + if ( new_vid > - 1 && new_vid < offset.index ) + faceVertices[ v + 1 ] = - 1; + } + } - }, + //Reindex the face. + for ( var v = 0; v < 6; v += 2 ) { + var vid = faceVertices[ v ]; + var new_vid = faceVertices[ v + 1 ]; - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ + if ( new_vid === - 1 ) + new_vid = vertexPtr ++; - mergeVertices: function () { + vertexMap[ vid ] = new_vid; + revVertexMap[ new_vid ] = vid; + sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit + offset.count ++; + } + } - var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) - var unique = [], changes = []; + /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ + this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr ); + this.offsets = offsets; // TODO: Deprecate + this.drawcalls = offsets; - var v, key; - var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 - var precision = Math.pow( 10, precisionPoints ); - var i,il, face; - var indices, k, j, jl, u; + /* + var orderTime = Date.now(); + console.log("Reorder time: "+(orderTime-s)+"ms"); + console.log("Duplicated "+duplicatedVertices+" vertices."); + console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); + console.log("Draw offsets: "+offsets.length); + */ - // reset cache of vertices as it now will be changing. - this.__tmpVertices = undefined; + return offsets; - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + }, - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + merge: function ( geometry, offset ) { - if ( verticesMap[ key ] === undefined ) { + if ( geometry instanceof THREE.BufferGeometry === false ) { - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; + THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; - } else { + } - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; + if ( offset === undefined ) offset = 0; - } + var attributes = this.attributes; - }; + for ( var key in attributes ) { + if ( geometry.attributes[ key ] === undefined ) continue; - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; - for( i = 0, il = this.faces.length; i < il; i ++ ) { + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; - face = this.faces[ i ]; + var attributeSize = attribute2.itemSize; - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; + for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { - indices = [ face.a, face.b, face.c ]; + attributeArray1[ j ] = attributeArray2[ i ]; - var dupIndex = -1; + } - // if any duplicate vertices are found in a Face3 - // we have to remove the face as nothing can be saved - for ( var n = 0; n < 3; n ++ ) { - if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { + } - dupIndex = n; - faceIndicesToRemove.push( i ); - break; + return this; - } - } + }, - } + normalizeNormals: function () { - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - var idx = faceIndicesToRemove[ i ]; + var normals = this.attributes.normal.array; - this.faces.splice( idx, 1 ); + var x, y, z, n; - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + for ( var i = 0, il = normals.length; i < il; i += 3 ) { - this.faceVertexUvs[ j ].splice( idx, 1 ); + x = normals[ i ]; + y = normals[ i + 1 ]; + z = normals[ i + 2 ]; - } + n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + + normals[ i ] *= n; + normals[ i + 1 ] *= n; + normals[ i + 2 ] *= n; } - // Use unique set of vertices + }, - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; + /* + reoderBuffers: + Reorder attributes based on a new indexBuffer and indexMap. + indexBuffer - Uint16Array of the new ordered indices. + indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. + vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). + */ + reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) { + + /* Create a copy of all attributes for reordering. */ + var sortedAttributes = {}; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + var sourceArray = this.attributes[ attr ].array; + sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount ); + } + + /* Move attribute positions based on the new index map */ + for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) { + var vid = indexMap[ new_vid ]; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + var attrArray = this.attributes[ attr ].array; + var attrSize = this.attributes[ attr ].itemSize; + var sortedAttr = sortedAttributes[ attr ]; + for ( var k = 0; k < attrSize; k ++ ) + sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; + } + } + /* Carry the new sorted buffers locally */ + this.attributes[ 'index' ].array = indexBuffer; + for ( var attr in this.attributes ) { + if ( attr == 'index' ) + continue; + this.attributes[ attr ].array = sortedAttributes[ attr ]; + this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount; + } }, - clone: function () { + toJSON: function () { - var geometry = new THREE.Geometry(); + var output = { + metadata: { + version: 4.0, + type: 'BufferGeometry', + generator: 'BufferGeometryExporter' + }, + uuid: this.uuid, + type: this.type, + data: { + attributes: {} + } + }; - var vertices = this.vertices; + var attributes = this.attributes; + var offsets = this.offsets; + var boundingSphere = this.boundingSphere; - for ( var i = 0, il = vertices.length; i < il; i ++ ) { + for ( var key in attributes ) { - geometry.vertices.push( vertices[ i ].clone() ); + var attribute = attributes[ key ]; + + var array = Array.prototype.slice.call( attribute.array ); + + output.data.attributes[ key ] = { + itemSize: attribute.itemSize, + type: attribute.array.constructor.name, + array: array + } } - var faces = this.faces; + if ( offsets.length > 0 ) { - for ( var i = 0, il = faces.length; i < il; i ++ ) { + output.data.offsets = JSON.parse( JSON.stringify( offsets ) ); - geometry.faces.push( faces[ i ].clone() ); + } + + if ( boundingSphere !== null ) { + + output.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + } } - var uvs = this.faceVertexUvs[ 0 ]; + return output; - for ( var i = 0, il = uvs.length; i < il; i ++ ) { + }, - var uv = uvs[ i ], uvCopy = []; + clone: function () { - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + var geometry = new THREE.BufferGeometry(); - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + for ( var attr in this.attributes ) { - } + var sourceAttr = this.attributes[ attr ]; + geometry.addAttribute( attr, sourceAttr.clone() ); - geometry.faceVertexUvs[ 0 ].push( uvCopy ); + } + + for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { + + var offset = this.offsets[ i ]; + + geometry.offsets.push( { + + start: offset.start, + index: offset.index, + count: offset.count + + } ); } @@ -9037,10467 +9464,8223 @@ THREE.Geometry.prototype = { }; -THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); +THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); -THREE.GeometryIdCount = 0; +// File:src/core/Geometry.js /** + * @author mrdoob / http://mrdoob.com/ + * @author kile / http://kile.stravaganza.org/ * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author bhouston / http://exocortex.com */ -THREE.BufferGeometry = function () { +THREE.Geometry = function () { + + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - this.id = THREE.GeometryIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; + this.type = 'Geometry'; - // attributes - - this.attributes = {}; + this.vertices = []; + this.colors = []; // one-to-one vertex colors, used in Points and Line - // attributes typed arrays are kept only if dynamic flag is set + this.faces = []; - this.dynamic = true; + this.faceVertexUvs = [ [] ]; - // offsets for chunks when using indexed elements + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; - this.offsets = []; + this.skinWeights = []; + this.skinIndices = []; - // boundings + this.lineDistances = []; this.boundingBox = null; this.boundingSphere = null; this.hasTangents = false; - // for compatibility - - this.morphTargets = []; - -}; - -THREE.BufferGeometry.prototype = { + this.dynamic = true; // the intermediate typed arrays will be deleted when set to false - constructor: THREE.BufferGeometry, + // update flags - addAttribute: function( name, type, numItems, itemSize ) { + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.tangentsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; - this.attributes[ name ] = { + this.groupsNeedUpdate = false; - itemSize: itemSize, - array: new type( numItems * itemSize ) +}; - }; +THREE.Geometry.prototype = { - }, + constructor: THREE.Geometry, applyMatrix: function ( matrix ) { - var positionArray; - var normalArray; - - if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array; - if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array; + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - if ( positionArray !== undefined ) { + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - matrix.multiplyVector3Array( positionArray ); - this.verticesNeedUpdate = true; + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); } - if ( normalArray !== undefined ) { + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); - normalMatrix.multiplyVector3Array( normalArray ); + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - this.normalizeNormals(); + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - this.normalsNeedUpdate = true; + } } - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { + if ( this.boundingBox !== null ) { - this.boundingBox = new THREE.Box3(); + this.computeBoundingBox(); } - var positions = this.attributes[ "position" ].array; - - if ( positions ) { + if ( this.boundingSphere !== null ) { - var bb = this.boundingBox; - var x, y, z; - - if( positions.length >= 3 ) { - bb.min.x = bb.max.x = positions[ 0 ]; - bb.min.y = bb.max.y = positions[ 1 ]; - bb.min.z = bb.max.z = positions[ 2 ]; - } + this.computeBoundingSphere(); - for ( var i = 3, il = positions.length; i < il; i += 3 ) { + } - x = positions[ i ]; - y = positions[ i + 1 ]; - z = positions[ i + 2 ]; + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; - // bounding box + }, - if ( x < bb.min.x ) { + fromBufferGeometry: function ( geometry ) { - bb.min.x = x; + var scope = this; - } else if ( x > bb.max.x ) { + var attributes = geometry.attributes; - bb.max.x = x; + var vertices = attributes.position.array; + var indices = attributes.index !== undefined ? attributes.index.array : undefined; + var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; + var colors = attributes.color !== undefined ? attributes.color.array : undefined; + var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; - } + var tempNormals = []; + var tempUVs = []; - if ( y < bb.min.y ) { + for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) { - bb.min.y = y; + scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - } else if ( y > bb.max.y ) { + if ( normals !== undefined ) { - bb.max.y = y; + tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); - } + } - if ( z < bb.min.z ) { + if ( colors !== undefined ) { - bb.min.z = z; + scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); - } else if ( z > bb.max.z ) { + } - bb.max.z = z; + if ( uvs !== undefined ) { - } + tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) ); } } - if ( positions === undefined || positions.length === 0 ) { + var addFace = function ( a, b, c ) { - this.boundingBox.min.set( 0, 0, 0 ); - this.boundingBox.max.set( 0, 0, 0 ); + var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; + var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; - } + scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) ); - }, + if ( uvs !== undefined ) { - computeBoundingSphere: function () { + scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - var box = new THREE.Box3(); - var vector = new THREE.Vector3(); + } - return function () { + }; - if ( this.boundingSphere === null ) { + if ( indices !== undefined ) { - this.boundingSphere = new THREE.Sphere(); + var drawcalls = geometry.drawcalls; - } + if ( drawcalls.length > 0 ) { - var positions = this.attributes[ "position" ].array; + for ( var i = 0; i < drawcalls.length; i ++ ) { - if ( positions ) { + var drawcall = drawcalls[ i ]; - var center = this.boundingSphere.center; + var start = drawcall.start; + var count = drawcall.count; + var index = drawcall.index; - for ( var i = 0, il = positions.length; i < il; i += 3 ) { + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - box.addPoint( vector ); + addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] ); - } + } - box.center( center ); + } - var maxRadiusSq = 0; + } else { - for ( var i = 0, il = positions.length; i < il; i += 3 ) { + for ( var i = 0; i < indices.length; i += 3 ) { - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); } - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - } - } + } else { - }(), + for ( var i = 0; i < vertices.length / 3; i += 3 ) { - computeVertexNormals: function () { + addFace( i, i + 1, i + 2 ); - if ( this.attributes[ "position" ] ) { + } - var i, il; - var j, jl; + } - var nVertexElements = this.attributes[ "position" ].array.length; + this.computeFaceNormals(); - if ( this.attributes[ "normal" ] === undefined ) { + if ( geometry.boundingBox !== null ) { - this.attributes[ "normal" ] = { + this.boundingBox = geometry.boundingBox.clone(); - itemSize: 3, - array: new Float32Array( nVertexElements ) + } - }; + if ( geometry.boundingSphere !== null ) { - } else { + this.boundingSphere = geometry.boundingSphere.clone(); - // reset existing normals to zero + } - for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { + return this; - this.attributes[ "normal" ].array[ i ] = 0; + }, - } + center: function () { - } + this.computeBoundingBox(); - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; + var offset = this.boundingBox.center().negate(); - var vA, vB, vC, x, y, z, + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); - pA = new THREE.Vector3(), - pB = new THREE.Vector3(), - pC = new THREE.Vector3(), + return offset; - cb = new THREE.Vector3(), - ab = new THREE.Vector3(); + }, - // indexed elements + computeFaceNormals: function () { - if ( this.attributes[ "index" ] ) { + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - var indices = this.attributes[ "index" ].array; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - var offsets = this.offsets; + var face = this.faces[ f ]; - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - for ( i = start, il = start + count; i < il; i += 3 ) { + cb.normalize(); - vA = index + indices[ i ]; - vB = index + indices[ i + 1 ]; - vC = index + indices[ i + 2 ]; + face.normal.copy( cb ); - x = positions[ vA * 3 ]; - y = positions[ vA * 3 + 1 ]; - z = positions[ vA * 3 + 2 ]; - pA.set( x, y, z ); + } - x = positions[ vB * 3 ]; - y = positions[ vB * 3 + 1 ]; - z = positions[ vB * 3 + 2 ]; - pB.set( x, y, z ); + }, - x = positions[ vC * 3 ]; - y = positions[ vC * 3 + 1 ]; - z = positions[ vC * 3 + 2 ]; - pC.set( x, y, z ); + computeVertexNormals: function ( areaWeighted ) { - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + var v, vl, f, fl, face, vertices; - normals[ vA * 3 ] += cb.x; - normals[ vA * 3 + 1 ] += cb.y; - normals[ vA * 3 + 2 ] += cb.z; + vertices = new Array( this.vertices.length ); - normals[ vB * 3 ] += cb.x; - normals[ vB * 3 + 1 ] += cb.y; - normals[ vB * 3 + 2 ] += cb.z; + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - normals[ vC * 3 ] += cb.x; - normals[ vC * 3 + 1 ] += cb.y; - normals[ vC * 3 + 2 ] += cb.z; + vertices[ v ] = new THREE.Vector3(); - } + } - } + if ( areaWeighted ) { - // non-indexed elements (unconnected triangle soup) + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm - } else { + var vA, vB, vC; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - for ( i = 0, il = positions.length; i < il; i += 9 ) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - x = positions[ i ]; - y = positions[ i + 1 ]; - z = positions[ i + 2 ]; - pA.set( x, y, z ); + face = this.faces[ f ]; - x = positions[ i + 3 ]; - y = positions[ i + 4 ]; - z = positions[ i + 5 ]; - pB.set( x, y, z ); + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; - x = positions[ i + 6 ]; - y = positions[ i + 7 ]; - z = positions[ i + 8 ]; - pC.set( x, y, z ); + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; + } - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; + } else { - } + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - } + face = this.faces[ f ]; - this.normalizeNormals(); + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); - this.normalsNeedUpdate = true; + } } - }, - - normalizeNormals: function () { - - var normals = this.attributes[ "normal" ].array; + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - var x, y, z, n; + vertices[ v ].normalize(); - for ( var i = 0, il = normals.length; i < il; i += 3 ) { + } - x = normals[ i ]; - y = normals[ i + 1 ]; - z = normals[ i + 2 ]; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + face = this.faces[ f ]; - normals[ i ] *= n; - normals[ i + 1 ] *= n; - normals[ i + 2 ] *= n; + face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); + face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); + face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); } }, - computeTangents: function () { - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( this.attributes[ "index" ] === undefined || - this.attributes[ "position" ] === undefined || - this.attributes[ "normal" ] === undefined || - this.attributes[ "uv" ] === undefined ) { - - console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); - return; + computeMorphNormals: function () { - } + var i, il, f, fl, face; - var indices = this.attributes[ "index" ].array; - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; - var uvs = this.attributes[ "uv" ].array; + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) - var nVertices = positions.length / 3; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - if ( this.attributes[ "tangent" ] === undefined ) { + face = this.faces[ f ]; - var nTangentElements = 4 * nVertices; + if ( ! face.__originalFaceNormal ) { - this.attributes[ "tangent" ] = { + face.__originalFaceNormal = face.normal.clone(); - itemSize: 4, - array: new Float32Array( nTangentElements ) + } else { - }; + face.__originalFaceNormal.copy( face.normal ); - } + } - var tangents = this.attributes[ "tangent" ].array; + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - var tan1 = [], tan2 = []; + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - for ( var k = 0; k < nVertices; k ++ ) { + if ( ! face.__originalVertexNormals[ i ] ) { - tan1[ k ] = new THREE.Vector3(); - tan2[ k ] = new THREE.Vector3(); + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - } + } else { - var xA, yA, zA, - xB, yB, zB, - xC, yC, zC, + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - uA, vA, - uB, vB, - uC, vC, + } - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r; + } - var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + } - function handleTriangle( a, b, c ) { + // use temp geometry to compute face and vertex normals for each morph - xA = positions[ a * 3 ]; - yA = positions[ a * 3 + 1 ]; - zA = positions[ a * 3 + 2 ]; + var tmpGeo = new THREE.Geometry(); + tmpGeo.faces = this.faces; - xB = positions[ b * 3 ]; - yB = positions[ b * 3 + 1 ]; - zB = positions[ b * 3 + 2 ]; + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - xC = positions[ c * 3 ]; - yC = positions[ c * 3 + 1 ]; - zC = positions[ c * 3 + 2 ]; + // create on first access - uA = uvs[ a * 2 ]; - vA = uvs[ a * 2 + 1 ]; + if ( ! this.morphNormals[ i ] ) { - uB = uvs[ b * 2 ]; - vB = uvs[ b * 2 + 1 ]; + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; - uC = uvs[ c * 2 ]; - vC = uvs[ c * 2 + 1 ]; + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - x1 = xB - xA; - x2 = xC - xA; + var faceNormal, vertexNormals; - y1 = yB - yA; - y2 = yC - yA; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - z1 = zB - zA; - z2 = zC - zA; + faceNormal = new THREE.Vector3(); + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; - s1 = uB - uA; - s2 = uC - uA; + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); - t1 = vB - vA; - t2 = vC - vA; + } - r = 1.0 / ( s1 * t2 - s2 * t1 ); + } - sdir.set( - ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r - ); + var morphNormals = this.morphNormals[ i ]; - tdir.set( - ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r - ); + // set vertices to morph target - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); + tmpGeo.vertices = this.morphTargets[ i ].vertices; - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); + // compute morph normals - } + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); - var i, il; - var j, jl; - var iA, iB, iC; + // store morph normals - var offsets = this.offsets; + var faceNormal, vertexNormals; - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + face = this.faces[ f ]; - for ( i = start, il = start + count; i < il; i += 3 ) { + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; + faceNormal.copy( face.normal ); - handleTriangle( iA, iB, iC ); + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); } } - var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); - var n = new THREE.Vector3(), n2 = new THREE.Vector3(); - var w, t, test; + // restore original normals - function handleVertex( v ) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - n.x = normals[ v * 3 ]; - n.y = normals[ v * 3 + 1 ]; - n.z = normals[ v * 3 + 2 ]; + face = this.faces[ f ]; - n2.copy( n ); + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; - t = tan1[ v ]; + } - // Gram-Schmidt orthogonalize + }, - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + computeTangents: function () { - // Calculate handedness + // based on http://www.terathon.com/code/tangent.html + // tangents go to vertices - tmp2.crossVectors( n2, t ); - test = tmp2.dot( tan2[ v ] ); - w = ( test < 0.0 ) ? -1.0 : 1.0; + var f, fl, v, vl, i, vertexIndex, + face, uv, vA, vB, vC, uvA, uvB, uvC, + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r, t, test, + tan1 = [], tan2 = [], + sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), + tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), + n = new THREE.Vector3(), w; - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + tan1[ v ] = new THREE.Vector3(); + tan2[ v ] = new THREE.Vector3(); } - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + function handleTriangle( context, a, b, c, ua, ub, uc ) { - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; + vA = context.vertices[ a ]; + vB = context.vertices[ b ]; + vC = context.vertices[ c ]; - for ( i = start, il = start + count; i < il; i += 3 ) { + uvA = uv[ ua ]; + uvB = uv[ ub ]; + uvC = uv[ uc ]; - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; - handleVertex( iA ); - handleVertex( iB ); - handleVertex( iC ); + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; - } + r = 1.0 / ( s1 * t2 - s2 * t1 ); + sdir.set( ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r ); + tdir.set( ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); } - this.hasTangents = true; - this.tangentsNeedUpdate = true; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - }, + face = this.faces[ f ]; + uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents - clone: function () { + handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); - var geometry = new THREE.BufferGeometry(); + } - var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + var faceIndex = [ 'a', 'b', 'c', 'd' ]; - for ( var attr in this.attributes ) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - var sourceAttr = this.attributes[ attr ]; - var sourceArray = sourceAttr.array; + face = this.faces[ f ]; + + for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) { - var attribute = { + n.copy( face.vertexNormals[ i ] ); - itemSize: sourceAttr.itemSize, - numItems: sourceAttr.numItems, - array: null + vertexIndex = face[ faceIndex[ i ] ]; - }; + t = tan1[ vertexIndex ]; - for ( var i = 0, il = types.length; i < il; i ++ ) { + // Gram-Schmidt orthogonalize - var type = types[ i ]; + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - if ( sourceArray instanceof type ) { + // Calculate handedness - attribute.array = new type( sourceArray ); - break; + tmp2.crossVectors( face.vertexNormals[ i ], t ); + test = tmp2.dot( tan2[ vertexIndex ] ); + w = ( test < 0.0 ) ? - 1.0 : 1.0; - } + face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); } - geometry.attributes[ attr ] = attribute; - } - for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { + this.hasTangents = true; - var offset = this.offsets[ i ]; + }, - geometry.offsets.push( { + computeLineDistances: function () { - start: offset.start, - index: offset.index, - count: offset.count + var d = 0; + var vertices = this.vertices; - } ); + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - } + if ( i > 0 ) { - return geometry; + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); - }, + } - dispose: function () { + this.lineDistances[ i ] = d; - this.dispatchEvent( { type: 'dispose' } ); + } - } + }, -}; + computeBoundingBox: function () { -THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); + if ( this.boundingBox === null ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ + this.boundingBox = new THREE.Box3(); -THREE.Camera = function () { + } - THREE.Object3D.call( this ); + this.boundingBox.setFromPoints( this.vertices ); - this.matrixWorldInverse = new THREE.Matrix4(); + }, - this.projectionMatrix = new THREE.Matrix4(); - this.projectionMatrixInverse = new THREE.Matrix4(); + computeBoundingSphere: function () { -}; + if ( this.boundingSphere === null ) { -THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); + this.boundingSphere = new THREE.Sphere(); -THREE.Camera.prototype.lookAt = function () { + } - // This routine does not support cameras with rotated and/or translated parent(s) + this.boundingSphere.setFromPoints( this.vertices ); - var m1 = new THREE.Matrix4(); + }, - return function ( vector ) { + merge: function ( geometry, matrix, materialIndexOffset ) { - m1.lookAt( this.position, vector, this.up ); + if ( geometry instanceof THREE.Geometry === false ) { - this.quaternion.setFromRotationMatrix( m1 ); + THREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; - }; + } -}(); + var normalMatrix, + vertexOffset = this.vertices.length, + vertices1 = this.vertices, + vertices2 = geometry.vertices, + faces1 = this.faces, + faces2 = geometry.faces, + uvs1 = this.faceVertexUvs[ 0 ], + uvs2 = geometry.faceVertexUvs[ 0 ]; -THREE.Camera.prototype.clone = function (camera) { + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - if ( camera === undefined ) camera = new THREE.Camera(); + if ( matrix !== undefined ) { - THREE.Object3D.prototype.clone.call( this, camera ); + normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - camera.matrixWorldInverse.copy( this.matrixWorldInverse ); - camera.projectionMatrix.copy( this.projectionMatrix ); - camera.projectionMatrixInverse.copy( this.projectionMatrixInverse ); + } - return camera; -}; + // vertices -/** - * @author alteredq / http://alteredqualia.com/ - */ + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { -THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { + var vertex = vertices2[ i ]; - THREE.Camera.call( this ); + var vertexCopy = vertex.clone(); - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; + vertices1.push( vertexCopy ); - this.updateProjectionMatrix(); + } -}; + // faces -THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); + for ( i = 0, il = faces2.length; i < il; i ++ ) { -THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; - this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); -}; + if ( normalMatrix !== undefined ) { -THREE.OrthographicCamera.prototype.clone = function () { + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - var camera = new THREE.OrthographicCamera(); + } - THREE.Camera.prototype.clone.call( this, camera ); + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - camera.left = this.left; - camera.right = this.right; - camera.top = this.top; - camera.bottom = this.bottom; + normal = faceVertexNormals[ j ].clone(); - camera.near = this.near; - camera.far = this.far; + if ( normalMatrix !== undefined ) { - return camera; -}; + normal.applyMatrix3( normalMatrix ).normalize(); -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ + } -THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { + faceCopy.vertexNormals.push( normal ); - THREE.Camera.call( this ); + } - this.fov = fov !== undefined ? fov : 50; - this.aspect = aspect !== undefined ? aspect : 1; - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; + faceCopy.color.copy( face.color ); - this.updateProjectionMatrix(); + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { -}; + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); -THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); + } + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; -/** - * Uses Focal Length (in mm) to estimate and set FOV - * 35mm (fullframe) camera is used if frame size is not specified; - * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html - */ + faces1.push( faceCopy ); -THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { + } - if ( frameHeight === undefined ) frameHeight = 24; + // uvs - this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); - this.updateProjectionMatrix(); + for ( i = 0, il = uvs2.length; i < il; i ++ ) { -} + var uv = uvs2[ i ], uvCopy = []; + if ( uv === undefined ) { -/** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * var w = 1920; - * var h = 1080; - * var fullWidth = w * 3; - * var fullHeight = h * 2; - * - * --A-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ + continue; -THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { + } - this.fullWidth = fullWidth; - this.fullHeight = fullHeight; - this.x = x; - this.y = y; - this.width = width; - this.height = height; + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - this.updateProjectionMatrix(); + uvCopy.push( uv[ j ].clone() ); -}; + } + uvs1.push( uvCopy ); -THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { + } - if ( this.fullWidth ) { + }, - var aspect = this.fullWidth / this.fullHeight; - var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; - var bottom = -top; - var left = aspect * bottom; - var right = aspect * top; - var width = Math.abs( right - left ); - var height = Math.abs( top - bottom ); + mergeMesh: function ( mesh ) { - this.projectionMatrix.makeFrustum( - left + this.x * width / this.fullWidth, - left + ( this.x + this.width ) * width / this.fullWidth, - top - ( this.y + this.height ) * height / this.fullHeight, - top - this.y * height / this.fullHeight, - this.near, - this.far - ); + if ( mesh instanceof THREE.Mesh === false ) { - } else { + THREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; - this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); + } - } + mesh.matrixAutoUpdate && mesh.updateMatrix(); -}; + this.merge( mesh.geometry, mesh.matrix ); -THREE.PerspectiveCamera.prototype.clone = function () { + }, - var camera = new THREE.PerspectiveCamera(); + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ - THREE.Camera.prototype.clone.call( this, camera ); + mergeVertices: function () { - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; + var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) + var unique = [], changes = []; - return camera; -}; + var v, key; + var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i, il, face; + var indices, j, jl; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { -THREE.Light = function ( hex ) { + v = this.vertices[ i ]; + key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); - THREE.Object3D.call( this ); + if ( verticesMap[ key ] === undefined ) { - this.color = new THREE.Color( hex ); + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; -}; + } else { -THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; -THREE.Light.prototype.clone = function ( light ) { + } - if ( light === undefined ) light = new THREE.Light(); - - THREE.Object3D.prototype.clone.call( this, light ); - - light.color.copy( this.color ); - - return light; + }; -}; -/** - * @author mrdoob / http://mrdoob.com/ - */ + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; -THREE.AmbientLight = function ( hex ) { + for ( i = 0, il = this.faces.length; i < il; i ++ ) { - THREE.Light.call( this, hex ); + face = this.faces[ i ]; -}; + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; -THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); + indices = [ face.a, face.b, face.c ]; -THREE.AmbientLight.prototype.clone = function () { + var dupIndex = - 1; - var light = new THREE.AmbientLight(); + // if any duplicate vertices are found in a Face3 + // we have to remove the face as nothing can be saved + for ( var n = 0; n < 3; n ++ ) { + if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { - THREE.Light.prototype.clone.call( this, light ); + dupIndex = n; + faceIndicesToRemove.push( i ); + break; - return light; + } + } -}; + } -/** - * @author MPanknin / http://www.redplant.de/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + var idx = faceIndicesToRemove[ i ]; -THREE.AreaLight = function ( hex, intensity ) { + this.faces.splice( idx, 1 ); - THREE.Light.call( this, hex ); + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - this.normal = new THREE.Vector3( 0, -1, 0 ); - this.right = new THREE.Vector3( 1, 0, 0 ); + this.faceVertexUvs[ j ].splice( idx, 1 ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + } - this.width = 1.0; - this.height = 1.0; + } - this.constantAttenuation = 1.5; - this.linearAttenuation = 0.5; - this.quadraticAttenuation = 0.1; + // Use unique set of vertices -}; + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; -THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); + }, + toJSON: function () { -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + var output = { + metadata: { + version: 4.0, + type: 'BufferGeometry', + generator: 'BufferGeometryExporter' + }, + uuid: this.uuid, + type: this.type + }; -THREE.DirectionalLight = function ( hex, intensity ) { + if ( this.name !== "" ) output.name = this.name; - THREE.Light.call( this, hex ); + if ( this.parameters !== undefined ) { - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); + var parameters = this.parameters; - this.intensity = ( intensity !== undefined ) ? intensity : 1; + for ( var key in parameters ) { - this.castShadow = false; - this.onlyShadow = false; + if ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ]; - // + } - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; + return output; - this.shadowCameraLeft = -500; - this.shadowCameraRight = 500; - this.shadowCameraTop = 500; - this.shadowCameraBottom = -500; + } - this.shadowCameraVisible = false; + var vertices = []; - this.shadowBias = 0; - this.shadowDarkness = 0.5; + for ( var i = 0; i < this.vertices.length; i ++ ) { - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - // + } - this.shadowCascade = false; + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; - this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); - this.shadowCascadeCount = 2; + for ( var i = 0; i < this.faces.length; i ++ ) { - this.shadowCascadeBias = [ 0, 0, 0 ]; - this.shadowCascadeWidth = [ 512, 512, 512 ]; - this.shadowCascadeHeight = [ 512, 512, 512 ]; + var face = this.faces[ i ]; - this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + var hasMaterial = false; // face.materialIndex !== undefined; + var hasFaceUv = false; // deprecated + var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; + var hasFaceNormal = face.normal.length() > 0; + var hasFaceVertexNormal = face.vertexNormals.length > 0; + var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; + var hasFaceVertexColor = face.vertexColors.length > 0; - this.shadowCascadeArray = []; + var faceType = 0; - // + faceType = setBit( faceType, 0, 0 ); + faceType = setBit( faceType, 1, hasMaterial ); + faceType = setBit( faceType, 2, hasFaceUv ); + faceType = setBit( faceType, 3, hasFaceVertexUv ); + faceType = setBit( faceType, 4, hasFaceNormal ); + faceType = setBit( faceType, 5, hasFaceVertexNormal ); + faceType = setBit( faceType, 6, hasFaceColor ); + faceType = setBit( faceType, 7, hasFaceVertexColor ); - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); -}; -THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); + /* + if ( hasMaterial ) { -THREE.DirectionalLight.prototype.clone = function () { + faces.push( face.materialIndex ); - var light = new THREE.DirectionalLight(); + } + */ - THREE.Light.prototype.clone.call( this, light ); + if ( hasFaceVertexUv ) { - light.target = this.target.clone(); + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; - light.intensity = this.intensity; + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + } - return light; + if ( hasFaceNormal ) { -}; + faces.push( getNormalIndex( face.normal ) ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.HemisphereLight = function ( skyColorHex, groundColorHex, intensity ) { + if ( hasFaceVertexNormal ) { - THREE.Light.call( this, skyColorHex ); + var vertexNormals = face.vertexNormals; - this.position.set( 0, 100, 0 ); + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); - this.groundColor = new THREE.Color( groundColorHex ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + } -}; + if ( hasFaceColor ) { -THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); + faces.push( getColorIndex( face.color ) ); -THREE.HemisphereLight.prototype.clone = function () { + } - var light = new THREE.HemisphereLight(); + if ( hasFaceVertexColor ) { - THREE.Light.prototype.clone.call( this, light ); + var vertexColors = face.vertexColors; - light.groundColor.copy( this.groundColor ); - light.intensity = this.intensity; + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); - return light; + } -}; + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + function setBit( value, position, enabled ) { -THREE.PointLight = function ( hex, intensity, distance ) { + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) ); - THREE.Light.call( this, hex ); + } - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; + function getNormalIndex( normal ) { -}; + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); -THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); + if ( normalsHash[ hash ] !== undefined ) { -THREE.PointLight.prototype.clone = function () { + return normalsHash[ hash ]; - var light = new THREE.PointLight(); + } - THREE.Light.prototype.clone.call( this, light ); + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); - light.intensity = this.intensity; - light.distance = this.distance; + return normalsHash[ hash ]; - return light; + } -}; + function getColorIndex( color ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + var hash = color.r.toString() + color.g.toString() + color.b.toString(); -THREE.SpotLight = function ( hex, intensity, distance, angle, exponent ) { + if ( colorsHash[ hash ] !== undefined ) { - THREE.Light.call( this, hex ); + return colorsHash[ hash ]; - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); + } - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.exponent = ( exponent !== undefined ) ? exponent : 10; + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); - this.castShadow = false; - this.onlyShadow = false; + return colorsHash[ hash ]; - // + } - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - this.shadowCameraFov = 50; + function getUvIndex( uv ) { - this.shadowCameraVisible = false; + var hash = uv.x.toString() + uv.y.toString(); - this.shadowBias = 0; - this.shadowDarkness = 0.5; + if ( uvsHash[ hash ] !== undefined ) { - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + return uvsHash[ hash ]; - // + } - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); -}; + return uvsHash[ hash ]; -THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); + } -THREE.SpotLight.prototype.clone = function () { + output.data = {}; - var light = new THREE.SpotLight(); + output.data.vertices = vertices; + output.data.normals = normals; + if ( colors.length > 0 ) output.data.colors = colors; + if ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility + output.data.faces = faces; - THREE.Light.prototype.clone.call( this, light ); + // - light.target = this.target.clone(); + return output; - light.intensity = this.intensity; - light.distance = this.distance; - light.angle = this.angle; - light.exponent = this.exponent; + }, - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + clone: function () { - return light; + var geometry = new THREE.Geometry(); -}; + var vertices = this.vertices; -/** - * @author alteredq / http://alteredqualia.com/ - */ + for ( var i = 0, il = vertices.length; i < il; i ++ ) { -THREE.Loader = function ( showStatus ) { + geometry.vertices.push( vertices[ i ].clone() ); - this.showStatus = showStatus; - this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + } - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; + var faces = this.faces; -}; + for ( var i = 0, il = faces.length; i < il; i ++ ) { -THREE.Loader.prototype = { + geometry.faces.push( faces[ i ].clone() ); - constructor: THREE.Loader, + } - crossOrigin: 'anonymous', + for ( var i = 0, il = this.faceVertexUvs.length; i < il; i ++ ) { - addStatusElement: function () { + var faceVertexUvs = this.faceVertexUvs[ i ]; - var e = document.createElement( "div" ); - - e.style.position = "absolute"; - e.style.right = "0px"; - e.style.top = "0px"; - e.style.fontSize = "0.8em"; - e.style.textAlign = "left"; - e.style.background = "rgba(0,0,0,0.25)"; - e.style.color = "#fff"; - e.style.width = "120px"; - e.style.padding = "0.5em 0.5em 0.5em 0.5em"; - e.style.zIndex = 1000; + if ( geometry.faceVertexUvs[ i ] === undefined ) { - e.innerHTML = "Loading ..."; + geometry.faceVertexUvs[ i ] = []; - return e; + } - }, + for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - updateProgress: function ( progress ) { + var uvs = faceVertexUvs[ j ], uvsCopy = []; - var message = "Loaded "; + for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { - if ( progress.total ) { + var uv = uvs[ k ]; - message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; + uvsCopy.push( uv.clone() ); + } - } else { + geometry.faceVertexUvs[ i ].push( uvsCopy ); - message += ( progress.loaded / 1000 ).toFixed(2) + " KB"; + } } - this.statusDomElement.innerHTML = message; + return geometry; }, - extractUrlBase: function ( url ) { + dispose: function () { - var parts = url.split( '/' ); - parts.pop(); - return ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/'; + this.dispatchEvent( { type: 'dispose' } ); - }, + } - initMaterials: function ( materials, texturePath ) { +}; - var array = []; +THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - for ( var i = 0; i < materials.length; ++ i ) { +THREE.GeometryIdCount = 0; - array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath ); +// File:src/cameras/Camera.js - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ - return array; +THREE.Camera = function () { - }, + THREE.Object3D.call( this ); - needsTangents: function ( materials ) { + this.type = 'Camera'; - for( var i = 0, il = materials.length; i < il; i ++ ) { + this.matrixWorldInverse = new THREE.Matrix4(); + this.projectionMatrix = new THREE.Matrix4(); - var m = materials[ i ]; +}; - if ( m instanceof THREE.ShaderMaterial ) return true; +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Camera.prototype.constructor = THREE.Camera; - } +THREE.Camera.prototype.getWorldDirection = function () { - return false; + var quaternion = new THREE.Quaternion(); - }, + return function ( optionalTarget ) { - createMaterial: function ( m, texturePath ) { + var result = optionalTarget || new THREE.Vector3(); - var _this = this; + this.getWorldQuaternion( quaternion ); - function is_pow2( n ) { + return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - var l = Math.log( n ) / Math.LN2; - return Math.floor( l ) == l; + } - } +}(); - function nearest_pow2( n ) { +THREE.Camera.prototype.lookAt = function () { - var l = Math.log( n ) / Math.LN2; - return Math.pow( 2, Math.round( l ) ); + // This routine does not support cameras with rotated and/or translated parent(s) - } + var m1 = new THREE.Matrix4(); - function load_image( where, url ) { + return function ( vector ) { - var image = new Image(); + m1.lookAt( this.position, vector, this.up ); - image.onload = function () { + this.quaternion.setFromRotationMatrix( m1 ); - if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) { + }; - var width = nearest_pow2( this.width ); - var height = nearest_pow2( this.height ); +}(); - where.image.width = width; - where.image.height = height; - where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height ); +THREE.Camera.prototype.clone = function ( camera ) { - } else { + if ( camera === undefined ) camera = new THREE.Camera(); - where.image = this; + THREE.Object3D.prototype.clone.call( this, camera ); - } + camera.matrixWorldInverse.copy( this.matrixWorldInverse ); + camera.projectionMatrix.copy( this.projectionMatrix ); - where.needsUpdate = true; + return camera; +}; - }; +// File:src/cameras/CubeCamera.js - image.crossOrigin = _this.crossOrigin; - image.src = url; +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.CubeCamera = function ( near, far, cubeResolution ) { - function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { + THREE.Object3D.call( this ); - var isCompressed = /\.dds$/i.test( sourceFile ); - var fullPath = texturePath + "/" + sourceFile; + this.type = 'CubeCamera'; - if ( isCompressed ) { + var fov = 90, aspect = 1; - var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); + var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); - where[ name ] = texture; + var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) ); + this.add( cameraNX ); - } else { + var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); - var texture = document.createElement( 'canvas' ); + var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) ); + this.add( cameraNY ); - where[ name ] = new THREE.Texture( texture ); + var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, - 1, 0 ); + cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); - } + var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) ); + this.add( cameraNZ ); - where[ name ].sourceFile = sourceFile; + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); - if( repeat ) { + this.updateCubeMap = function ( renderer, scene ) { - where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; - if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; + renderTarget.generateMipmaps = false; - } + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); - if ( offset ) { + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); - where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); - } + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); - if ( wrap ) { + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } + renderTarget.generateMipmaps = generateMipmaps; - if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; - if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); - } + }; - if ( anisotropy ) { +}; - where[ name ].anisotropy = anisotropy; +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; - } +// File:src/cameras/OrthographicCamera.js - if ( ! isCompressed ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - load_image( where[ name ], fullPath ); +THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { - } + THREE.Camera.call( this ); - } + this.type = 'OrthographicCamera'; - function rgb2hex( rgb ) { + this.zoom = 1; - return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; - } + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; - // defaults + this.updateProjectionMatrix(); - var mtype = "MeshLambertMaterial"; - var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; +}; - // parameters from model file +THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; - if ( m.shading ) { +THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { - var shading = m.shading.toLowerCase(); + var dx = ( this.right - this.left ) / ( 2 * this.zoom ); + var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + var cx = ( this.right + this.left ) / 2; + var cy = ( this.top + this.bottom ) / 2; - if ( shading === "phong" ) mtype = "MeshPhongMaterial"; - else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far ); - } +}; - if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { +THREE.OrthographicCamera.prototype.clone = function () { - mpars.blending = THREE[ m.blending ]; + var camera = new THREE.OrthographicCamera(); - } + THREE.Camera.prototype.clone.call( this, camera ); - if ( m.transparent !== undefined || m.opacity < 1.0 ) { + camera.zoom = this.zoom; - mpars.transparent = m.transparent; + camera.left = this.left; + camera.right = this.right; + camera.top = this.top; + camera.bottom = this.bottom; - } + camera.near = this.near; + camera.far = this.far; - if ( m.depthTest !== undefined ) { + camera.projectionMatrix.copy( this.projectionMatrix ); - mpars.depthTest = m.depthTest; + return camera; +}; - } +// File:src/cameras/PerspectiveCamera.js - if ( m.depthWrite !== undefined ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ - mpars.depthWrite = m.depthWrite; +THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { - } + THREE.Camera.call( this ); - if ( m.visible !== undefined ) { + this.type = 'PerspectiveCamera'; - mpars.visible = m.visible; + this.zoom = 1; - } + this.fov = fov !== undefined ? fov : 50; + this.aspect = aspect !== undefined ? aspect : 1; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; - if ( m.flipSided !== undefined ) { + this.updateProjectionMatrix(); - mpars.side = THREE.BackSide; +}; - } +THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; - if ( m.doubleSided !== undefined ) { - mpars.side = THREE.DoubleSide; +/** + * Uses Focal Length (in mm) to estimate and set FOV + * 35mm (fullframe) camera is used if frame size is not specified; + * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html + */ - } +THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { - if ( m.wireframe !== undefined ) { + if ( frameHeight === undefined ) frameHeight = 24; - mpars.wireframe = m.wireframe; + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); - } +} - if ( m.vertexColors !== undefined ) { - if ( m.vertexColors === "face" ) { +/** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * var w = 1920; + * var h = 1080; + * var fullWidth = w * 3; + * var fullHeight = h * 2; + * + * --A-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ - mpars.vertexColors = THREE.FaceColors; +THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { - } else if ( m.vertexColors ) { + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; - mpars.vertexColors = THREE.VertexColors; + this.updateProjectionMatrix(); - } +}; - } - // colors +THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { - if ( m.colorDiffuse ) { + var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) ); - mpars.color = rgb2hex( m.colorDiffuse ); + if ( this.fullWidth ) { - } else if ( m.DbgColor ) { + var aspect = this.fullWidth / this.fullHeight; + var top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near; + var bottom = - top; + var left = aspect * bottom; + var right = aspect * top; + var width = Math.abs( right - left ); + var height = Math.abs( top - bottom ); - mpars.color = m.DbgColor; + this.projectionMatrix.makeFrustum( + left + this.x * width / this.fullWidth, + left + ( this.x + this.width ) * width / this.fullWidth, + top - ( this.y + this.height ) * height / this.fullHeight, + top - this.y * height / this.fullHeight, + this.near, + this.far + ); - } - - if ( m.colorSpecular ) { - - mpars.specular = rgb2hex( m.colorSpecular ); - - } - - if ( m.colorAmbient ) { - - mpars.ambient = rgb2hex( m.colorAmbient ); - - } + } else { - // modifiers + this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far ); - if ( m.transparency ) { + } - mpars.opacity = m.transparency; +}; - } +THREE.PerspectiveCamera.prototype.clone = function () { - if ( m.specularCoef ) { + var camera = new THREE.PerspectiveCamera(); - mpars.shininess = m.specularCoef; + THREE.Camera.prototype.clone.call( this, camera ); - } + camera.zoom = this.zoom; - // textures + camera.fov = this.fov; + camera.aspect = this.aspect; + camera.near = this.near; + camera.far = this.far; - if ( m.mapDiffuse && texturePath ) { + camera.projectionMatrix.copy( this.projectionMatrix ); - create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + return camera; - } +}; - if ( m.mapLight && texturePath ) { +// File:src/lights/Light.js - create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.Light = function ( color ) { - if ( m.mapBump && texturePath ) { + THREE.Object3D.call( this ); - create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + this.type = 'Light'; + + this.color = new THREE.Color( color ); - } +}; - if ( m.mapNormal && texturePath ) { +THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Light.prototype.constructor = THREE.Light; - create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); +THREE.Light.prototype.clone = function ( light ) { - } + if ( light === undefined ) light = new THREE.Light(); - if ( m.mapSpecular && texturePath ) { + THREE.Object3D.prototype.clone.call( this, light ); - create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + light.color.copy( this.color ); - } + return light; - // +}; - if ( m.mapBumpScale ) { +// File:src/lights/AmbientLight.js - mpars.bumpScale = m.mapBumpScale; +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.AmbientLight = function ( color ) { - // special case for normal mapped material + THREE.Light.call( this, color ); - if ( m.mapNormal ) { + this.type = 'AmbientLight'; - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); +}; - uniforms[ "tNormal" ].value = mpars.normalMap; +THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; - if ( m.mapNormalFactor ) { +THREE.AmbientLight.prototype.clone = function () { - uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); + var light = new THREE.AmbientLight(); - } + THREE.Light.prototype.clone.call( this, light ); - if ( mpars.map ) { + return light; - uniforms[ "tDiffuse" ].value = mpars.map; - uniforms[ "enableDiffuse" ].value = true; +}; - } +// File:src/lights/AreaLight.js - if ( mpars.specularMap ) { +/** + * @author MPanknin / http://www.redplant.de/ + * @author alteredq / http://alteredqualia.com/ + */ - uniforms[ "tSpecular" ].value = mpars.specularMap; - uniforms[ "enableSpecular" ].value = true; +THREE.AreaLight = function ( color, intensity ) { - } + THREE.Light.call( this, color ); - if ( mpars.lightMap ) { + this.type = 'AreaLight'; - uniforms[ "tAO" ].value = mpars.lightMap; - uniforms[ "enableAO" ].value = true; + this.normal = new THREE.Vector3( 0, - 1, 0 ); + this.right = new THREE.Vector3( 1, 0, 0 ); - } + this.intensity = ( intensity !== undefined ) ? intensity : 1; - // for the moment don't handle displacement texture + this.width = 1.0; + this.height = 1.0; - uniforms[ "uDiffuseColor" ].value.setHex( mpars.color ); - uniforms[ "uSpecularColor" ].value.setHex( mpars.specular ); - uniforms[ "uAmbientColor" ].value.setHex( mpars.ambient ); + this.constantAttenuation = 1.5; + this.linearAttenuation = 0.5; + this.quadraticAttenuation = 0.1; - uniforms[ "uShininess" ].value = mpars.shininess; +}; - if ( mpars.opacity !== undefined ) { +THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AreaLight.prototype.constructor = THREE.AreaLight; - uniforms[ "uOpacity" ].value = mpars.opacity; - } +// File:src/lights/DirectionalLight.js - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - var material = new THREE.ShaderMaterial( parameters ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - if ( mpars.transparent ) { +THREE.DirectionalLight = function ( color, intensity ) { - material.transparent = true; + THREE.Light.call( this, color ); - } + this.type = 'DirectionalLight'; - } else { + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); - var material = new THREE[ mtype ]( mpars ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; - } + this.castShadow = false; + this.onlyShadow = false; - if ( m.DbgName !== undefined ) material.name = m.DbgName; + // - return material; + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; - } + this.shadowCameraLeft = - 500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = - 500; -}; + this.shadowCameraVisible = false; -/** - * @author mrdoob / http://mrdoob.com/ - */ + this.shadowBias = 0; + this.shadowDarkness = 0.5; -THREE.XHRLoader = function ( manager ) { + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + // -}; + this.shadowCascade = false; -THREE.XHRLoader.prototype = { + this.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 ); + this.shadowCascadeCount = 2; - constructor: THREE.XHRLoader, + this.shadowCascadeBias = [ 0, 0, 0 ]; + this.shadowCascadeWidth = [ 512, 512, 512 ]; + this.shadowCascadeHeight = [ 512, 512, 512 ]; - load: function ( url, onLoad, onProgress, onError ) { + this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; - var scope = this; - var request = new XMLHttpRequest(); + this.shadowCascadeArray = []; - if ( onLoad !== undefined ) { + // - request.addEventListener( 'load', function ( event ) { + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; - onLoad( event.target.responseText ); - scope.manager.itemEnd( url ); +}; - }, false ); +THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); +THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; - } +THREE.DirectionalLight.prototype.clone = function () { - if ( onProgress !== undefined ) { + var light = new THREE.DirectionalLight(); - request.addEventListener( 'progress', function ( event ) { + THREE.Light.prototype.clone.call( this, light ); - onProgress( event ); + light.target = this.target.clone(); - }, false ); + light.intensity = this.intensity; - } + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; - if ( onError !== undefined ) { + // - request.addEventListener( 'error', function ( event ) { + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; - onError( event ); + light.shadowCameraLeft = this.shadowCameraLeft; + light.shadowCameraRight = this.shadowCameraRight; + light.shadowCameraTop = this.shadowCameraTop; + light.shadowCameraBottom = this.shadowCameraBottom; - }, false ); + light.shadowCameraVisible = this.shadowCameraVisible; - } + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; - if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; - request.open( 'GET', url, true ); - request.send( null ); + // - scope.manager.itemStart( url ); + light.shadowCascade = this.shadowCascade; - }, + light.shadowCascadeOffset.copy( this.shadowCascadeOffset ); + light.shadowCascadeCount = this.shadowCascadeCount; - setCrossOrigin: function ( value ) { + light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 ); + light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 ); + light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 ); - this.crossOrigin = value; + light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 ); + light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 ); - } + return light; }; +// File:src/lights/HemisphereLight.js + /** - * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ */ -THREE.ImageLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.ImageLoader.prototype = { +THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { - constructor: THREE.ImageLoader, + THREE.Light.call( this, skyColor ); - load: function ( url, onLoad, onProgress, onError ) { + this.type = 'HemisphereLight'; - var scope = this; - var image = document.createElement( 'img' ); + this.position.set( 0, 100, 0 ); - if ( onLoad !== undefined ) { + this.groundColor = new THREE.Color( groundColor ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; - image.addEventListener( 'load', function ( event ) { +}; - scope.manager.itemEnd( url ); - onLoad( this ); +THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); +THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; - }, false ); +THREE.HemisphereLight.prototype.clone = function () { - } + var light = new THREE.HemisphereLight(); - if ( onProgress !== undefined ) { + THREE.Light.prototype.clone.call( this, light ); - image.addEventListener( 'progress', function ( event ) { + light.groundColor.copy( this.groundColor ); + light.intensity = this.intensity; - onProgress( event ); + return light; - }, false ); +}; - } +// File:src/lights/PointLight.js - if ( onError !== undefined ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - image.addEventListener( 'error', function ( event ) { +THREE.PointLight = function ( color, intensity, distance, decay ) { - onError( event ); + THREE.Light.call( this, color ); - }, false ); + this.type = 'PointLight'; - } + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; +}; - image.src = url; +THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); +THREE.PointLight.prototype.constructor = THREE.PointLight; - scope.manager.itemStart( url ); +THREE.PointLight.prototype.clone = function () { - return image; + var light = new THREE.PointLight(); - }, + THREE.Light.prototype.clone.call( this, light ); - setCrossOrigin: function ( value ) { + light.intensity = this.intensity; + light.distance = this.distance; + light.decay = this.decay; - this.crossOrigin = value; + return light; - } +}; -} +// File:src/lights/SpotLight.js /** - * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ -THREE.JSONLoader = function ( showStatus ) { +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { - THREE.Loader.call( this, showStatus ); + THREE.Light.call( this, color ); - this.withCredentials = false; + this.type = 'SpotLight'; -}; + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); -THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.exponent = ( exponent !== undefined ) ? exponent : 10; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. -THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { + this.castShadow = false; + this.onlyShadow = false; - var scope = this; + // - // todo: unify load API to for easier SceneLoader use + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; - texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); + this.shadowCameraVisible = false; - this.onLoadStart(); - this.loadAjaxJSON( this, url, callback, texturePath ); + this.shadowBias = 0; + this.shadowDarkness = 0.5; -}; + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; -THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { + // - var xhr = new XMLHttpRequest(); + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; - var length = 0; +}; - xhr.onreadystatechange = function () { +THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); +THREE.SpotLight.prototype.constructor = THREE.SpotLight; - if ( xhr.readyState === xhr.DONE ) { +THREE.SpotLight.prototype.clone = function () { - if ( xhr.status === 200 || xhr.status === 0 ) { + var light = new THREE.SpotLight(); - if ( xhr.responseText ) { + THREE.Light.prototype.clone.call( this, light ); - var json = JSON.parse( xhr.responseText ); - var result = context.parse( json, texturePath ); - callback( result.geometry, result.materials ); + light.target = this.target.clone(); - } else { + light.intensity = this.intensity; + light.distance = this.distance; + light.angle = this.angle; + light.exponent = this.exponent; + light.decay = this.decay; - console.warn( "THREE.JSONLoader: [" + url + "] seems to be unreachable or file there is empty" ); + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; - } + // - // in context of more complex asset initialization - // do not block on single failed file - // maybe should go even one more level up + light.shadowCameraNear = this.shadowCameraNear; + light.shadowCameraFar = this.shadowCameraFar; + light.shadowCameraFov = this.shadowCameraFov; - context.onLoadComplete(); + light.shadowCameraVisible = this.shadowCameraVisible; - } else { + light.shadowBias = this.shadowBias; + light.shadowDarkness = this.shadowDarkness; - console.error( "THREE.JSONLoader: Couldn't load [" + url + "] [" + xhr.status + "]" ); + light.shadowMapWidth = this.shadowMapWidth; + light.shadowMapHeight = this.shadowMapHeight; - } + return light; - } else if ( xhr.readyState === xhr.LOADING ) { +}; - if ( callbackProgress ) { +// File:src/loaders/Cache.js - if ( length === 0 ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - length = xhr.getResponseHeader( "Content-Length" ); +THREE.Cache = { - } + files: {}, - callbackProgress( { total: length, loaded: xhr.responseText.length } ); + add: function ( key, file ) { - } + // console.log( 'THREE.Cache', 'Adding key:', key ); - } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { + this.files[ key ] = file; - if ( callbackProgress !== undefined ) { + }, - length = xhr.getResponseHeader( "Content-Length" ); + get: function ( key ) { - } + // console.log( 'THREE.Cache', 'Checking key:', key ); - } + return this.files[ key ]; - }; + }, - xhr.open( "GET", url, true ); - xhr.withCredentials = this.withCredentials; - xhr.send( null ); + remove: function ( key ) { -}; + delete this.files[ key ]; -THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { + }, - var scope = this, - geometry = new THREE.Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + clear: function () { - parseModel( scale ); + this.files = {} - parseSkin(); - parseMorphing( scale ); + } - geometry.computeCentroids(); - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); +}; - function parseModel( scale ) { +// File:src/loaders/Loader.js - function isBitSet( value, position ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - return value & ( 1 << position ); +THREE.Loader = function ( showStatus ) { - } + this.showStatus = showStatus; + this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; - var i, j, fi, + this.imageLoader = new THREE.ImageLoader(); - offset, zLength, + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; - colorIndex, normalIndex, uvIndex, materialIndex, +}; - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, +THREE.Loader.prototype = { - vertex, face, faceA, faceB, color, hex, normal, + constructor: THREE.Loader, - uvLayer, uv, u, v, + crossOrigin: undefined, - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + addStatusElement: function () { - nUvLayers = 0; + var e = document.createElement( 'div' ); + + e.style.position = 'absolute'; + e.style.right = '0px'; + e.style.top = '0px'; + e.style.fontSize = '0.8em'; + e.style.textAlign = 'left'; + e.style.background = 'rgba(0,0,0,0.25)'; + e.style.color = '#fff'; + e.style.width = '120px'; + e.style.padding = '0.5em 0.5em 0.5em 0.5em'; + e.style.zIndex = 1000; - if ( json.uvs !== undefined ) { + e.innerHTML = 'Loading ...'; - // disregard empty arrays + return e; - for ( i = 0; i < json.uvs.length; i++ ) { + }, - if ( json.uvs[ i ].length ) nUvLayers ++; + updateProgress: function ( progress ) { - } + var message = 'Loaded '; - for ( i = 0; i < nUvLayers; i++ ) { + if ( progress.total ) { - geometry.faceVertexUvs[ i ] = []; + message += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%'; - } - } + } else { - offset = 0; - zLength = vertices.length; + message += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB'; - while ( offset < zLength ) { + } - vertex = new THREE.Vector3(); + this.statusDomElement.innerHTML = message; - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; + }, - geometry.vertices.push( vertex ); + extractUrlBase: function ( url ) { - } + var parts = url.split( '/' ); - offset = 0; - zLength = faces.length; + if ( parts.length === 1 ) return './'; - while ( offset < zLength ) { + parts.pop(); - type = faces[ offset ++ ]; + return parts.join( '/' ) + '/'; + }, - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); + initMaterials: function ( materials, texturePath ) { - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + var array = []; - if ( isQuad ) { + for ( var i = 0; i < materials.length; ++ i ) { - faceA = new THREE.Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; + array[ i ] = this.createMaterial( materials[ i ], texturePath ); - faceB = new THREE.Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; + } - offset += 4; + return array; - if ( hasMaterial ) { + }, - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; + needsTangents: function ( materials ) { - } + for ( var i = 0, il = materials.length; i < il; i ++ ) { - // to get face <=> uv index correspondence + var m = materials[ i ]; - fi = geometry.faces.length; + if ( m instanceof THREE.ShaderMaterial ) return true; - if ( hasFaceVertexUv ) { + } - for ( i = 0; i < nUvLayers; i++ ) { + return false; - uvLayer = json.uvs[ i ]; + }, - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = [] + createMaterial: function ( m, texturePath ) { - for ( j = 0; j < 4; j ++ ) { + var scope = this; - uvIndex = faces[ offset ++ ]; + function nearest_pow2( n ) { - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); - uv = new THREE.Vector2( u, v ); + } - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - } + var fullPath = texturePath + sourceFile; - } + var texture; - } + var loader = THREE.Loader.Handlers.get( fullPath ); - if ( hasFaceNormal ) { + if ( loader !== null ) { - normalIndex = faces[ offset ++ ] * 3; + texture = loader.load( fullPath ); - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + } else { - faceB.normal.copy( faceA.normal ); + texture = new THREE.Texture(); - } + loader = scope.imageLoader; + loader.crossOrigin = scope.crossOrigin; + loader.load( fullPath, function ( image ) { - if ( hasFaceVertexNormal ) { + if ( THREE.Math.isPowerOfTwo( image.width ) === false || + THREE.Math.isPowerOfTwo( image.height ) === false ) { - for ( i = 0; i < 4; i++ ) { + var width = nearest_pow2( image.width ); + var height = nearest_pow2( image.height ); - normalIndex = faces[ offset ++ ] * 3; + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, width, height ); + texture.image = canvas; - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + } else { + + texture.image = image; } - } + texture.needsUpdate = true; + } ); - if ( hasFaceColor ) { + } - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + texture.sourceFile = sourceFile; - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + if ( repeat ) { - } + texture.repeat.set( repeat[ 0 ], repeat[ 1 ] ); + if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - if ( hasFaceVertexColor ) { + } - for ( i = 0; i < 4; i++ ) { + if ( offset ) { - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + texture.offset.set( offset[ 0 ], offset[ 1 ] ); - if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); + } - } + if ( wrap ) { + var wrapMap = { + 'repeat': THREE.RepeatWrapping, + 'mirror': THREE.MirroredRepeatWrapping } - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ]; - } else { + } - face = new THREE.Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + if ( anisotropy ) { - if ( hasMaterial ) { + texture.anisotropy = anisotropy; - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + } - } + where[ name ] = texture; - // to get face <=> uv index correspondence + } - fi = geometry.faces.length; + function rgb2hex( rgb ) { - if ( hasFaceVertexUv ) { + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; - for ( i = 0; i < nUvLayers; i++ ) { + } - uvLayer = json.uvs[ i ]; + // defaults - geometry.faceVertexUvs[ i ][ fi ] = []; + var mtype = 'MeshLambertMaterial'; + var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; - for ( j = 0; j < 3; j ++ ) { - - uvIndex = faces[ offset ++ ]; - - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; - - uv = new THREE.Vector2( u, v ); - - geometry.faceVertexUvs[ i ][ fi ].push( uv ); - - } - - } - - } - - if ( hasFaceNormal ) { - - normalIndex = faces[ offset ++ ] * 3; - - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - } - - if ( hasFaceVertexNormal ) { - - for ( i = 0; i < 3; i++ ) { - - normalIndex = faces[ offset ++ ] * 3; - - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - face.vertexNormals.push( normal ); - - } - - } - - - if ( hasFaceColor ) { - - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); - - } - - - if ( hasFaceVertexColor ) { - - for ( i = 0; i < 3; i++ ) { - - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); - - } + // parameters from model file - } + if ( m.shading ) { - geometry.faces.push( face ); + var shading = m.shading.toLowerCase(); - } + if ( shading === 'phong' ) mtype = 'MeshPhongMaterial'; + else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial'; } - }; - - function parseSkin() { - - var i, l, x, y, z, w, a, b, c, d; - - if ( json.skinWeights ) { + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { - for ( i = 0, l = json.skinWeights.length; i < l; i += 2 ) { + mpars.blending = THREE[ m.blending ]; - x = json.skinWeights[ i ]; - y = json.skinWeights[ i + 1 ]; - z = 0; - w = 0; + } - geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); + if ( m.transparent !== undefined ) { - } + mpars.transparent = m.transparent; } - if ( json.skinIndices ) { + if ( m.opacity !== undefined && m.opacity < 1.0 ) { - for ( i = 0, l = json.skinIndices.length; i < l; i += 2 ) { + mpars.transparent = true; - a = json.skinIndices[ i ]; - b = json.skinIndices[ i + 1 ]; - c = 0; - d = 0; + } - geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); + if ( m.depthTest !== undefined ) { - } + mpars.depthTest = m.depthTest; } - geometry.bones = json.bones; - // could change this to json.animations[0] or remove completely - geometry.animation = json.animation; - geometry.animations = json.animations; - }; - - function parseMorphing( scale ) { + if ( m.depthWrite !== undefined ) { - if ( json.morphTargets !== undefined ) { + mpars.depthWrite = m.depthWrite; - var i, l, v, vl, dstVertices, srcVertices; + } - for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + if ( m.visible !== undefined ) { - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; + mpars.visible = m.visible; - dstVertices = geometry.morphTargets[ i ].vertices; - srcVertices = json.morphTargets [ i ].vertices; + } - for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + if ( m.flipSided !== undefined ) { - var vertex = new THREE.Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + mpars.side = THREE.BackSide; - dstVertices.push( vertex ); + } - } + if ( m.doubleSided !== undefined ) { - } + mpars.side = THREE.DoubleSide; } - if ( json.morphColors !== undefined ) { + if ( m.wireframe !== undefined ) { - var i, l, c, cl, dstColors, srcColors, color; + mpars.wireframe = m.wireframe; - for ( i = 0, l = json.morphColors.length; i < l; i++ ) { + } - geometry.morphColors[ i ] = {}; - geometry.morphColors[ i ].name = json.morphColors[ i ].name; - geometry.morphColors[ i ].colors = []; + if ( m.vertexColors !== undefined ) { - dstColors = geometry.morphColors[ i ].colors; - srcColors = json.morphColors [ i ].colors; + if ( m.vertexColors === 'face' ) { - for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + mpars.vertexColors = THREE.FaceColors; - color = new THREE.Color( 0xffaa00 ); - color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); - dstColors.push( color ); + } else if ( m.vertexColors ) { - } + mpars.vertexColors = THREE.VertexColors; } } - }; - - if ( json.materials === undefined ) { - - return { geometry: geometry }; + // colors - } else { + if ( m.colorDiffuse ) { - var materials = this.initMaterials( json.materials, texturePath ); + mpars.color = rgb2hex( m.colorDiffuse ); - if ( this.needsTangents( materials ) ) { + } else if ( m.DbgColor ) { - geometry.computeTangents(); + mpars.color = m.DbgColor; } - return { geometry: geometry, materials: materials }; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LoadingManager = function ( onLoad, onProgress, onError ) { - - var scope = this; - - var loaded = 0, total = 0; - - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - total ++; - - }; - - this.itemEnd = function ( url ) { - - loaded ++; - - if ( scope.onProgress !== undefined ) { + if ( m.colorSpecular ) { - scope.onProgress( url, loaded, total ); + mpars.specular = rgb2hex( m.colorSpecular ); } - if ( loaded === total && scope.onLoad !== undefined ) { + if ( m.colorEmissive ) { - scope.onLoad(); + mpars.emissive = rgb2hex( m.colorEmissive ); } - }; - -}; - -THREE.DefaultLoadingManager = new THREE.LoadingManager(); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BufferGeometryLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.BufferGeometryLoader.prototype = { - - constructor: THREE.BufferGeometryLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { + // modifiers - onLoad( scope.parse( JSON.parse( text ) ) ); + if ( m.transparency !== undefined ) { - } ); + console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); + m.opacity = m.transparency; - }, + } - setCrossOrigin: function ( value ) { + if ( m.opacity !== undefined ) { - this.crossOrigin = value; + mpars.opacity = m.opacity; - }, + } - parse: function ( json ) { + if ( m.specularCoef ) { - var geometry = new THREE.BufferGeometry(); + mpars.shininess = m.specularCoef; - var attributes = json.attributes; - var offsets = json.offsets; - var boundingSphere = json.boundingSphere; + } - for ( var key in attributes ) { + // textures - var attribute = attributes[ key ]; + if ( m.mapDiffuse && texturePath ) { - geometry.attributes[ key ] = { - itemSize: attribute.itemSize, - array: new self[ attribute.type ]( attribute.array ) - } + create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); } - if ( offsets !== undefined ) { + if ( m.mapLight && texturePath ) { - geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); + create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); } - if ( boundingSphere !== undefined ) { + if ( m.mapBump && texturePath ) { - geometry.boundingSphere = new THREE.Sphere( - new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), - boundingSphere.radius - ); + create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); } - return geometry; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.GeometryLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; + if ( m.mapNormal && texturePath ) { -THREE.GeometryLoader.prototype = { + create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - constructor: THREE.GeometryLoader, + } - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MaterialLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.MaterialLoader.prototype = { - - constructor: THREE.MaterialLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var material = new THREE[ json.type ]; - - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - - if ( json.materials !== undefined ) { - - for ( var i = 0, l = json.materials.length; i < l; i ++ ) { - - material.materials.push( this.parse( json.materials[ i ] ) ); - - } - - } - - return material; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ObjectLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.ObjectLoader.prototype = { - - constructor: THREE.ObjectLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var geometries = this.parseGeometries( json.geometries ); - var materials = this.parseMaterials( json.materials ); - var object = this.parseObject( json.object, geometries, materials ); - - return object; - - }, - - parseGeometries: function ( json ) { - - var geometries = {}; - - if ( json !== undefined ) { - - var geometryLoader = new THREE.JSONLoader(); - var bufferGeometryLoader = new THREE.BufferGeometryLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var geometry; - var data = json[ i ]; - - switch ( data.type ) { - - case 'PlaneGeometry': - - geometry = new THREE.PlaneGeometry( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); - - break; - - case 'CircleGeometry': - - geometry = new THREE.CircleGeometry( - data.radius, - data.segments - ); - - break; - - case 'CubeGeometry': - - geometry = new THREE.CubeGeometry( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); - - break; - - case 'CylinderGeometry': - - geometry = new THREE.CylinderGeometry( - data.radiusTop, - data.radiusBottom, - data.height, - data.radiusSegments, - data.heightSegments, - data.openEnded - ); - - break; - - case 'SphereGeometry': - - geometry = new THREE.SphereGeometry( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'IcosahedronGeometry': - - geometry = new THREE.IcosahedronGeometry( - data.radius, - data.detail - ); - - break; - - case 'TorusGeometry': - - geometry = new THREE.TorusGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); - - break; - - case 'TorusKnotGeometry': - - geometry = new THREE.TorusKnotGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.p, - data.q, - data.heightScale - ); - - break; - - case 'BufferGeometry': - - geometry = bufferGeometryLoader.parse( data.data ); - - break; - - case 'Geometry': - - geometry = geometryLoader.parse( data.data ).geometry; - - break; - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - }, - - parseMaterials: function ( json ) { - - var materials = {}; - - if ( json !== undefined ) { - - var loader = new THREE.MaterialLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - var material = loader.parse( data ); - - material.uuid = data.uuid; - - if ( data.name !== undefined ) material.name = data.name; - - materials[ data.uuid ] = material; - - } - - } - - return materials; - - }, - - parseObject: function () { - - var matrix = new THREE.Matrix4(); - - return function ( data, geometries, materials ) { - - var object; - - switch ( data.type ) { - - case 'Scene': - - object = new THREE.Scene(); - - break; - - case 'PerspectiveCamera': - - object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - break; - - case 'OrthographicCamera': - - object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - break; - - case 'AmbientLight': - - object = new THREE.AmbientLight( data.color ); - - break; - - case 'DirectionalLight': - - object = new THREE.DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new THREE.PointLight( data.color, data.intensity, data.distance ); - - break; - - case 'SpotLight': - - object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent ); - - break; - - case 'HemisphereLight': - - object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'Mesh': - - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); - - } - - if ( material === undefined ) { - - console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); - - } - - object = new THREE.Mesh( geometry, material ); - - break; - - default: - - object = new THREE.Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { - - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; - - if ( data.children !== undefined ) { - - for ( var child in data.children ) { - - object.add( this.parseObject( data.children[ child ], geometries, materials ) ); - - } - - } - - return object; - - } - - }() - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SceneLoader = function () { - - this.onLoadStart = function () {}; - this.onLoadProgress = function() {}; - this.onLoadComplete = function () {}; - - this.callbackSync = function () {}; - this.callbackProgress = function () {}; - - this.geometryHandlers = {}; - this.hierarchyHandlers = {}; - - this.addGeometryHandler( "ascii", THREE.JSONLoader ); - -}; - -THREE.SceneLoader.prototype = { - - constructor: THREE.SceneLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - scope.parse( JSON.parse( text ), onLoad, url ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - addGeometryHandler: function ( typeID, loaderClass ) { - - this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; - - }, - - addHierarchyHandler: function ( typeID, loaderClass ) { - - this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; - - }, - - parse: function ( json, callbackFinished, url ) { - - var scope = this; - - var urlBase = THREE.Loader.prototype.extractUrlBase( url ); - - var geometry, material, camera, fog, - texture, images, color, - light, hex, intensity, - counter_models, counter_textures, - total_models, total_textures, - result; - - var target_array = []; - - var data = json; - - // async geometry loaders - - for ( var typeID in this.geometryHandlers ) { - - var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; - this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); - - } - - // async hierachy loaders - - for ( var typeID in this.hierarchyHandlers ) { - - var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; - this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); - - } - - counter_models = 0; - counter_textures = 0; - - result = { - - scene: new THREE.Scene(), - geometries: {}, - face_materials: {}, - materials: {}, - textures: {}, - objects: {}, - cameras: {}, - lights: {}, - fogs: {}, - empties: {}, - groups: {} - - }; - - if ( data.transform ) { - - var position = data.transform.position, - rotation = data.transform.rotation, - scale = data.transform.scale; - - if ( position ) { - - result.scene.position.fromArray( position ); - - } - - if ( rotation ) { - - result.scene.rotation.fromArray( rotation ); - - } - - if ( scale ) { - - result.scene.scale.fromArray( scale ); - - } - - if ( position || rotation || scale ) { - - result.scene.updateMatrix(); - result.scene.updateMatrixWorld(); - - } - - } - - function get_url( source_url, url_type ) { - - if ( url_type == "relativeToHTML" ) { - - return source_url; - - } else { - - return urlBase + "/" + source_url; - - } - - }; - - // toplevel loader function, delegates to handle_children - - function handle_objects() { - - handle_children( result.scene, data.objects ); - - } - - // handle all the children from the loaded json and attach them to given parent - - function handle_children( parent, children ) { - - var mat, dst, pos, rot, scl, quat; - - for ( var objID in children ) { - - // check by id if child has already been handled, - // if not, create new object - - var object = result.objects[ objID ]; - var objJSON = children[ objID ]; - - if ( object === undefined ) { - - // meshes - - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { - - if ( objJSON.loading === undefined ) { - - var reservedTypes = { - "type": 1, "url": 1, "material": 1, - "position": 1, "rotation": 1, "scale" : 1, - "visible": 1, "children": 1, "userData": 1, - "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 - }; - - var loaderParameters = {}; - - for ( var parType in objJSON ) { - - if ( ! ( parType in reservedTypes ) ) { - - loaderParameters[ parType ] = objJSON[ parType ]; - - } - - } - - material = result.materials[ objJSON.material ]; - - objJSON.loading = true; - - var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; - - // ColladaLoader - - if ( loader.options ) { - - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); - - // UTF8Loader - // OBJLoader - - } else { - - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); - - } - - } - - } else if ( objJSON.geometry !== undefined ) { - - geometry = result.geometries[ objJSON.geometry ]; - - // geometry already loaded - - if ( geometry ) { - - var needsTangents = false; - - material = result.materials[ objJSON.material ]; - needsTangents = material instanceof THREE.ShaderMaterial; - - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - mat = objJSON.matrix; - quat = objJSON.quaternion; - - // use materials from the model file - // if there is no material specified in the object - - if ( ! objJSON.material ) { - - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); - - } - - // use materials from the model file - // if there is just empty face material - // (must create new material as each model has its own face material) - - if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { - - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); - - } - - if ( material instanceof THREE.MeshFaceMaterial ) { - - for ( var i = 0; i < material.materials.length; i ++ ) { - - needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); - - } - - } - - if ( needsTangents ) { - - geometry.computeTangents(); - - } - - if ( objJSON.skin ) { - - object = new THREE.SkinnedMesh( geometry, material ); - - } else if ( objJSON.morph ) { - - object = new THREE.MorphAnimMesh( geometry, material ); - - if ( objJSON.duration !== undefined ) { - - object.duration = objJSON.duration; - - } - - if ( objJSON.time !== undefined ) { - - object.time = objJSON.time; - - } - - if ( objJSON.mirroredLoop !== undefined ) { - - object.mirroredLoop = objJSON.mirroredLoop; - - } - - if ( material.morphNormals ) { - - geometry.computeMorphNormals(); - - } - - } else { - - object = new THREE.Mesh( geometry, material ); - - } - - object.name = objID; - - if ( mat ) { - - object.matrixAutoUpdate = false; - object.matrix.set( - mat[0], mat[1], mat[2], mat[3], - mat[4], mat[5], mat[6], mat[7], - mat[8], mat[9], mat[10], mat[11], - mat[12], mat[13], mat[14], mat[15] - ); - - } else { - - object.position.fromArray( pos ); - - if ( quat ) { - - object.quaternion.fromArray( quat ); - - } else { - - object.rotation.fromArray( rot ); - - } - - object.scale.fromArray( scl ); - - } - - object.visible = objJSON.visible; - object.castShadow = objJSON.castShadow; - object.receiveShadow = objJSON.receiveShadow; - - parent.add( object ); - - result.objects[ objID ] = object; - - } - - // lights - - } else if ( objJSON.type === "DirectionalLight" || objJSON.type === "PointLight" || objJSON.type === "AmbientLight" ) { - - hex = ( objJSON.color !== undefined ) ? objJSON.color : 0xffffff; - intensity = ( objJSON.intensity !== undefined ) ? objJSON.intensity : 1; - - if ( objJSON.type === "DirectionalLight" ) { - - pos = objJSON.direction; - - light = new THREE.DirectionalLight( hex, intensity ); - light.position.fromArray( pos ); - - if ( objJSON.target ) { - - target_array.push( { "object": light, "targetName" : objJSON.target } ); - - // kill existing default target - // otherwise it gets added to scene when parent gets added - - light.target = null; - - } - - } else if ( objJSON.type === "PointLight" ) { - - pos = objJSON.position; - dst = objJSON.distance; - - light = new THREE.PointLight( hex, intensity, dst ); - light.position.fromArray( pos ); - - } else if ( objJSON.type === "AmbientLight" ) { - - light = new THREE.AmbientLight( hex ); - - } - - parent.add( light ); - - light.name = objID; - result.lights[ objID ] = light; - result.objects[ objID ] = light; - - // cameras - - } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { - - pos = objJSON.position; - rot = objJSON.rotation; - quat = objJSON.quaternion; - - if ( objJSON.type === "PerspectiveCamera" ) { - - camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); - - } else if ( objJSON.type === "OrthographicCamera" ) { - - camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); - - } - - camera.name = objID; - camera.position.fromArray( pos ); - - if ( quat !== undefined ) { - - camera.quaternion.fromArray( quat ); - - } else if ( rot !== undefined ) { - - camera.rotation.fromArray( rot ); - - } - - parent.add( camera ); - - result.cameras[ objID ] = camera; - result.objects[ objID ] = camera; - - // pure Object3D - - } else { - - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - quat = objJSON.quaternion; - - object = new THREE.Object3D(); - object.name = objID; - object.position.fromArray( pos ); - - if ( quat ) { - - object.quaternion.fromArray( quat ); - - } else { - - object.rotation.fromArray( rot ); - - } - - object.scale.fromArray( scl ); - object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; - - parent.add( object ); - - result.objects[ objID ] = object; - result.empties[ objID ] = object; - - } - - if ( object ) { - - if ( objJSON.userData !== undefined ) { - - for ( var key in objJSON.userData ) { - - var value = objJSON.userData[ key ]; - object.userData[ key ] = value; - - } - - } - - if ( objJSON.groups !== undefined ) { - - for ( var i = 0; i < objJSON.groups.length; i ++ ) { - - var groupID = objJSON.groups[ i ]; - - if ( result.groups[ groupID ] === undefined ) { - - result.groups[ groupID ] = []; - - } - - result.groups[ groupID ].push( objID ); - - } - - } - - } - - } - - if ( object !== undefined && objJSON.children !== undefined ) { - - handle_children( object, objJSON.children ); - - } - - } - - }; - - function handle_mesh( geo, mat, id ) { - - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; - handle_objects(); - - }; - - function handle_hierarchy( node, id, parent, material, obj ) { - - var p = obj.position; - var r = obj.rotation; - var q = obj.quaternion; - var s = obj.scale; - - node.position.fromArray( p ); - - if ( q ) { - - node.quaternion.fromArray( q ); - - } else { - - node.rotation.fromArray( r ); - - } - - node.scale.fromArray( s ); - - // override children materials - // if object material was specified in JSON explicitly - - if ( material ) { - - node.traverse( function ( child ) { - - child.material = material; - - } ); - - } - - // override children visibility - // with root node visibility as specified in JSON - - var visible = ( obj.visible !== undefined ) ? obj.visible : true; - - node.traverse( function ( child ) { - - child.visible = visible; - - } ); - - parent.add( node ); - - node.name = id; - - result.objects[ id ] = node; - handle_objects(); - - }; - - function create_callback_geometry( id ) { - - return function ( geo, mat ) { - - geo.name = id; - - handle_mesh( geo, mat, id ); - - counter_models -= 1; - - scope.onLoadComplete(); - - async_callback_gate(); - - } - - }; - - function create_callback_hierachy( id, parent, material, obj ) { - - return function ( event ) { - - var result; - - // loaders which use EventDispatcher - - if ( event.content ) { - - result = event.content; - - // ColladaLoader - - } else if ( event.dae ) { - - result = event.scene; - - - // UTF8Loader - - } else { - - result = event; - - } - - handle_hierarchy( result, id, parent, material, obj ); - - counter_models -= 1; - - scope.onLoadComplete(); - - async_callback_gate(); - - } - - }; - - function create_callback_embed( id ) { - - return function ( geo, mat ) { - - geo.name = id; - - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; - - } - - }; - - function async_callback_gate() { - - var progress = { - - totalModels : total_models, - totalTextures : total_textures, - loadedModels : total_models - counter_models, - loadedTextures : total_textures - counter_textures - - }; - - scope.callbackProgress( progress, result ); - - scope.onLoadProgress(); - - if ( counter_models === 0 && counter_textures === 0 ) { - - finalize(); - callbackFinished( result ); - - } - - }; - - function finalize() { - - // take care of targets which could be asynchronously loaded objects - - for ( var i = 0; i < target_array.length; i ++ ) { - - var ta = target_array[ i ]; - - var target = result.objects[ ta.targetName ]; - - if ( target ) { - - ta.object.target = target; - - } else { - - // if there was error and target of specified name doesn't exist in the scene file - // create instead dummy target - // (target must be added to scene explicitly as parent is already added) - - ta.object.target = new THREE.Object3D(); - result.scene.add( ta.object.target ); - - } - - ta.object.target.userData.targetInverse = ta.object; - - } - - }; - - var callbackTexture = function ( count ) { - - counter_textures -= count; - async_callback_gate(); - - scope.onLoadComplete(); - - }; - - // must use this instead of just directly calling callbackTexture - // because of closure in the calling context loop - - var generateTextureCallback = function ( count ) { - - return function () { - - callbackTexture( count ); - - }; - - }; - - function traverse_json_hierarchy( objJSON, callback ) { - - callback( objJSON ); - - if ( objJSON.children !== undefined ) { - - for ( var objChildID in objJSON.children ) { - - traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); - - } - - } - - }; - - // first go synchronous elements - - // fogs - - var fogID, fogJSON; - - for ( fogID in data.fogs ) { - - fogJSON = data.fogs[ fogID ]; - - if ( fogJSON.type === "linear" ) { - - fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); - - } else if ( fogJSON.type === "exp2" ) { - - fog = new THREE.FogExp2( 0x000000, fogJSON.density ); - - } - - color = fogJSON.color; - fog.color.setRGB( color[0], color[1], color[2] ); - - result.fogs[ fogID ] = fog; - - } - - // now come potentially asynchronous elements - - // geometries - - // count how many geometries will be loaded asynchronously - - var geoID, geoJSON; - - for ( geoID in data.geometries ) { - - geoJSON = data.geometries[ geoID ]; - - if ( geoJSON.type in this.geometryHandlers ) { - - counter_models += 1; - - scope.onLoadStart(); - - } - - } - - // count how many hierarchies will be loaded asynchronously - - for ( var objID in data.objects ) { - - traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { - - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { - - counter_models += 1; - - scope.onLoadStart(); - - } - - }); - - } - - total_models = counter_models; - - for ( geoID in data.geometries ) { - - geoJSON = data.geometries[ geoID ]; - - if ( geoJSON.type === "cube" ) { - - geometry = new THREE.CubeGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "plane" ) { - - geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "sphere" ) { - - geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "cylinder" ) { - - geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "torus" ) { - - geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "icosahedron" ) { - - geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type in this.geometryHandlers ) { - - var loaderParameters = {}; - - for ( var parType in geoJSON ) { - - if ( parType !== "type" && parType !== "url" ) { - - loaderParameters[ parType ] = geoJSON[ parType ]; - - } - - } - - var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; - loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); - - } else if ( geoJSON.type === "embedded" ) { - - var modelJson = data.embeds[ geoJSON.id ], - texture_path = ""; - - // pass metadata along to jsonLoader so it knows the format version - - modelJson.metadata = data.metadata; - - if ( modelJson ) { - - var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; - var model = jsonLoader.parse( modelJson, texture_path ); - create_callback_embed( geoID )( model.geometry, model.materials ); - - } - - } - - } - - // textures - - // count how many textures will be loaded asynchronously - - var textureID, textureJSON; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.url instanceof Array ) { - - counter_textures += textureJSON.url.length; - - for( var n = 0; n < textureJSON.url.length; n ++ ) { - - scope.onLoadStart(); - - } - - } else { - - counter_textures += 1; - - scope.onLoadStart(); - - } - - } - - total_textures = counter_textures; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { - - textureJSON.mapping = new THREE[ textureJSON.mapping ](); - - } - - if ( textureJSON.url instanceof Array ) { - - var count = textureJSON.url.length; - var url_array = []; - - for( var i = 0; i < count; i ++ ) { - - url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); - - } - - var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } else { - - texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } - - } else { - - var isCompressed = /\.dds$/i.test( textureJSON.url ); - var fullUrl = get_url( textureJSON.url, data.urlBaseType ); - var textureCallback = generateTextureCallback( 1 ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } else { - - texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } - - if ( THREE[ textureJSON.minFilter ] !== undefined ) - texture.minFilter = THREE[ textureJSON.minFilter ]; - - if ( THREE[ textureJSON.magFilter ] !== undefined ) - texture.magFilter = THREE[ textureJSON.magFilter ]; - - if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; - - if ( textureJSON.repeat ) { - - texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); - - if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; - if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - - } - - if ( textureJSON.offset ) { - - texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); - - } - - // handle wrap after repeat so that default repeat can be overriden - - if ( textureJSON.wrap ) { - - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } - - if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; - if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; - - } - - } - - result.textures[ textureID ] = texture; - - } - - // materials - - var matID, matJSON; - var parID; - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - for ( parID in matJSON.parameters ) { - - if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { - - matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; - - } else if ( parID === "shading" ) { - - matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; - - } else if ( parID === "side" ) { - - if ( matJSON.parameters[ parID ] == "double" ) { - - matJSON.parameters[ parID ] = THREE.DoubleSide; - - } else if ( matJSON.parameters[ parID ] == "back" ) { - - matJSON.parameters[ parID ] = THREE.BackSide; - - } else { - - matJSON.parameters[ parID ] = THREE.FrontSide; - - } - - } else if ( parID === "blending" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; - - } else if ( parID === "combine" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; - - } else if ( parID === "vertexColors" ) { - - if ( matJSON.parameters[ parID ] == "face" ) { - - matJSON.parameters[ parID ] = THREE.FaceColors; - - // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false - - } else if ( matJSON.parameters[ parID ] ) { - - matJSON.parameters[ parID ] = THREE.VertexColors; - - } - - } else if ( parID === "wrapRGB" ) { - - var v3 = matJSON.parameters[ parID ]; - matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); - - } - - } - - if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { - - matJSON.parameters.transparent = true; - - } - - if ( matJSON.parameters.normalMap ) { - - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - var diffuse = matJSON.parameters.color; - var specular = matJSON.parameters.specular; - var ambient = matJSON.parameters.ambient; - var shininess = matJSON.parameters.shininess; - - uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; - - if ( matJSON.parameters.normalScale ) { - - uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); - - } - - if ( matJSON.parameters.map ) { - - uniforms[ "tDiffuse" ].value = matJSON.parameters.map; - uniforms[ "enableDiffuse" ].value = true; - - } - - if ( matJSON.parameters.envMap ) { - - uniforms[ "tCube" ].value = matJSON.parameters.envMap; - uniforms[ "enableReflection" ].value = true; - uniforms[ "uReflectivity" ].value = matJSON.parameters.reflectivity; - - } - - if ( matJSON.parameters.lightMap ) { - - uniforms[ "tAO" ].value = matJSON.parameters.lightMap; - uniforms[ "enableAO" ].value = true; - - } - - if ( matJSON.parameters.specularMap ) { - - uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; - uniforms[ "enableSpecular" ].value = true; - - } - - if ( matJSON.parameters.displacementMap ) { - - uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; - uniforms[ "enableDisplacement" ].value = true; - - uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; - uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; - - } - - uniforms[ "uDiffuseColor" ].value.setHex( diffuse ); - uniforms[ "uSpecularColor" ].value.setHex( specular ); - uniforms[ "uAmbientColor" ].value.setHex( ambient ); - - uniforms[ "uShininess" ].value = shininess; - - if ( matJSON.parameters.opacity ) { - - uniforms[ "uOpacity" ].value = matJSON.parameters.opacity; - - } - - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - - material = new THREE.ShaderMaterial( parameters ); - - } else { - - material = new THREE[ matJSON.type ]( matJSON.parameters ); - - } - - material.name = matID; - - result.materials[ matID ] = material; - - } - - // second pass through all materials to initialize MeshFaceMaterials - // that could be referring to other materials out of order - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - if ( matJSON.parameters.materials ) { - - var materialArray = []; - - for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { - - var label = matJSON.parameters.materials[ i ]; - materialArray.push( result.materials[ label ] ); - - } - - result.materials[ matID ].materials = materialArray; - - } - - } - - // objects ( synchronous init of procedural primitives ) - - handle_objects(); - - // defaults - - if ( result.cameras && data.defaults.camera ) { - - result.currentCamera = result.cameras[ data.defaults.camera ]; - - } - - if ( result.fogs && data.defaults.fog ) { - - result.scene.fog = result.fogs[ data.defaults.fog ]; - - } - - // synchronous callback - - scope.callbackSync( result ); - - // just in case there are no async elements - - async_callback_gate(); - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.TextureLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.TextureLoader.prototype = { - - constructor: THREE.TextureLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.ImageLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( image ) { - - var texture = new THREE.Texture( image ); - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Material = function () { - - this.id = THREE.MaterialIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.side = THREE.FrontSide; - - this.opacity = 1; - this.transparent = false; - - this.blending = THREE.NormalBlending; - - this.blendSrc = THREE.SrcAlphaFactor; - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - - this.depthTest = true; - this.depthWrite = true; - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.alphaTest = 0; - - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - - this.visible = true; - - this.needsUpdate = true; - -}; - -THREE.Material.prototype = { - - constructor: THREE.Material, - - setValues: function ( values ) { - - if ( values === undefined ) return; - - for ( var key in values ) { - - var newValue = values[ key ]; - - if ( newValue === undefined ) { - - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); - continue; - - } - - if ( key in this ) { - - var currentValue = this[ key ]; - - if ( currentValue instanceof THREE.Color ) { - - currentValue.set( newValue ); - - } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { - - currentValue.copy( newValue ); - - } else if ( key == 'overdraw') { - - // ensure overdraw is backwards-compatable with legacy boolean type - this[ key ] = Number(newValue); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - }, - - clone: function ( material ) { - - if ( material === undefined ) material = new THREE.Material(); - - material.name = this.name; - - material.side = this.side; - - material.opacity = this.opacity; - material.transparent = this.transparent; - - material.blending = this.blending; - - material.blendSrc = this.blendSrc; - material.blendDst = this.blendDst; - material.blendEquation = this.blendEquation; - - material.depthTest = this.depthTest; - material.depthWrite = this.depthWrite; - - material.polygonOffset = this.polygonOffset; - material.polygonOffsetFactor = this.polygonOffsetFactor; - material.polygonOffsetUnits = this.polygonOffsetUnits; - - material.alphaTest = this.alphaTest; - - material.overdraw = this.overdraw; - - material.visible = this.visible; - - return material; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - -THREE.MaterialIdCount = 0; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * opacity: <float>, - * - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * linewidth: <float>, - * linecap: "round", - * linejoin: "round", - * - * vertexColors: <bool> - * - * fog: <bool> - * } - */ - -THREE.LineBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineBasicMaterial.prototype.clone = function () { - - var material = new THREE.LineBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - material.linecap = this.linecap; - material.linejoin = this.linejoin; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * opacity: <float>, - * - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * linewidth: <float>, - * - * scale: <float>, - * dashSize: <float>, - * gapSize: <float>, - * - * vertexColors: <bool> - * - * fog: <bool> - * } - */ - -THREE.LineDashedMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineDashedMaterial.prototype.clone = function () { - - var material = new THREE.LineDashedMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - - material.scale = this.scale; - material.dashSize = this.dashSize; - material.gapSize = this.gapSize; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * opacity: <float>, - * map: new THREE.Texture( <Image> ), - * - * lightMap: new THREE.Texture( <Image> ), - * - * specularMap: new THREE.Texture( <Image> ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: <float>, - * refractionRatio: <float>, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float>, - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: <bool>, - * morphTargets: <bool>, - * - * fog: <bool> - * } - */ - -THREE.MeshBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshBasicMaterial.prototype.clone = function () { - - var material = new THREE.MeshBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * ambient: <hex>, - * emissive: <hex>, - * opacity: <float>, - * - * map: new THREE.Texture( <Image> ), - * - * lightMap: new THREE.Texture( <Image> ), - * - * specularMap: new THREE.Texture( <Image> ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: <float>, - * refractionRatio: <float>, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float>, - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: <bool>, - * morphTargets: <bool>, - * morphNormals: <bool>, - * - * fog: <bool> - * } - */ + if ( m.mapSpecular && texturePath ) { -THREE.MeshLambertMaterial = function ( parameters ) { + create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - THREE.Material.call( this ); + } - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); - this.emissive = new THREE.Color( 0x000000 ); + if ( m.mapAlpha && texturePath ) { - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - this.map = null; + } - this.lightMap = null; + // - this.specularMap = null; + if ( m.mapBumpScale ) { - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + mpars.bumpScale = m.mapBumpScale; - this.fog = true; + } - this.shading = THREE.SmoothShading; + if ( m.mapNormalFactor ) { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + mpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor ); - this.vertexColors = THREE.NoColors; + } - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + var material = new THREE[ mtype ]( mpars ); - this.setValues( parameters ); + if ( m.DbgName !== undefined ) material.name = m.DbgName; -}; + return material; -THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); + } -THREE.MeshLambertMaterial.prototype.clone = function () { +}; - var material = new THREE.MeshLambertMaterial(); +THREE.Loader.Handlers = { - THREE.Material.prototype.clone.call( this, material ); + handlers: [], - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); + add: function ( regex, loader ) { - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); + this.handlers.push( regex, loader ); - material.map = this.map; + }, - material.lightMap = this.lightMap; + get: function ( file ) { - material.specularMap = this.specularMap; + for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) { - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; + var regex = this.handlers[ i ]; + var loader = this.handlers[ i + 1 ]; - material.fog = this.fog; + if ( regex.test( file ) ) { - material.shading = this.shading; + return loader; - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; + } - material.vertexColors = this.vertexColors; + } - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + return null; - return material; + } }; +// File:src/loaders/XHRLoader.js + /** * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * ambient: <hex>, - * emissive: <hex>, - * specular: <hex>, - * shininess: <float>, - * opacity: <float>, - * - * map: new THREE.Texture( <Image> ), - * - * lightMap: new THREE.Texture( <Image> ), - * - * bumpMap: new THREE.Texture( <Image> ), - * bumpScale: <float>, - * - * normalMap: new THREE.Texture( <Image> ), - * normalScale: <Vector2>, - * - * specularMap: new THREE.Texture( <Image> ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: <float>, - * refractionRatio: <float>, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float>, - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: <bool>, - * morphTargets: <bool>, - * morphNormals: <bool>, - * - * fog: <bool> - * } */ -THREE.MeshPhongMaterial = function ( parameters ) { +THREE.XHRLoader = function ( manager ) { - THREE.Material.call( this ); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); - this.emissive = new THREE.Color( 0x000000 ); - this.specular = new THREE.Color( 0x111111 ); - this.shininess = 30; +}; - this.metal = false; - this.perPixel = true; +THREE.XHRLoader.prototype = { - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + constructor: THREE.XHRLoader, - this.map = null; + load: function ( url, onLoad, onProgress, onError ) { - this.lightMap = null; + var scope = this; - this.bumpMap = null; - this.bumpScale = 1; + var cached = THREE.Cache.get( url ); - this.normalMap = null; - this.normalScale = new THREE.Vector2( 1, 1 ); + if ( cached !== undefined ) { - this.specularMap = null; + if ( onLoad ) onLoad( cached ); + return; - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + } - this.fog = true; + var request = new XMLHttpRequest(); + request.open( 'GET', url, true ); - this.shading = THREE.SmoothShading; + request.addEventListener( 'load', function ( event ) { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + THREE.Cache.add( url, this.response ); - this.vertexColors = THREE.NoColors; + if ( onLoad ) onLoad( this.response ); - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + scope.manager.itemEnd( url ); - this.setValues( parameters ); + }, false ); -}; + if ( onProgress !== undefined ) { -THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); + request.addEventListener( 'progress', function ( event ) { -THREE.MeshPhongMaterial.prototype.clone = function () { + onProgress( event ); - var material = new THREE.MeshPhongMaterial(); + }, false ); - THREE.Material.prototype.clone.call( this, material ); + } - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); - material.specular.copy( this.specular ); - material.shininess = this.shininess; + if ( onError !== undefined ) { - material.metal = this.metal; - material.perPixel = this.perPixel; + request.addEventListener( 'error', function ( event ) { - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); + onError( event ); - material.map = this.map; + }, false ); - material.lightMap = this.lightMap; + } - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; + if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + if ( this.responseType !== undefined ) request.responseType = this.responseType; - material.normalMap = this.normalMap; - material.normalScale.copy( this.normalScale ); + request.send( null ); - material.specularMap = this.specularMap; + scope.manager.itemStart( url ); - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; + }, - material.fog = this.fog; + setResponseType: function ( value ) { - material.shading = this.shading; + this.responseType = value; - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; + }, - material.vertexColors = this.vertexColors; + setCrossOrigin: function ( value ) { - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + this.crossOrigin = value; - return material; + } }; +// File:src/loaders/ImageLoader.js + /** * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * opacity: <float>, - * - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float> - * } */ -THREE.MeshDepthMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.wireframe = false; - this.wireframeLinewidth = 1; +THREE.ImageLoader = function ( manager ) { - this.setValues( parameters ); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; -THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshDepthMaterial.prototype.clone = function () { - - var material = new THREE.MeshDepthMaterial(); - - THREE.Material.prototype.clone.call( this, material ); +THREE.ImageLoader.prototype = { - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; + constructor: THREE.ImageLoader, - return material; + load: function ( url, onLoad, onProgress, onError ) { -}; + var scope = this; -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * opacity: <float>, - * - * shading: THREE.FlatShading, - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float> - * } - */ + var cached = THREE.Cache.get( url ); -THREE.MeshNormalMaterial = function ( parameters ) { + if ( cached !== undefined ) { - THREE.Material.call( this, parameters ); + onLoad( cached ); + return; - this.shading = THREE.FlatShading; + } - this.wireframe = false; - this.wireframeLinewidth = 1; + var image = document.createElement( 'img' ); - this.morphTargets = false; + image.addEventListener( 'load', function ( event ) { - this.setValues( parameters ); + THREE.Cache.add( url, this ); -}; + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); -THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); + }, false ); -THREE.MeshNormalMaterial.prototype.clone = function () { + if ( onProgress !== undefined ) { - var material = new THREE.MeshNormalMaterial(); + image.addEventListener( 'progress', function ( event ) { - THREE.Material.prototype.clone.call( this, material ); + onProgress( event ); - material.shading = this.shading; + }, false ); - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; + } - return material; + if ( onError !== undefined ) { -}; + image.addEventListener( 'error', function ( event ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + onError( event ); -THREE.MeshFaceMaterial = function ( materials ) { + }, false ); - this.materials = materials instanceof Array ? materials : []; + } -}; + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + image.src = url; + + scope.manager.itemStart( url ); -THREE.MeshFaceMaterial.prototype.clone = function () { + return image; - var material = new THREE.MeshFaceMaterial(); + }, - for ( var i = 0; i < this.materials.length; i ++ ) { + setCrossOrigin: function ( value ) { - material.materials.push( this.materials[ i ].clone() ); + this.crossOrigin = value; } - return material; +} -}; +// File:src/loaders/JSONLoader.js /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * opacity: <float>, - * map: new THREE.Texture( <Image> ), - * - * size: <float>, - * - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * vertexColors: <bool>, - * - * fog: <bool> - * } */ -THREE.ParticleSystemMaterial = function ( parameters ) { +THREE.JSONLoader = function ( showStatus ) { - THREE.Material.call( this ); + THREE.Loader.call( this, showStatus ); - this.color = new THREE.Color( 0xffffff ); + this.withCredentials = false; - this.map = null; +}; - this.size = 1; - this.sizeAttenuation = true; +THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); +THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; - this.vertexColors = false; +THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { - this.fog = true; + // todo: unify load API to for easier SceneLoader use - this.setValues( parameters ); + texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url ); + + this.onLoadStart(); + this.loadAjaxJSON( this, url, callback, texturePath ); }; -THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { -THREE.ParticleSystemMaterial.prototype.clone = function () { + var xhr = new XMLHttpRequest(); - var material = new THREE.ParticleSystemMaterial(); + var length = 0; - THREE.Material.prototype.clone.call( this, material ); + xhr.onreadystatechange = function () { - material.color.copy( this.color ); + if ( xhr.readyState === xhr.DONE ) { - material.map = this.map; + if ( xhr.status === 200 || xhr.status === 0 ) { - material.size = this.size; - material.sizeAttenuation = this.sizeAttenuation; + if ( xhr.responseText ) { - material.vertexColors = this.vertexColors; + var json = JSON.parse( xhr.responseText ); + var metadata = json.metadata; - material.fog = this.fog; + if ( metadata !== undefined ) { - return material; + if ( metadata.type === 'object' ) { -}; + THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; -// backwards compatibility + } -THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; + if ( metadata.type === 'scene' ) { -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * fragmentShader: <string>, - * vertexShader: <string>, - * - * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, - * - * defines: { "label" : "value" }, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * wireframe: <boolean>, - * wireframeLinewidth: <float>, - * - * lights: <bool>, - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: <bool>, - * morphTargets: <bool>, - * morphNormals: <bool>, - * - * fog: <bool> - * } - */ + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; -THREE.ShaderMaterial = function ( parameters ) { + } - THREE.Material.call( this ); + } - this.fragmentShader = "void main() {}"; - this.vertexShader = "void main() {}"; - this.uniforms = {}; - this.defines = {}; - this.attributes = null; + var result = context.parse( json, texturePath ); + callback( result.geometry, result.materials ); - this.shading = THREE.SmoothShading; + } else { - this.linewidth = 1; + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' ); - this.wireframe = false; - this.wireframeLinewidth = 1; + } - this.fog = false; // set to use scene fog + // in context of more complex asset initialization + // do not block on single failed file + // maybe should go even one more level up - this.lights = false; // set to use scene lights + context.onLoadComplete(); - this.vertexColors = THREE.NoColors; // set to use "color" attribute stream + } else { - this.skinning = false; // set to use skinning attribute streams + THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' ); - this.morphTargets = false; // set to use morph targets - this.morphNormals = false; // set to use morph normals + } - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - "color" : [ 1, 1, 1], - "uv" : [ 0, 0 ], - "uv2" : [ 0, 0 ] - }; + } else if ( xhr.readyState === xhr.LOADING ) { - // By default, bind position to attribute index 0. In WebGL, attribute 0 - // should always be used to avoid potentially expensive emulation. - this.index0AttributeName = "position"; + if ( callbackProgress ) { - this.setValues( parameters ); + if ( length === 0 ) { -}; + length = xhr.getResponseHeader( 'Content-Length' ); -THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); + } -THREE.ShaderMaterial.prototype.clone = function () { + callbackProgress( { total: length, loaded: xhr.responseText.length } ); - var material = new THREE.ShaderMaterial(); + } - THREE.Material.prototype.clone.call( this, material ); + } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { - material.fragmentShader = this.fragmentShader; - material.vertexShader = this.vertexShader; + if ( callbackProgress !== undefined ) { - material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); + length = xhr.getResponseHeader( 'Content-Length' ); - material.attributes = this.attributes; - material.defines = this.defines; + } - material.shading = this.shading; + } - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; + }; - material.fog = this.fog; + xhr.open( 'GET', url, true ); + xhr.withCredentials = this.withCredentials; + xhr.send( null ); - material.lights = this.lights; +}; - material.vertexColors = this.vertexColors; +THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - material.skinning = this.skinning; + var geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + parseModel( scale ); - return material; + parseSkin(); + parseMorphing( scale ); -}; + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: <hex>, - * opacity: <float>, - * map: new THREE.Texture( <Image> ), - * - * blending: THREE.NormalBlending, - * depthTest: <bool>, - * depthWrite: <bool>, - * - * useScreenCoordinates: <bool>, - * sizeAttenuation: <bool>, - * alignment: THREE.SpriteAlignment.center, - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2(), - * - * fog: <bool> - * } - */ + function parseModel( scale ) { -THREE.SpriteMaterial = function ( parameters ) { + function isBitSet( value, position ) { - THREE.Material.call( this ); + return value & ( 1 << position ); - // defaults + } - this.color = new THREE.Color( 0xffffff ); - this.map = new THREE.Texture(); + var i, j, fi, - this.useScreenCoordinates = true; - this.depthTest = !this.useScreenCoordinates; - this.sizeAttenuation = !this.useScreenCoordinates; - this.alignment = THREE.SpriteAlignment.center.clone(); + offset, zLength, - this.fog = false; + colorIndex, normalIndex, uvIndex, materialIndex, + + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, - this.uvOffset = new THREE.Vector2( 0, 0 ); - this.uvScale = new THREE.Vector2( 1, 1 ); + vertex, face, faceA, faceB, hex, normal, - // set parameters + uvLayer, uv, u, v, - this.setValues( parameters ); + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, - // override coupled defaults if not specified explicitly by parameters + nUvLayers = 0; - parameters = parameters || {}; + if ( json.uvs !== undefined ) { - if ( parameters.depthTest === undefined ) this.depthTest = !this.useScreenCoordinates; - if ( parameters.sizeAttenuation === undefined ) this.sizeAttenuation = !this.useScreenCoordinates; + // disregard empty arrays -}; + for ( i = 0; i < json.uvs.length; i ++ ) { -THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); + if ( json.uvs[ i ].length ) nUvLayers ++; -THREE.SpriteMaterial.prototype.clone = function () { + } - var material = new THREE.SpriteMaterial(); + for ( i = 0; i < nUvLayers; i ++ ) { - THREE.Material.prototype.clone.call( this, material ); + geometry.faceVertexUvs[ i ] = []; - material.color.copy( this.color ); - material.map = this.map; + } - material.useScreenCoordinates = this.useScreenCoordinates; - material.sizeAttenuation = this.sizeAttenuation; - material.alignment.copy( this.alignment ); + } - material.uvOffset.copy( this.uvOffset ); - material.uvScale.copy( this.uvScale ); + offset = 0; + zLength = vertices.length; - material.fog = this.fog; + while ( offset < zLength ) { - return material; + vertex = new THREE.Vector3(); -}; + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; -// Alignment enums + geometry.vertices.push( vertex ); -THREE.SpriteAlignment = {}; -THREE.SpriteAlignment.topLeft = new THREE.Vector2( 0.5, -0.5 ); -THREE.SpriteAlignment.topCenter = new THREE.Vector2( 0, -0.5 ); -THREE.SpriteAlignment.topRight = new THREE.Vector2( -0.5, -0.5 ); -THREE.SpriteAlignment.centerLeft = new THREE.Vector2( 0.5, 0 ); -THREE.SpriteAlignment.center = new THREE.Vector2( 0, 0 ); -THREE.SpriteAlignment.centerRight = new THREE.Vector2( -0.5, 0 ); -THREE.SpriteAlignment.bottomLeft = new THREE.Vector2( 0.5, 0.5 ); -THREE.SpriteAlignment.bottomCenter = new THREE.Vector2( 0, 0.5 ); -THREE.SpriteAlignment.bottomRight = new THREE.Vector2( -0.5, 0.5 ); + } -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * color: <hex>, - * program: <function>, - * opacity: <float>, - * blending: THREE.NormalBlending - * } - */ + offset = 0; + zLength = faces.length; -THREE.SpriteCanvasMaterial = function ( parameters ) { + while ( offset < zLength ) { - THREE.Material.call( this ); + type = faces[ offset ++ ]; - this.color = new THREE.Color( 0xffffff ); - this.program = function ( context, color ) {}; - this.setValues( parameters ); + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); -}; + // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); -THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); + if ( isQuad ) { -THREE.SpriteCanvasMaterial.prototype.clone = function () { + faceA = new THREE.Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; - var material = new THREE.SpriteCanvasMaterial(); + faceB = new THREE.Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; - THREE.Material.prototype.clone.call( this, material ); + offset += 4; - material.color.copy( this.color ); - material.program = this.program; + if ( hasMaterial ) { - return material; + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; -}; + } -// backwards compatibility + // to get face <=> uv index correspondence -THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ + fi = geometry.faces.length; -THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + if ( hasFaceVertexUv ) { - this.id = THREE.TextureIdCount ++; - this.uuid = THREE.Math.generateUUID(); + for ( i = 0; i < nUvLayers; i ++ ) { - this.name = ''; + uvLayer = json.uvs[ i ]; - this.image = image; - this.mipmaps = []; + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = [] - this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); + for ( j = 0; j < 4; j ++ ) { - this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + uvIndex = faces[ offset ++ ]; - this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + uv = new THREE.Vector2( u, v ); - this.format = format !== undefined ? format : THREE.RGBAFormat; - this.type = type !== undefined ? type : THREE.UnsignedByteType; + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.Vector2( 1, 1 ); + } - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + } - this.needsUpdate = false; - this.onUpdate = null; + } -}; + if ( hasFaceNormal ) { -THREE.Texture.prototype = { + normalIndex = faces[ offset ++ ] * 3; - constructor: THREE.Texture, + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - clone: function ( texture ) { + faceB.normal.copy( faceA.normal ); - if ( texture === undefined ) texture = new THREE.Texture(); + } - texture.image = this.image; - texture.mipmaps = this.mipmaps.slice(0); + if ( hasFaceVertexNormal ) { - texture.mapping = this.mapping; + for ( i = 0; i < 4; i ++ ) { - texture.wrapS = this.wrapS; - texture.wrapT = this.wrapT; + normalIndex = faces[ offset ++ ] * 3; - texture.magFilter = this.magFilter; - texture.minFilter = this.minFilter; + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - texture.anisotropy = this.anisotropy; - texture.format = this.format; - texture.type = this.type; + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); - texture.offset.copy( this.offset ); - texture.repeat.copy( this.repeat ); + } - texture.generateMipmaps = this.generateMipmaps; - texture.premultiplyAlpha = this.premultiplyAlpha; - texture.flipY = this.flipY; - texture.unpackAlignment = this.unpackAlignment; + } - return texture; - }, + if ( hasFaceColor ) { - dispose: function () { + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; - this.dispatchEvent( { type: 'dispose' } ); + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); - } + } -}; -THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); + if ( hasFaceVertexColor ) { -THREE.TextureIdCount = 0; + for ( i = 0; i < 4; i ++ ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; -THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + } - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; + } - this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); -}; + } else { -THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); + face = new THREE.Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; -THREE.CompressedTexture.prototype.clone = function () { + if ( hasMaterial ) { - var texture = new THREE.CompressedTexture(); + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; - THREE.Texture.prototype.clone.call( this, texture ); + } - return texture; + // to get face <=> uv index correspondence -}; + fi = geometry.faces.length; -/** - * @author alteredq / http://alteredqualia.com/ - */ + if ( hasFaceVertexUv ) { -THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + for ( i = 0; i < nUvLayers; i ++ ) { - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + uvLayer = json.uvs[ i ]; - this.image = { data: data, width: width, height: height }; + geometry.faceVertexUvs[ i ][ fi ] = []; -}; + for ( j = 0; j < 3; j ++ ) { -THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); + uvIndex = faces[ offset ++ ]; -THREE.DataTexture.prototype.clone = function () { + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - var texture = new THREE.DataTexture(); + uv = new THREE.Vector2( u, v ); - THREE.Texture.prototype.clone.call( this, texture ); + geometry.faceVertexUvs[ i ][ fi ].push( uv ); - return texture; + } -}; + } -/** - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.ParticleSystem = function ( geometry, material ) { + if ( hasFaceNormal ) { - THREE.Object3D.call( this ); + normalIndex = faces[ offset ++ ] * 3; - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - this.sortParticles = false; - this.frustumCulled = false; + } -}; + if ( hasFaceVertexNormal ) { -THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); + for ( i = 0; i < 3; i ++ ) { -THREE.ParticleSystem.prototype.clone = function ( object ) { + normalIndex = faces[ offset ++ ] * 3; - if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - object.sortParticles = this.sortParticles; + face.vertexNormals.push( normal ); - THREE.Object3D.prototype.clone.call( this, object ); + } - return object; + } -}; -/** - * @author mrdoob / http://mrdoob.com/ - */ + if ( hasFaceColor ) { -THREE.Line = function ( geometry, material, type ) { + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); - THREE.Object3D.call( this ); + } - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - this.type = ( type !== undefined ) ? type : THREE.LineStrip; + if ( hasFaceVertexColor ) { -}; + for ( i = 0; i < 3; i ++ ) { -THREE.LineStrip = 0; -THREE.LinePieces = 1; + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); -THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); + } -THREE.Line.prototype.clone = function ( object ) { + } - if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); + geometry.faces.push( face ); - THREE.Object3D.prototype.clone.call( this, object ); + } - return object; + } -}; + }; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ + function parseSkin() { + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; -THREE.Mesh = function ( geometry, material ) { + if ( json.skinWeights ) { - THREE.Object3D.call( this ); + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + var x = json.skinWeights[ i ]; + var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; + var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; + var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; - this.updateMorphTargets(); + geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); -}; + } -THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); + } -THREE.Mesh.prototype.updateMorphTargets = function () { + if ( json.skinIndices ) { - if ( this.geometry.morphTargets.length > 0 ) { + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - this.morphTargetBase = -1; - this.morphTargetForcedOrder = []; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + var a = json.skinIndices[ i ]; + var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; + var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; + var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; - for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { + geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; + } } - } + geometry.bones = json.bones; -}; + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { -THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { + THREE.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - if ( this.morphTargetDictionary[ name ] !== undefined ) { + } - return this.morphTargetDictionary[ name ]; - } + // could change this to json.animations[0] or remove completely - console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); + geometry.animation = json.animation; + geometry.animations = json.animations; - return 0; + }; -}; + function parseMorphing( scale ) { -THREE.Mesh.prototype.clone = function ( object ) { + if ( json.morphTargets !== undefined ) { - if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); + var i, l, v, vl, dstVertices, srcVertices; - THREE.Object3D.prototype.clone.call( this, object ); + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { - return object; + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; -}; + dstVertices = geometry.morphTargets[ i ].vertices; + srcVertices = json.morphTargets [ i ].vertices; -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { -THREE.Bone = function( belongsToSkin ) { + var vertex = new THREE.Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; - THREE.Object3D.call( this ); + dstVertices.push( vertex ); - this.skin = belongsToSkin; - this.skinMatrix = new THREE.Matrix4(); + } -}; + } -THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); + } + + if ( json.morphColors !== undefined ) { -THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { + var i, l, c, cl, dstColors, srcColors, color; - // update local + for ( i = 0, l = json.morphColors.length; i < l; i ++ ) { - if ( this.matrixAutoUpdate ) { + geometry.morphColors[ i ] = {}; + geometry.morphColors[ i ].name = json.morphColors[ i ].name; + geometry.morphColors[ i ].colors = []; - forceUpdate |= this.updateMatrix(); + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors [ i ].colors; - } + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { - // update skin matrix + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); - if ( forceUpdate || this.matrixWorldNeedsUpdate ) { + } - if( parentSkinMatrix ) { + } - this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); + } - } else { + }; - this.skinMatrix.copy( this.matrix ); + if ( json.materials === undefined || json.materials.length === 0 ) { - } + return { geometry: geometry }; - this.matrixWorldNeedsUpdate = false; - forceUpdate = true; + } else { - } + var materials = this.initMaterials( json.materials, texturePath ); - // update children + if ( this.needsTangents( materials ) ) { - var child, i, l = this.children.length; + geometry.computeTangents(); - for ( i = 0; i < l; i ++ ) { + } - this.children[ i ].update( this.skinMatrix, forceUpdate ); + return { geometry: geometry, materials: materials }; } }; +// File:src/loaders/LoadingManager.js /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ */ -THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - - THREE.Mesh.call( this, geometry, material ); - - // - - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; +THREE.LoadingManager = function ( onLoad, onProgress, onError ) { - // init bones + var scope = this; - this.identityMatrix = new THREE.Matrix4(); + var loaded = 0, total = 0; - this.bones = []; - this.boneMatrices = []; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; - var b, bone, gbone, p, q, s; + this.itemStart = function ( url ) { - if ( this.geometry && this.geometry.bones !== undefined ) { + total ++; - for ( b = 0; b < this.geometry.bones.length; b ++ ) { + }; - gbone = this.geometry.bones[ b ]; + this.itemEnd = function ( url ) { - p = gbone.pos; - q = gbone.rotq; - s = gbone.scl; + loaded ++; - bone = this.addBone(); + if ( scope.onProgress !== undefined ) { - bone.name = gbone.name; - bone.position.set( p[0], p[1], p[2] ); - bone.quaternion.set( q[0], q[1], q[2], q[3] ); + scope.onProgress( url, loaded, total ); - if ( s !== undefined ) { + } - bone.scale.set( s[0], s[1], s[2] ); + if ( loaded === total && scope.onLoad !== undefined ) { - } else { + scope.onLoad(); - bone.scale.set( 1, 1, 1 ); + } - } + }; - } +}; - for ( b = 0; b < this.bones.length; b ++ ) { +THREE.DefaultLoadingManager = new THREE.LoadingManager(); - gbone = this.geometry.bones[ b ]; - bone = this.bones[ b ]; +// File:src/loaders/BufferGeometryLoader.js - if ( gbone.parent === -1 ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - this.add( bone ); +THREE.BufferGeometryLoader = function ( manager ) { - } else { + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - this.bones[ gbone.parent ].add( bone ); +}; - } +THREE.BufferGeometryLoader.prototype = { - } + constructor: THREE.BufferGeometryLoader, - // + load: function ( url, onLoad, onProgress, onError ) { - var nBones = this.bones.length; + var scope = this; - if ( this.useVertexTexture ) { + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones (8 * 8 / 4) - // 16x16 pixel texture max 64 bones (16 * 16 / 4) - // 32x32 pixel texture max 256 bones (32 * 32 / 4) - // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - - var size; - - if ( nBones > 256 ) - size = 64; - else if ( nBones > 64 ) - size = 32; - else if ( nBones > 16 ) - size = 16; - else - size = 8; - - this.boneTextureWidth = size; - this.boneTextureHeight = size; - - this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel - this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); - this.boneTexture.minFilter = THREE.NearestFilter; - this.boneTexture.magFilter = THREE.NearestFilter; - this.boneTexture.generateMipmaps = false; - this.boneTexture.flipY = false; + onLoad( scope.parse( JSON.parse( text ) ) ); - } else { + }, onProgress, onError ); - this.boneMatrices = new Float32Array( 16 * nBones ); + }, - } + setCrossOrigin: function ( value ) { - this.pose(); + this.crossOrigin = value; - } + }, -}; + parse: function ( json ) { -THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); + var geometry = new THREE.BufferGeometry(); -THREE.SkinnedMesh.prototype.addBone = function( bone ) { + var attributes = json.data.attributes; - if ( bone === undefined ) { + for ( var key in attributes ) { - bone = new THREE.Bone( this ); + var attribute = attributes[ key ]; + var typedArray = new self[ attribute.type ]( attribute.array ); - } + geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) ); - this.bones.push( bone ); + } - return bone; + var offsets = json.data.offsets; -}; + if ( offsets !== undefined ) { -THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { + geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); - var offsetMatrix = new THREE.Matrix4(); + } - return function ( force ) { + var boundingSphere = json.data.boundingSphere; - this.matrixAutoUpdate && this.updateMatrix(); + if ( boundingSphere !== undefined ) { - // update matrixWorld + var center = new THREE.Vector3(); - if ( this.matrixWorldNeedsUpdate || force ) { + if ( boundingSphere.center !== undefined ) { - if ( this.parent ) { + center.fromArray( boundingSphere.center ); - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + } - } else { + geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius ); - this.matrixWorld.copy( this.matrix ); + } - } + return geometry; - this.matrixWorldNeedsUpdate = false; + } - force = true; +}; - } +// File:src/loaders/MaterialLoader.js - // update children +/** + * @author mrdoob / http://mrdoob.com/ + */ - for ( var i = 0, l = this.children.length; i < l; i ++ ) { +THREE.MaterialLoader = function ( manager ) { - var child = this.children[ i ]; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - if ( child instanceof THREE.Bone ) { +}; - child.update( this.identityMatrix, false ); +THREE.MaterialLoader.prototype = { - } else { + constructor: THREE.MaterialLoader, - child.updateMatrixWorld( true ); + load: function ( url, onLoad, onProgress, onError ) { - } + var scope = this; - } + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - // make a snapshot of the bones' rest position + onLoad( scope.parse( JSON.parse( text ) ) ); - if ( this.boneInverses == undefined ) { + }, onProgress, onError ); - this.boneInverses = []; + }, - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + setCrossOrigin: function ( value ) { - var inverse = new THREE.Matrix4(); + this.crossOrigin = value; - inverse.getInverse( this.bones[ b ].skinMatrix ); + }, - this.boneInverses.push( inverse ); + parse: function ( json ) { - } + var material = new THREE[ json.type ]; - } + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + if ( json.shading !== undefined ) material.shading = json.shading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.side !== undefined ) material.side = json.side; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - // flatten bone matrices to array + // for PointCloudMaterial + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + if ( json.materials !== undefined ) { - // compute the offset between the current and the original transform; + for ( var i = 0, l = json.materials.length; i < l; i ++ ) { - // TODO: we could get rid of this multiplication step if the skinMatrix - // was already representing the offset; however, this requires some - // major changes to the animation system + material.materials.push( this.parse( json.materials[ i ] ) ); - offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); - offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); + } } - if ( this.useVertexTexture ) { - - this.boneTexture.needsUpdate = true; + return material; - } + } - }; +}; -}(); +// File:src/loaders/ObjectLoader.js -THREE.SkinnedMesh.prototype.pose = function () { +/** + * @author mrdoob / http://mrdoob.com/ + */ - this.updateMatrixWorld( true ); +THREE.ObjectLoader = function ( manager ) { - this.normalizeSkinWeights(); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.texturePath = ''; }; -THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - - if ( this.geometry instanceof THREE.Geometry ) { - - for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - - var sw = this.geometry.skinWeights[ i ]; +THREE.ObjectLoader.prototype = { - var scale = 1.0 / sw.lengthManhattan(); + constructor: THREE.ObjectLoader, - if ( scale !== Infinity ) { + load: function ( url, onLoad, onProgress, onError ) { - sw.multiplyScalar( scale ); + if ( this.texturePath === '' ) { - } else { + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - sw.set( 1 ); // this will be normalized by the shader anyway + } - } + var scope = this; - } + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { - } else { + scope.parse( JSON.parse( text ), onLoad ); - // skinning weights assumed to be normalized for THREE.BufferGeometry + }, onProgress, onError ); - } + }, -}; + setTexturePath: function ( value ) { -THREE.SkinnedMesh.prototype.clone = function ( object ) { + this.texturePath = value; - if ( object === undefined ) { + }, - object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); + setCrossOrigin: function ( value ) { - } + this.crossOrigin = value; - THREE.Mesh.prototype.clone.call( this, object ); + }, - return object; + parse: function ( json, onLoad ) { -}; + var geometries = this.parseGeometries( json.geometries ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + var images = this.parseImages( json.images, function () { -THREE.MorphAnimMesh = function ( geometry, material ) { + if ( onLoad !== undefined ) onLoad( object ); - THREE.Mesh.call( this, geometry, material ); + } ); + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); + var object = this.parseObject( json.object, geometries, materials ); - // API + if ( json.images === undefined || json.images.length === 0 ) { - this.duration = 1000; // milliseconds - this.mirroredLoop = false; - this.time = 0; + if ( onLoad !== undefined ) onLoad( object ); - // internals + } - this.lastKeyframe = 0; - this.currentKeyframe = 0; + return object; - this.direction = 1; - this.directionBackwards = false; + }, - this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); + parseGeometries: function ( json ) { -}; + var geometries = {}; -THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); + if ( json !== undefined ) { -THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { + var geometryLoader = new THREE.JSONLoader(); + var bufferGeometryLoader = new THREE.BufferGeometryLoader(); - this.startKeyframe = start; - this.endKeyframe = end; + for ( var i = 0, l = json.length; i < l; i ++ ) { - this.length = this.endKeyframe - this.startKeyframe + 1; + var geometry; + var data = json[ i ]; -}; + switch ( data.type ) { -THREE.MorphAnimMesh.prototype.setDirectionForward = function () { + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - this.direction = 1; - this.directionBackwards = false; + geometry = new THREE[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); -}; + break; -THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { + case 'BoxGeometry': + case 'CubeGeometry': // backwards compatible - this.direction = -1; - this.directionBackwards = true; + geometry = new THREE.BoxGeometry( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); -}; + break; -THREE.MorphAnimMesh.prototype.parseAnimations = function () { + case 'CircleGeometry': - var geometry = this.geometry; + geometry = new THREE.CircleGeometry( + data.radius, + data.segments + ); - if ( ! geometry.animations ) geometry.animations = {}; + break; - var firstAnimation, animations = geometry.animations; + case 'CylinderGeometry': - var pattern = /([a-z]+)(\d+)/; + geometry = new THREE.CylinderGeometry( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded + ); - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + break; - var morph = geometry.morphTargets[ i ]; - var parts = morph.name.match( pattern ); + case 'SphereGeometry': - if ( parts && parts.length > 1 ) { + geometry = new THREE.SphereGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); - var label = parts[ 1 ]; - var num = parts[ 2 ]; + break; - if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; + case 'IcosahedronGeometry': - var animation = animations[ label ]; + geometry = new THREE.IcosahedronGeometry( + data.radius, + data.detail + ); - if ( i < animation.start ) animation.start = i; - if ( i > animation.end ) animation.end = i; + break; - if ( ! firstAnimation ) firstAnimation = label; + case 'TorusGeometry': - } + geometry = new THREE.TorusGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - } + break; - geometry.firstAnimation = firstAnimation; + case 'TorusKnotGeometry': -}; + geometry = new THREE.TorusKnotGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.p, + data.q, + data.heightScale + ); -THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { + break; - if ( ! this.geometry.animations ) this.geometry.animations = {}; + case 'BufferGeometry': - this.geometry.animations[ label ] = { start: start, end: end }; + geometry = bufferGeometryLoader.parse( data ); -}; + break; -THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { + case 'Geometry': - var animation = this.geometry.animations[ label ]; + geometry = geometryLoader.parse( data.data ).geometry; - if ( animation ) { + break; - this.setFrameRange( animation.start, animation.end ); - this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); - this.time = 0; + } - } else { + geometry.uuid = data.uuid; - console.warn( "animation[" + label + "] undefined" ); + if ( data.name !== undefined ) geometry.name = data.name; - } + geometries[ data.uuid ] = geometry; -}; + } -THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { + } - var frameTime = this.duration / this.length; + return geometries; - this.time += this.direction * delta; + }, - if ( this.mirroredLoop ) { + parseMaterials: function ( json, textures ) { - if ( this.time > this.duration || this.time < 0 ) { + var materials = {}; - this.direction *= -1; + if ( json !== undefined ) { - if ( this.time > this.duration ) { + var getTexture = function ( name ) { - this.time = this.duration; - this.directionBackwards = true; + if ( textures[ name ] === undefined ) { - } + THREE.warn( 'THREE.ObjectLoader: Undefined texture', name ); - if ( this.time < 0 ) { + } - this.time = 0; - this.directionBackwards = false; + return textures[ name ]; - } + }; - } + var loader = new THREE.MaterialLoader(); - } else { + for ( var i = 0, l = json.length; i < l; i ++ ) { - this.time = this.time % this.duration; + var data = json[ i ]; + var material = loader.parse( data ); - if ( this.time < 0 ) this.time += this.duration; + material.uuid = data.uuid; - } + if ( data.name !== undefined ) material.name = data.name; - var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); + if ( data.map !== undefined ) { - if ( keyframe !== this.currentKeyframe ) { + material.map = getTexture( data.map ); - this.morphTargetInfluences[ this.lastKeyframe ] = 0; - this.morphTargetInfluences[ this.currentKeyframe ] = 1; + } - this.morphTargetInfluences[ keyframe ] = 0; + if ( data.bumpMap !== undefined ) { - this.lastKeyframe = this.currentKeyframe; - this.currentKeyframe = keyframe; + material.bumpMap = getTexture( data.bumpMap ); + if ( data.bumpScale ) { + material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale ); + } - } + } - var mix = ( this.time % frameTime ) / frameTime; + if ( data.alphaMap !== undefined ) { - if ( this.directionBackwards ) { + material.alphaMap = getTexture( data.alphaMap ); - mix = 1 - mix; + } - } + if ( data.envMap !== undefined ) { - this.morphTargetInfluences[ this.currentKeyframe ] = mix; - this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; + material.envMap = getTexture( data.envMap ); -}; + } -THREE.MorphAnimMesh.prototype.clone = function ( object ) { + if ( data.normalMap !== undefined ) { - if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); + material.normalMap = getTexture( data.normalMap ); + if ( data.normalScale ) { + material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale ); + } - object.duration = this.duration; - object.mirroredLoop = this.mirroredLoop; - object.time = this.time; + } - object.lastKeyframe = this.lastKeyframe; - object.currentKeyframe = this.currentKeyframe; + if ( data.lightMap !== undefined ) { - object.direction = this.direction; - object.directionBackwards = this.directionBackwards; + material.lightMap = getTexture( data.lightMap ); - THREE.Mesh.prototype.clone.call( this, object ); + } - return object; + if ( data.specularMap !== undefined ) { -}; + material.specularMap = getTexture( data.specularMap ); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + } -THREE.LOD = function () { + materials[ data.uuid ] = material; - THREE.Object3D.call( this ); + } - this.objects = []; + } -}; + return materials; + }, -THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); + parseImages: function ( json, onLoad ) { -THREE.LOD.prototype.addLevel = function ( object, distance ) { + var scope = this; + var images = {}; - if ( distance === undefined ) distance = 0; + if ( json !== undefined && json.length > 0 ) { - distance = Math.abs( distance ); + var manager = new THREE.LoadingManager( onLoad ); - for ( var l = 0; l < this.objects.length; l ++ ) { + var loader = new THREE.ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - if ( distance < this.objects[ l ].distance ) { + var loadImage = function ( url ) { - break; + scope.manager.itemStart( url ); - } + return loader.load( url, function () { - } + scope.manager.itemEnd( url ); - this.objects.splice( l, 0, { distance: distance, object: object } ); - this.add( object ); + } ); -}; + }; -THREE.LOD.prototype.getObjectForDistance = function ( distance ) { + for ( var i = 0, l = json.length; i < l; i ++ ) { - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; - if ( distance < this.objects[ i ].distance ) { + images[ image.uuid ] = loadImage( path ); - break; + } } - } + return images; - return this.objects[ i - 1 ].object; + }, -}; + parseTextures: function ( json, images ) { -THREE.LOD.prototype.update = function () { + var textures = {}; - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + if ( json !== undefined ) { - return function ( camera ) { + for ( var i = 0, l = json.length; i < l; i ++ ) { - if ( this.objects.length > 1 ) { + var data = json[ i ]; - v1.getPositionFromMatrix( camera.matrixWorld ); - v2.getPositionFromMatrix( this.matrixWorld ); + if ( data.image === undefined ) { - var distance = v1.distanceTo( v2 ); + THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid ); - this.objects[ 0 ].object.visible = true; + } - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + if ( images[ data.image ] === undefined ) { - if ( distance >= this.objects[ i ].distance ) { + THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - this.objects[ i - 1 ].object.visible = false; - this.objects[ i ].object.visible = true; + } - } else { + var texture = new THREE.Texture( images[ data.image ] ); + texture.needsUpdate = true; - break; + texture.uuid = data.uuid; - } + if ( data.name !== undefined ) texture.name = data.name; + if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); + if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ]; + if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ]; + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + if ( data.wrap instanceof Array ) { - } + texture.wrapS = THREE[ data.wrap[ 0 ] ]; + texture.wrapT = THREE[ data.wrap[ 1 ] ]; - for( ; i < l; i ++ ) { + } - this.objects[ i ].object.visible = false; + textures[ data.uuid ] = texture; } } - }; - -}(); + return textures; -THREE.LOD.prototype.clone = function () { + }, - // TODO + parseObject: function () { -}; + var matrix = new THREE.Matrix4(); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + return function ( data, geometries, materials ) { -THREE.Sprite = function ( material ) { + var object; - THREE.Object3D.call( this ); + var getGeometry = function ( name ) { - this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); + if ( geometries[ name ] === undefined ) { - this.rotation = 0; + THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name ); -}; + } -THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); + return geometries[ name ]; -/* - * Custom update matrix - */ + }; -THREE.Sprite.prototype.updateMatrix = function () { + var getMaterial = function ( name ) { - this.matrix.compose( this.position, this.quaternion, this.scale ); + if ( materials[ name ] === undefined ) { - this.matrixWorldNeedsUpdate = true; + THREE.warn( 'THREE.ObjectLoader: Undefined material', name ); -}; + } -THREE.Sprite.prototype.clone = function ( object ) { + return materials[ name ]; - if ( object === undefined ) object = new THREE.Sprite( this.material ); + }; - THREE.Object3D.prototype.clone.call( this, object ); + switch ( data.type ) { - return object; + case 'Scene': -}; + object = new THREE.Scene(); -// Backwards compatibility + break; -THREE.Particle = THREE.Sprite; -/** - * @author mrdoob / http://mrdoob.com/ - */ + case 'PerspectiveCamera': -THREE.Scene = function () { + object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - THREE.Object3D.call( this ); + break; - this.fog = null; - this.overrideMaterial = null; + case 'OrthographicCamera': - this.autoUpdate = true; // checked by the renderer - this.matrixAutoUpdate = false; + object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - this.__lights = []; + break; - this.__objectsAdded = []; - this.__objectsRemoved = []; + case 'AmbientLight': -}; + object = new THREE.AmbientLight( data.color ); -THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); + break; -THREE.Scene.prototype.__addObject = function ( object ) { + case 'DirectionalLight': - if ( object instanceof THREE.Light ) { + object = new THREE.DirectionalLight( data.color, data.intensity ); - if ( this.__lights.indexOf( object ) === - 1 ) { + break; - this.__lights.push( object ); + case 'PointLight': - } + object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay ); - if ( object.target && object.target.parent === undefined ) { + break; - this.add( object.target ); + case 'SpotLight': - } + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay ); - } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { + break; - this.__objectsAdded.push( object ); + case 'HemisphereLight': - // check if previously removed + object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); - var i = this.__objectsRemoved.indexOf( object ); + break; - if ( i !== -1 ) { + case 'Mesh': - this.__objectsRemoved.splice( i, 1 ); + object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); - } + break; - } + case 'Line': - for ( var c = 0; c < object.children.length; c ++ ) { + object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - this.__addObject( object.children[ c ] ); + break; - } + case 'PointCloud': -}; + object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) ); -THREE.Scene.prototype.__removeObject = function ( object ) { + break; - if ( object instanceof THREE.Light ) { + case 'Sprite': - var i = this.__lights.indexOf( object ); + object = new THREE.Sprite( getMaterial( data.material ) ); - if ( i !== -1 ) { + break; - this.__lights.splice( i, 1 ); + case 'Group': - } + object = new THREE.Group(); - if ( object.shadowCascadeArray ) { + break; - for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { + default: - this.__removeObject( object.shadowCascadeArray[ x ] ); + object = new THREE.Object3D(); } - } - - } else if ( !( object instanceof THREE.Camera ) ) { - - this.__objectsRemoved.push( object ); - - // check if previously added - - var i = this.__objectsAdded.indexOf( object ); + object.uuid = data.uuid; - if ( i !== -1 ) { + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { - this.__objectsAdded.splice( i, 1 ); + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); - } + } else { - } + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - for ( var c = 0; c < object.children.length; c ++ ) { + } - this.__removeObject( object.children[ c ] ); + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.userData !== undefined ) object.userData = data.userData; - } + if ( data.children !== undefined ) { -}; + for ( var child in data.children ) { -THREE.Scene.prototype.clone = function ( object ) { + object.add( this.parseObject( data.children[ child ], geometries, materials ) ); - if ( object === undefined ) object = new THREE.Scene(); + } - THREE.Object3D.prototype.clone.call(this, object); + } - if ( this.fog !== null ) object.fog = this.fog.clone(); - if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); + return object; - object.autoUpdate = this.autoUpdate; - object.matrixAutoUpdate = this.matrixAutoUpdate; + } - return object; + }() }; +// File:src/loaders/TextureLoader.js + /** * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ */ -THREE.Fog = function ( hex, near, far ) { - - this.name = ''; - - this.color = new THREE.Color( hex ); +THREE.TextureLoader = function ( manager ) { - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; -THREE.Fog.prototype.clone = function () { +THREE.TextureLoader.prototype = { - return new THREE.Fog( this.color.getHex(), this.near, this.far ); + constructor: THREE.TextureLoader, -}; + load: function ( url, onLoad, onProgress, onError ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + var scope = this; -THREE.FogExp2 = function ( hex, density ) { + var loader = new THREE.ImageLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( image ) { - this.name = ''; + var texture = new THREE.Texture( image ); + texture.needsUpdate = true; - this.color = new THREE.Color( hex ); - this.density = ( density !== undefined ) ? density : 0.00025; + if ( onLoad !== undefined ) { -}; + onLoad( texture ); -THREE.FogExp2.prototype.clone = function () { + } - return new THREE.FogExp2( this.color.getHex(), this.density ); + }, onProgress, onError ); -}; + }, -/** - * @author mrdoob / http://mrdoob.com/ - */ + setCrossOrigin: function ( value ) { -THREE.CanvasRenderer = function ( parameters ) { + this.crossOrigin = value; - console.log( 'THREE.CanvasRenderer', THREE.REVISION ); + } - var smoothstep = THREE.Math.smoothstep; +}; - parameters = parameters || {}; +// File:src/loaders/BinaryTextureLoader.js - var _this = this, - _renderData, _elements, _lights, - _projector = new THREE.Projector(), +/** + * @author Nikos M. / https://github.com/foo123/ + * + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + */ - _canvas = parameters.canvas !== undefined - ? parameters.canvas - : document.createElement( 'canvas' ), +THREE.DataTextureLoader = THREE.BinaryTextureLoader = function () { - _canvasWidth = _canvas.width, - _canvasHeight = _canvas.height, - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), + // override in sub classes + this._parser = null; - _context = _canvas.getContext( '2d' ), +}; - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0, +THREE.BinaryTextureLoader.prototype = { - _contextGlobalAlpha = 1, - _contextGlobalCompositeOperation = 0, - _contextStrokeStyle = null, - _contextFillStyle = null, - _contextLineWidth = null, - _contextLineCap = null, - _contextLineJoin = null, - _contextDashSize = null, - _contextGapSize = 0, + constructor: THREE.BinaryTextureLoader, + + load: function ( url, onLoad, onProgress, onError ) { - _camera, + var scope = this; - _v1, _v2, _v3, _v4, - _v5 = new THREE.RenderableVertex(), - _v6 = new THREE.RenderableVertex(), + var texture = new THREE.DataTexture( ); - _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, - _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, + var loader = new THREE.XHRLoader(); + loader.setResponseType( 'arraybuffer' ); - _color = new THREE.Color(), - _color1 = new THREE.Color(), - _color2 = new THREE.Color(), - _color3 = new THREE.Color(), - _color4 = new THREE.Color(), + loader.load( url, function ( buffer ) { - _diffuseColor = new THREE.Color(), - _emissiveColor = new THREE.Color(), + var texData = scope._parser( buffer ); - _lightColor = new THREE.Color(), + if ( !texData ) return; - _patterns = {}, _imagedatas = {}, + if ( undefined !== texData.image ) { - _near, _far, + texture.image = texData.image; - _image, _uvs, - _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, + } else if ( undefined !== texData.data ) { - _clipBox = new THREE.Box2(), - _clearBox = new THREE.Box2(), - _elemBox = new THREE.Box2(), + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - _ambientLight = new THREE.Color(), - _directionalLights = new THREE.Color(), - _pointLights = new THREE.Color(), + } - _vector3 = new THREE.Vector3(), // Needed for PointLight + texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping; + texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; - _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData, - _gradientMap, _gradientMapContext, _gradientMapQuality = 16; + texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; + texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter; - _pixelMap = document.createElement( 'canvas' ); - _pixelMap.width = _pixelMap.height = 2; + texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; - _pixelMapContext = _pixelMap.getContext( '2d' ); - _pixelMapContext.fillStyle = 'rgba(0,0,0,1)'; - _pixelMapContext.fillRect( 0, 0, 2, 2 ); + if ( undefined !== texData.format ) { - _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 ); - _pixelMapData = _pixelMapImage.data; + texture.format = texData.format; - _gradientMap = document.createElement( 'canvas' ); - _gradientMap.width = _gradientMap.height = _gradientMapQuality; + } + if ( undefined !== texData.type ) { - _gradientMapContext = _gradientMap.getContext( '2d' ); - _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 ); - _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality ); + texture.type = texData.type; - _gradientMapQuality --; // Fix UVs + } - // dash+gap fallbacks for Firefox and everything else + if ( undefined !== texData.mipmaps ) { - if ( _context.setLineDash === undefined ) { + texture.mipmaps = texData.mipmaps; - if ( _context.mozDash !== undefined ) { + } - _context.setLineDash = function ( values ) { + if ( 1 === texData.mipmapCount ) { - _context.mozDash = values[ 0 ] !== null ? values : null; + texture.minFilter = THREE.LinearFilter; } - } else { + texture.needsUpdate = true; - _context.setLineDash = function () {} + if ( onLoad ) onLoad( texture, texData ); - } + }, onProgress, onError ); - } - this.domElement = _canvas; + return texture; - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; + } - this.autoClear = true; - this.sortObjects = true; - this.sortElements = true; +}; - this.info = { +// File:src/loaders/CompressedTextureLoader.js - render: { +/** + * @author mrdoob / http://mrdoob.com/ + * + * Abstract Base class to block based textures loader (dds, pvr, ...) + */ - vertices: 0, - faces: 0 +THREE.CompressedTextureLoader = function () { - } + // override in sub classes + this._parser = null; - } +}; - // WebGLRenderer compatibility - this.supportsVertexTextures = function () {}; - this.setFaceCulling = function () {}; +THREE.CompressedTextureLoader.prototype = { - this.setSize = function ( width, height, updateStyle ) { + constructor: THREE.CompressedTextureLoader, - _canvasWidth = width * this.devicePixelRatio; - _canvasHeight = height * this.devicePixelRatio; + load: function ( url, onLoad, onError ) { - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); + var scope = this; - _canvas.width = _canvasWidth; - _canvas.height = _canvasHeight; + var images = []; - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + var texture = new THREE.CompressedTexture(); + texture.image = images; - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + var loader = new THREE.XHRLoader(); + loader.setResponseType( 'arraybuffer' ); - } + if ( url instanceof Array ) { - _clipBox.set( - new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), - new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) - ); + var loaded = 0; - _clearBox.set( - new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), - new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) - ); + var loadTexture = function ( i ) { - _contextGlobalAlpha = 1; - _contextGlobalCompositeOperation = 0; - _contextStrokeStyle = null; - _contextFillStyle = null; - _contextLineWidth = null; - _contextLineCap = null; - _contextLineJoin = null; + loader.load( url[ i ], function ( buffer ) { - }; + var texDatas = scope._parser( buffer, true ); - this.setClearColor = function ( color, alpha ) { + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - _clearColor.set( color ); - _clearAlpha = alpha !== undefined ? alpha : 1; + loaded += 1; - _clearBox.set( - new THREE.Vector2( - _canvasWidthHalf, - _canvasHeightHalf ), - new THREE.Vector2( _canvasWidthHalf, _canvasHeightHalf ) - ); + if ( loaded === 6 ) { - }; + if (texDatas.mipmapCount == 1) + texture.minFilter = THREE.LinearFilter; - this.setClearColorHex = function ( hex, alpha ) { + texture.format = texDatas.format; + texture.needsUpdate = true; - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); + if ( onLoad ) onLoad( texture ); - }; + } - this.getMaxAnisotropy = function () { + } ); - return 0; + }; - }; + for ( var i = 0, il = url.length; i < il; ++ i ) { - this.clear = function () { + loadTexture( i ); - _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + } - if ( _clearBox.empty() === false ) { + } else { - _clearBox.intersect( _clipBox ); - _clearBox.expandByScalar( 2 ); + // compressed cubemap texture stored in a single DDS file - if ( _clearAlpha < 1 ) { + loader.load( url, function ( buffer ) { - _context.clearRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); + var texDatas = scope._parser( buffer, true ); - } + if ( texDatas.isCubemap ) { - if ( _clearAlpha > 0 ) { + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - setBlending( THREE.NormalBlending ); - setOpacity( 1 ); + for ( var f = 0; f < faces; f ++ ) { - setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); + images[ f ] = { mipmaps : [] }; - _context.fillRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); + for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { - } + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; - _clearBox.makeEmpty(); + } - } + } + } else { - }; + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - this.render = function ( scene, camera ) { + } - if ( camera instanceof THREE.Camera === false ) { + if ( texDatas.mipmapCount === 1 ) { - console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + texture.minFilter = THREE.LinearFilter; - } + } - if ( this.autoClear === true ) this.clear(); + texture.format = texDatas.format; + texture.needsUpdate = true; - _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + if ( onLoad ) onLoad( texture ); - _this.info.render.vertices = 0; - _this.info.render.faces = 0; + } ); - _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); - _elements = _renderData.elements; - _lights = _renderData.lights; - _camera = camera; + } - /* DEBUG - setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); - _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); - */ + return texture; - calculateLights(); + } - for ( var e = 0, el = _elements.length; e < el; e++ ) { +}; - var element = _elements[ e ]; +// File:src/materials/Material.js - var material = element.material; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - if ( material === undefined || material.visible === false ) continue; +THREE.Material = function () { - _elemBox.makeEmpty(); + Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } ); - if ( element instanceof THREE.RenderableSprite ) { + this.uuid = THREE.Math.generateUUID(); - _v1 = element; - _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; + this.name = ''; + this.type = 'Material'; - renderSprite( _v1, element, material ); + this.side = THREE.FrontSide; - } else if ( element instanceof THREE.RenderableLine ) { + this.opacity = 1; + this.transparent = false; - _v1 = element.v1; _v2 = element.v2; + this.blending = THREE.NormalBlending; - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen - ] ); + this.depthTest = true; + this.depthWrite = true; - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + this.colorWrite = true; - renderLine( _v1, _v2, element, material ); + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - } + this.alphaTest = 0; - } else if ( element instanceof THREE.RenderableFace3 ) { + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; + this.visible = true; - if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; - if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; - if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; + this._needsUpdate = true; - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; - _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; +}; - if ( material.overdraw > 0 ) { +THREE.Material.prototype = { - expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); - expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); - expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); + constructor: THREE.Material, - } + get needsUpdate () { - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen, - _v3.positionScreen - ] ); + return this._needsUpdate; - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + }, - renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); + set needsUpdate ( value ) { - } + if ( value === true ) this.update(); - } + this._needsUpdate = value; - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); - _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); - */ + }, - _clearBox.union( _elemBox ); + setValues: function ( values ) { - } + if ( values === undefined ) return; - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); - _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); - */ + for ( var key in values ) { - _context.setTransform( 1, 0, 0, 1, 0, 0 ); + var newValue = values[ key ]; - }; + if ( newValue === undefined ) { - // + THREE.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + continue; - function calculateLights() { + } - _ambientLight.setRGB( 0, 0, 0 ); - _directionalLights.setRGB( 0, 0, 0 ); - _pointLights.setRGB( 0, 0, 0 ); + if ( key in this ) { - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + var currentValue = this[ key ]; - var light = _lights[ l ]; - var lightColor = light.color; + if ( currentValue instanceof THREE.Color ) { - if ( light instanceof THREE.AmbientLight ) { + currentValue.set( newValue ); - _ambientLight.add( lightColor ); + } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { - } else if ( light instanceof THREE.DirectionalLight ) { + currentValue.copy( newValue ); - // for sprites + } else if ( key == 'overdraw' ) { - _directionalLights.add( lightColor ); + // ensure overdraw is backwards-compatable with legacy boolean type + this[ key ] = Number( newValue ); - } else if ( light instanceof THREE.PointLight ) { + } else { - // for sprites + this[ key ] = newValue; - _pointLights.add( lightColor ); + } } } - } + }, - function calculateLight( position, normal, color ) { + toJSON: function () { - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type + }; - var light = _lights[ l ]; + if ( this.name !== "" ) output.name = this.name; - _lightColor.copy( light.color ); + if ( this instanceof THREE.MeshBasicMaterial ) { - if ( light instanceof THREE.DirectionalLight ) { + output.color = this.color.getHex(); + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ).normalize(); + } else if ( this instanceof THREE.MeshLambertMaterial ) { - var amount = normal.dot( lightPosition ); + output.color = this.color.getHex(); + output.emissive = this.emissive.getHex(); + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - if ( amount <= 0 ) continue; + } else if ( this instanceof THREE.MeshPhongMaterial ) { - amount *= light.intensity; + output.color = this.color.getHex(); + output.emissive = this.emissive.getHex(); + output.specular = this.specular.getHex(); + output.shininess = this.shininess; + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - color.add( _lightColor.multiplyScalar( amount ) ); + } else if ( this instanceof THREE.MeshNormalMaterial ) { - } else if ( light instanceof THREE.PointLight ) { + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - var lightPosition = _vector3.getPositionFromMatrix( light.matrixWorld ); + } else if ( this instanceof THREE.MeshDepthMaterial ) { - var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + if ( this.side !== THREE.FrontSide ) output.side = this.side; - if ( amount <= 0 ) continue; + } else if ( this instanceof THREE.PointCloudMaterial ) { - amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); + output.size = this.size; + output.sizeAttenuation = this.sizeAttenuation; + output.color = this.color.getHex(); - if ( amount == 0 ) continue; + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; - amount *= light.intensity; + } else if ( this instanceof THREE.ShaderMaterial ) { - color.add( _lightColor.multiplyScalar( amount ) ); + output.uniforms = this.uniforms; + output.vertexShader = this.vertexShader; + output.fragmentShader = this.fragmentShader; - } + } else if ( this instanceof THREE.SpriteMaterial ) { + + output.color = this.color.getHex(); } - } + if ( this.opacity < 1 ) output.opacity = this.opacity; + if ( this.transparent !== false ) output.transparent = this.transparent; + if ( this.wireframe !== false ) output.wireframe = this.wireframe; - function renderSprite( v1, element, material ) { + return output; - setOpacity( material.opacity ); - setBlending( material.blending ); + }, - var width, height, scaleX, scaleY, - bitmap, bitmapWidth, bitmapHeight; + clone: function ( material ) { - if ( material instanceof THREE.SpriteMaterial || - material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility + if ( material === undefined ) material = new THREE.Material(); - if ( material.map.image !== undefined ) { + material.name = this.name; - bitmap = material.map.image; - bitmapWidth = bitmap.width >> 1; - bitmapHeight = bitmap.height >> 1; + material.side = this.side; - scaleX = element.scale.x * _canvasWidthHalf; - scaleY = element.scale.y * _canvasHeightHalf; + material.opacity = this.opacity; + material.transparent = this.transparent; - width = scaleX * bitmapWidth; - height = scaleY * bitmapHeight; + material.blending = this.blending; - // TODO: Rotations break this... + material.blendSrc = this.blendSrc; + material.blendDst = this.blendDst; + material.blendEquation = this.blendEquation; + material.blendSrcAlpha = this.blendSrcAlpha; + material.blendDstAlpha = this.blendDstAlpha; + material.blendEquationAlpha = this.blendEquationAlpha; - _elemBox.min.set( v1.x - width, v1.y - height ); - _elemBox.max.set( v1.x + width, v1.y + height ); + material.depthTest = this.depthTest; + material.depthWrite = this.depthWrite; - if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + material.polygonOffset = this.polygonOffset; + material.polygonOffsetFactor = this.polygonOffsetFactor; + material.polygonOffsetUnits = this.polygonOffsetUnits; - _elemBox.makeEmpty(); - return; + material.alphaTest = this.alphaTest; - } + material.overdraw = this.overdraw; - _context.save(); - _context.translate( v1.x, v1.y ); - _context.rotate( - element.rotation ); - _context.scale( scaleX, - scaleY ); + material.visible = this.visible; - _context.translate( - bitmapWidth, - bitmapHeight ); - _context.drawImage( bitmap, 0, 0 ); - _context.restore(); + return material; - } else { + }, - scaleX = element.object.scale.x; - scaleY = element.object.scale.y; + update: function () { - // TODO: Be able to disable this + this.dispatchEvent( { type: 'update' } ); - scaleX *= element.scale.x * _canvasWidthHalf; - scaleY *= element.scale.y * _canvasHeightHalf; + }, - _elemBox.min.set( v1.x - scaleX, v1.y - scaleY ); - _elemBox.max.set( v1.x + scaleX, v1.y + scaleY ); + dispose: function () { - if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + this.dispatchEvent( { type: 'dispose' } ); - _elemBox.makeEmpty(); - return; + } - } +}; - setFillStyle( material.color.getStyle() ); +THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - _context.save(); - _context.translate( v1.x, v1.y ); - _context.rotate( - element.rotation ); - _context.scale( scaleX, scaleY ); - _context.fillRect( -1, -1, 2, 2 ); - _context.restore(); +THREE.MaterialIdCount = 0; - } +// File:src/materials/LineBasicMaterial.js - /* DEBUG - setStrokeStyle( 'rgb(255,255,0)' ); - _context.beginPath(); - _context.moveTo( v1.x - 10, v1.y ); - _context.lineTo( v1.x + 10, v1.y ); - _context.moveTo( v1.x, v1.y - 10 ); - _context.lineTo( v1.x, v1.y + 10 ); - _context.stroke(); - */ +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * linewidth: <float>, + * linecap: "round", + * linejoin: "round", + * + * vertexColors: <bool> + * + * fog: <bool> + * } + */ - } else if ( material instanceof THREE.SpriteCanvasMaterial ) { +THREE.LineBasicMaterial = function ( parameters ) { - width = element.scale.x * _canvasWidthHalf; - height = element.scale.y * _canvasHeightHalf; + THREE.Material.call( this ); - _elemBox.min.set( v1.x - width, v1.y - height ); - _elemBox.max.set( v1.x + width, v1.y + height ); + this.type = 'LineBasicMaterial'; - if ( _clipBox.isIntersectionBox( _elemBox ) === false ) { + this.color = new THREE.Color( 0xffffff ); - _elemBox.makeEmpty(); - return; + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - } + this.vertexColors = THREE.NoColors; - setStrokeStyle( material.color.getStyle() ); - setFillStyle( material.color.getStyle() ); + this.fog = true; - _context.save(); - _context.translate( v1.x, v1.y ); - _context.rotate( - element.rotation ); - _context.scale( width, height ); + this.setValues( parameters ); - material.program( _context ); +}; - _context.restore(); +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; - } +THREE.LineBasicMaterial.prototype.clone = function () { - } + var material = new THREE.LineBasicMaterial(); - function renderLine( v1, v2, element, material ) { + THREE.Material.prototype.clone.call( this, material ); - setOpacity( material.opacity ); - setBlending( material.blending ); + material.color.copy( this.color ); - _context.beginPath(); - _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); - _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); + material.linewidth = this.linewidth; + material.linecap = this.linecap; + material.linejoin = this.linejoin; - if ( material instanceof THREE.LineBasicMaterial ) { + material.vertexColors = this.vertexColors; - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); + material.fog = this.fog; - if ( material.vertexColors !== THREE.VertexColors ) { + return material; - setStrokeStyle( material.color.getStyle() ); +}; - } else { +// File:src/materials/LineDashedMaterial.js - var colorStyle1 = element.vertexColors[0].getStyle(); - var colorStyle2 = element.vertexColors[1].getStyle(); +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * linewidth: <float>, + * + * scale: <float>, + * dashSize: <float>, + * gapSize: <float>, + * + * vertexColors: <bool> + * + * fog: <bool> + * } + */ - if ( colorStyle1 === colorStyle2 ) { +THREE.LineDashedMaterial = function ( parameters ) { - setStrokeStyle( colorStyle1 ); + THREE.Material.call( this ); - } else { + this.type = 'LineDashedMaterial'; - try { + this.color = new THREE.Color( 0xffffff ); - var grad = _context.createLinearGradient( - v1.positionScreen.x, - v1.positionScreen.y, - v2.positionScreen.x, - v2.positionScreen.y - ); - grad.addColorStop( 0, colorStyle1 ); - grad.addColorStop( 1, colorStyle2 ); + this.linewidth = 1; - } catch ( exception ) { + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; - grad = colorStyle1; + this.vertexColors = false; - } + this.fog = true; - setStrokeStyle( grad ); + this.setValues( parameters ); - } +}; - } +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial; - _context.stroke(); - _elemBox.expandByScalar( material.linewidth * 2 ); +THREE.LineDashedMaterial.prototype.clone = function () { - } else if ( material instanceof THREE.LineDashedMaterial ) { + var material = new THREE.LineDashedMaterial(); - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); - setStrokeStyle( material.color.getStyle() ); - setDashAndGap( material.dashSize, material.gapSize ); + THREE.Material.prototype.clone.call( this, material ); - _context.stroke(); + material.color.copy( this.color ); - _elemBox.expandByScalar( material.linewidth * 2 ); + material.linewidth = this.linewidth; - setDashAndGap( null, null ); + material.scale = this.scale; + material.dashSize = this.dashSize; + material.gapSize = this.gapSize; - } + material.vertexColors = this.vertexColors; - } + material.fog = this.fog; - function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { + return material; - _this.info.render.vertices += 3; - _this.info.render.faces ++; +}; - setOpacity( material.opacity ); - setBlending( material.blending ); +// File:src/materials/MeshBasicMaterial.js - _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; - _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; - _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * specularMap: new THREE.Texture( <Image> ), + * + * alphaMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * + * fog: <bool> + * } + */ - drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); +THREE.MeshBasicMaterial = function ( parameters ) { - if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { + THREE.Material.call( this ); - _diffuseColor.copy( material.color ); - _emissiveColor.copy( material.emissive ); + this.type = 'MeshBasicMaterial'; - if ( material.vertexColors === THREE.FaceColors ) { + this.color = new THREE.Color( 0xffffff ); // emissive - _diffuseColor.multiply( element.color ); + this.map = null; - } + this.lightMap = null; - if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 3 ) { + this.specularMap = null; - _color1.copy( _ambientLight ); - _color2.copy( _ambientLight ); - _color3.copy( _ambientLight ); + this.alphaMap = null; - calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); - calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); - calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 ); + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - _color1.multiply( _diffuseColor ).add( _emissiveColor ); - _color2.multiply( _diffuseColor ).add( _emissiveColor ); - _color3.multiply( _diffuseColor ).add( _emissiveColor ); - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + this.fog = true; - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + this.shading = THREE.SmoothShading; - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - } else { + this.vertexColors = THREE.NoColors; - _color.copy( _ambientLight ); + this.skinning = false; + this.morphTargets = false; - calculateLight( element.centroidModel, element.normalModel, _color ); + this.setValues( parameters ); - _color.multiply( _diffuseColor ).add( _emissiveColor ); +}; - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; - } +THREE.MeshBasicMaterial.prototype.clone = function () { - } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + var material = new THREE.MeshBasicMaterial(); - if ( material.map !== null ) { + THREE.Material.prototype.clone.call( this, material ); - if ( material.map.mapping instanceof THREE.UVMapping ) { + material.color.copy( this.color ); - _uvs = element.uvs[ 0 ]; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); + material.map = this.map; - } + material.lightMap = this.lightMap; + material.specularMap = this.specularMap; - } else if ( material.envMap !== null ) { + material.alphaMap = this.alphaMap; - if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - _vector3.copy( element.vertexNormalsModelView[ uv1 ] ); - _uv1x = 0.5 * _vector3.x + 0.5; - _uv1y = 0.5 * _vector3.y + 0.5; + material.fog = this.fog; - _vector3.copy( element.vertexNormalsModelView[ uv2 ] ); - _uv2x = 0.5 * _vector3.x + 0.5; - _uv2y = 0.5 * _vector3.y + 0.5; + material.shading = this.shading; - _vector3.copy( element.vertexNormalsModelView[ uv3 ] ); - _uv3x = 0.5 * _vector3.x + 0.5; - _uv3y = 0.5 * _vector3.y + 0.5; + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + material.vertexColors = this.vertexColors; - }/* else if ( material.envMap.mapping == THREE.SphericalRefractionMapping ) { + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + return material; +}; - }*/ +// File:src/materials/MeshLambertMaterial.js +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * emissive: <hex>, + * opacity: <float>, + * + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * specularMap: new THREE.Texture( <Image> ), + * + * alphaMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ - } else { +THREE.MeshLambertMaterial = function ( parameters ) { - _color.copy( material.color ); + THREE.Material.call( this ); - if ( material.vertexColors === THREE.FaceColors ) { + this.type = 'MeshLambertMaterial'; - _color.multiply( element.color ); + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); - } + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); + this.map = null; - } + this.lightMap = null; - } else if ( material instanceof THREE.MeshDepthMaterial ) { + this.specularMap = null; - _near = _camera.near; - _far = _camera.far; + this.alphaMap = null; - _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); - _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); - _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + this.fog = true; - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + this.shading = THREE.SmoothShading; - } else if ( material instanceof THREE.MeshNormalMaterial ) { + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - var normal; + this.vertexColors = THREE.NoColors; - if ( material.shading == THREE.FlatShading ) { + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - normal = element.normalModelView; + this.setValues( parameters ); - _color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); +}; - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial; - } else if ( material.shading == THREE.SmoothShading ) { +THREE.MeshLambertMaterial.prototype.clone = function () { - normal = element.vertexNormalsModelView[ uv1 ]; - _color1.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + var material = new THREE.MeshLambertMaterial(); - normal = element.vertexNormalsModelView[ uv2 ]; - _color2.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + THREE.Material.prototype.clone.call( this, material ); - normal = element.vertexNormalsModelView[ uv3 ]; - _color3.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + material.color.copy( this.color ); + material.emissive.copy( this.emissive ); - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + material.map = this.map; - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + material.lightMap = this.lightMap; - } + material.specularMap = this.specularMap; - } + material.alphaMap = this.alphaMap; - } + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - // + material.fog = this.fog; - function drawTriangle( x0, y0, x1, y1, x2, y2 ) { + material.shading = this.shading; - _context.beginPath(); - _context.moveTo( x0, y0 ); - _context.lineTo( x1, y1 ); - _context.lineTo( x2, y2 ); - _context.closePath(); + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - } + material.vertexColors = this.vertexColors; - function strokePath( color, linewidth, linecap, linejoin ) { + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - setLineWidth( linewidth ); - setLineCap( linecap ); - setLineJoin( linejoin ); - setStrokeStyle( color.getStyle() ); + return material; - _context.stroke(); +}; - _elemBox.expandByScalar( linewidth * 2 ); +// File:src/materials/MeshPhongMaterial.js - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * emissive: <hex>, + * specular: <hex>, + * shininess: <float>, + * opacity: <float>, + * + * map: new THREE.Texture( <Image> ), + * + * lightMap: new THREE.Texture( <Image> ), + * + * bumpMap: new THREE.Texture( <Image> ), + * bumpScale: <float>, + * + * normalMap: new THREE.Texture( <Image> ), + * normalScale: <Vector2>, + * + * specularMap: new THREE.Texture( <Image> ), + * + * alphaMap: new THREE.Texture( <Image> ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: <float>, + * refractionRatio: <float>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ - function fillPath( color ) { +THREE.MeshPhongMaterial = function ( parameters ) { - setFillStyle( color.getStyle() ); - _context.fill(); + THREE.Material.call( this ); - } + this.type = 'MeshPhongMaterial'; - function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0x111111 ); + this.shininess = 30; - if ( texture instanceof THREE.DataTexture || texture.image === undefined || texture.image.width == 0 ) return; + this.metal = false; - if ( texture.needsUpdate === true ) { + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - var repeatX = texture.wrapS == THREE.RepeatWrapping; - var repeatY = texture.wrapT == THREE.RepeatWrapping; + this.map = null; - _patterns[ texture.id ] = _context.createPattern( - texture.image, repeatX === true && repeatY === true - ? 'repeat' - : repeatX === true && repeatY === false - ? 'repeat-x' - : repeatX === false && repeatY === true - ? 'repeat-y' - : 'no-repeat' - ); + this.lightMap = null; - texture.needsUpdate = false; + this.bumpMap = null; + this.bumpScale = 1; - } + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); - _patterns[ texture.id ] === undefined - ? setFillStyle( 'rgba(0,0,0,1)' ) - : setFillStyle( _patterns[ texture.id ] ); + this.specularMap = null; - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + this.alphaMap = null; - var a, b, c, d, e, f, det, idet, - offsetX = texture.offset.x / texture.repeat.x, - offsetY = texture.offset.y / texture.repeat.y, - width = texture.image.width * texture.repeat.x, - height = texture.image.height * texture.repeat.y; + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - u0 = ( u0 + offsetX ) * width; - v0 = ( 1.0 - v0 + offsetY ) * height; + this.fog = true; - u1 = ( u1 + offsetX ) * width; - v1 = ( 1.0 - v1 + offsetY ) * height; + this.shading = THREE.SmoothShading; - u2 = ( u2 + offsetX ) * width; - v2 = ( 1.0 - v2 + offsetY ) * height; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; + this.vertexColors = THREE.NoColors; - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - det = u1 * v2 - u2 * v1; + this.setValues( parameters ); - if ( det === 0 ) { +}; - if ( _imagedatas[ texture.id ] === undefined ) { +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; - var canvas = document.createElement( 'canvas' ) - canvas.width = texture.image.width; - canvas.height = texture.image.height; +THREE.MeshPhongMaterial.prototype.clone = function () { - var context = canvas.getContext( '2d' ); - context.drawImage( texture.image, 0, 0 ); + var material = new THREE.MeshPhongMaterial(); - _imagedatas[ texture.id ] = context.getImageData( 0, 0, texture.image.width, texture.image.height ).data; + THREE.Material.prototype.clone.call( this, material ); - } + material.color.copy( this.color ); + material.emissive.copy( this.emissive ); + material.specular.copy( this.specular ); + material.shininess = this.shininess; - var data = _imagedatas[ texture.id ]; - var index = ( Math.floor( u0 ) + Math.floor( v0 ) * texture.image.width ) * 4; + material.metal = this.metal; - _color.setRGB( data[ index ] / 255, data[ index + 1 ] / 255, data[ index + 2 ] / 255 ); - fillPath( _color ); + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); - return; + material.map = this.map; - } + material.lightMap = this.lightMap; - idet = 1 / det; + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; + material.specularMap = this.specularMap; - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.fill(); - _context.restore(); + material.alphaMap = this.alphaMap; - } + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; - function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { + material.fog = this.fog; - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + material.shading = this.shading; - var a, b, c, d, e, f, det, idet, - width = image.width - 1, - height = image.height - 1; + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; - u0 *= width; v0 *= height; - u1 *= width; v1 *= height; - u2 *= width; v2 *= height; + material.vertexColors = this.vertexColors; - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; + return material; - det = u1 * v2 - u2 * v1; +}; - idet = 1 / det; +// File:src/materials/MeshDepthMaterial.js - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * opacity: <float>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float> + * } + */ - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; +THREE.MeshDepthMaterial = function ( parameters ) { - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.clip(); - _context.drawImage( image, 0, 0 ); - _context.restore(); + THREE.Material.call( this ); - } + this.type = 'MeshDepthMaterial'; - function getGradientTexture( color1, color2, color3, color4 ) { + this.morphTargets = false; + this.wireframe = false; + this.wireframeLinewidth = 1; - // http://mrdoob.com/blog/post/710 + this.setValues( parameters ); - _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0; - _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0; - _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0; +}; - _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0; - _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0; - _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0; +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial; - _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0; - _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0; - _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0; +THREE.MeshDepthMaterial.prototype.clone = function () { - _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0; - _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0; - _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0; + var material = new THREE.MeshDepthMaterial(); - _pixelMapContext.putImageData( _pixelMapImage, 0, 0 ); - _gradientMapContext.drawImage( _pixelMap, 0, 0 ); + THREE.Material.prototype.clone.call( this, material ); - return _gradientMap; + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - } + return material; - // Hide anti-alias gaps +}; - function expand( v1, v2, pixels ) { +// File:src/materials/MeshNormalMaterial.js - var x = v2.x - v1.x, y = v2.y - v1.y, - det = x * x + y * y, idet; +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: <float>, + * + * shading: THREE.FlatShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float> + * } + */ - if ( det === 0 ) return; +THREE.MeshNormalMaterial = function ( parameters ) { - idet = pixels / Math.sqrt( det ); + THREE.Material.call( this, parameters ); - x *= idet; y *= idet; + this.type = 'MeshNormalMaterial'; - v2.x += x; v2.y += y; - v1.x -= x; v1.y -= y; + this.wireframe = false; + this.wireframeLinewidth = 1; - } + this.morphTargets = false; - // Context cached methods. + this.setValues( parameters ); - function setOpacity( value ) { +}; - if ( _contextGlobalAlpha !== value ) { +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial; - _context.globalAlpha = value; - _contextGlobalAlpha = value; +THREE.MeshNormalMaterial.prototype.clone = function () { - } + var material = new THREE.MeshNormalMaterial(); - } + THREE.Material.prototype.clone.call( this, material ); - function setBlending( value ) { + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - if ( _contextGlobalCompositeOperation !== value ) { + return material; - if ( value === THREE.NormalBlending ) { +}; - _context.globalCompositeOperation = 'source-over'; +// File:src/materials/MeshFaceMaterial.js - } else if ( value === THREE.AdditiveBlending ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - _context.globalCompositeOperation = 'lighter'; +THREE.MeshFaceMaterial = function ( materials ) { - } else if ( value === THREE.SubtractiveBlending ) { + this.uuid = THREE.Math.generateUUID(); - _context.globalCompositeOperation = 'darker'; + this.type = 'MeshFaceMaterial'; + + this.materials = materials instanceof Array ? materials : []; - } +}; - _contextGlobalCompositeOperation = value; +THREE.MeshFaceMaterial.prototype = { - } + constructor: THREE.MeshFaceMaterial, - } + toJSON: function () { - function setLineWidth( value ) { + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type, + materials: [] + }; - if ( _contextLineWidth !== value ) { + for ( var i = 0, l = this.materials.length; i < l; i ++ ) { - _context.lineWidth = value; - _contextLineWidth = value; + output.materials.push( this.materials[ i ].toJSON() ); } - } - - function setLineCap( value ) { + return output; - // "butt", "round", "square" - - if ( _contextLineCap !== value ) { + }, - _context.lineCap = value; - _contextLineCap = value; + clone: function () { - } + var material = new THREE.MeshFaceMaterial(); - } + for ( var i = 0; i < this.materials.length; i ++ ) { - function setLineJoin( value ) { + material.materials.push( this.materials[ i ].clone() ); - // "round", "bevel", "miter" + } - if ( _contextLineJoin !== value ) { + return material; - _context.lineJoin = value; - _contextLineJoin = value; + } - } +}; - } +// File:src/materials/PointCloudMaterial.js - function setStrokeStyle( value ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * size: <float>, + * sizeAttenuation: <bool>, + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * vertexColors: <bool>, + * + * fog: <bool> + * } + */ - if ( _contextStrokeStyle !== value ) { +THREE.PointCloudMaterial = function ( parameters ) { - _context.strokeStyle = value; - _contextStrokeStyle = value; + THREE.Material.call( this ); - } + this.type = 'PointCloudMaterial'; - } + this.color = new THREE.Color( 0xffffff ); - function setFillStyle( value ) { + this.map = null; - if ( _contextFillStyle !== value ) { + this.size = 1; + this.sizeAttenuation = true; - _context.fillStyle = value; - _contextFillStyle = value; + this.vertexColors = THREE.NoColors; - } + this.fog = true; - } + this.setValues( parameters ); - function setDashAndGap( dashSizeValue, gapSizeValue ) { +}; - if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { +THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial; - _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); - _contextDashSize = dashSizeValue; - _contextGapSize = gapSizeValue; +THREE.PointCloudMaterial.prototype.clone = function () { - } + var material = new THREE.PointCloudMaterial(); - } + THREE.Material.prototype.clone.call( this, material ); -}; + material.color.copy( this.color ); -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - */ + material.map = this.map; -THREE.ShaderChunk = { + material.size = this.size; + material.sizeAttenuation = this.sizeAttenuation; - // FOG + material.vertexColors = this.vertexColors; - fog_pars_fragment: [ + material.fog = this.fog; - "#ifdef USE_FOG", + return material; - "uniform vec3 fogColor;", +}; - "#ifdef FOG_EXP2", +// backwards compatibility - "uniform float fogDensity;", +THREE.ParticleBasicMaterial = function ( parameters ) { - "#else", + THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); + return new THREE.PointCloudMaterial( parameters ); - "uniform float fogNear;", - "uniform float fogFar;", +}; - "#endif", +THREE.ParticleSystemMaterial = function ( parameters ) { - "#endif" + THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); + return new THREE.PointCloudMaterial( parameters ); - ].join("\n"), +}; - fog_fragment: [ +// File:src/materials/ShaderMaterial.js - "#ifdef USE_FOG", +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * defines: { "label" : "value" }, + * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, + * + * fragmentShader: <string>, + * vertexShader: <string>, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * wireframe: <boolean>, + * wireframeLinewidth: <float>, + * + * lights: <bool>, + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: <bool>, + * morphTargets: <bool>, + * morphNormals: <bool>, + * + * fog: <bool> + * } + */ - "float depth = gl_FragCoord.z / gl_FragCoord.w;", +THREE.ShaderMaterial = function ( parameters ) { - "#ifdef FOG_EXP2", + THREE.Material.call( this ); - "const float LOG2 = 1.442695;", - "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", - "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + this.type = 'ShaderMaterial'; - "#else", + this.defines = {}; + this.uniforms = {}; + this.attributes = null; - "float fogFactor = smoothstep( fogNear, fogFar, depth );", + this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; + this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; - "#endif", + this.shading = THREE.SmoothShading; - "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + this.linewidth = 1; - "#endif" + this.wireframe = false; + this.wireframeLinewidth = 1; - ].join("\n"), + this.fog = false; // set to use scene fog - // ENVIRONMENT MAP + this.lights = false; // set to use scene lights - envmap_pars_fragment: [ + this.vertexColors = THREE.NoColors; // set to use "color" attribute stream - "#ifdef USE_ENVMAP", + this.skinning = false; // set to use skinning attribute streams - "uniform float reflectivity;", - "uniform samplerCube envMap;", - "uniform float flipEnvMap;", - "uniform int combine;", + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals - "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + 'color': [ 1, 1, 1 ], + 'uv': [ 0, 0 ], + 'uv2': [ 0, 0 ] + }; - "uniform bool useRefract;", - "uniform float refractionRatio;", + this.index0AttributeName = undefined; - "#else", + this.setValues( parameters ); - "varying vec3 vReflect;", +}; - "#endif", +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial; - "#endif" +THREE.ShaderMaterial.prototype.clone = function () { - ].join("\n"), + var material = new THREE.ShaderMaterial(); - envmap_fragment: [ + THREE.Material.prototype.clone.call( this, material ); - "#ifdef USE_ENVMAP", + material.fragmentShader = this.fragmentShader; + material.vertexShader = this.vertexShader; - "vec3 reflectVec;", + material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); - "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + material.attributes = this.attributes; + material.defines = this.defines; - "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + material.shading = this.shading; - "if ( useRefract ) {", + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; - "reflectVec = refract( cameraToVertex, normal, refractionRatio );", + material.fog = this.fog; - "} else { ", + material.lights = this.lights; - "reflectVec = reflect( cameraToVertex, normal );", + material.vertexColors = this.vertexColors; - "}", + material.skinning = this.skinning; - "#else", + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; - "reflectVec = vReflect;", + return material; - "#endif", +}; - "#ifdef DOUBLE_SIDED", +// File:src/materials/RawShaderMaterial.js - "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#else", +THREE.RawShaderMaterial = function ( parameters ) { - "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + THREE.ShaderMaterial.call( this, parameters ); - "#endif", + this.type = 'RawShaderMaterial'; - "#ifdef GAMMA_INPUT", +}; - "cubeColor.xyz *= cubeColor.xyz;", +THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); +THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial; - "#endif", +THREE.RawShaderMaterial.prototype.clone = function () { - "if ( combine == 1 ) {", + var material = new THREE.RawShaderMaterial(); - "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", + THREE.ShaderMaterial.prototype.clone.call( this, material ); - "} else if ( combine == 2 ) {", + return material; - "gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", +}; - "} else {", +// File:src/materials/SpriteMaterial.js - "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: <hex>, + * opacity: <float>, + * map: new THREE.Texture( <Image> ), + * + * blending: THREE.NormalBlending, + * depthTest: <bool>, + * depthWrite: <bool>, + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: <bool> + * } + */ - "}", +THREE.SpriteMaterial = function ( parameters ) { - "#endif" + THREE.Material.call( this ); - ].join("\n"), + this.type = 'SpriteMaterial'; - envmap_pars_vertex: [ + this.color = new THREE.Color( 0xffffff ); + this.map = null; - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + this.rotation = 0; - "varying vec3 vReflect;", + this.fog = false; - "uniform float refractionRatio;", - "uniform bool useRefract;", + // set parameters - "#endif" + this.setValues( parameters ); - ].join("\n"), +}; - worldpos_vertex : [ +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; - "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", +THREE.SpriteMaterial.prototype.clone = function () { - "#ifdef USE_SKINNING", + var material = new THREE.SpriteMaterial(); - "vec4 worldPosition = modelMatrix * skinned;", + THREE.Material.prototype.clone.call( this, material ); - "#endif", + material.color.copy( this.color ); + material.map = this.map; - "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + material.rotation = this.rotation; - "vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", + material.fog = this.fog; - "#endif", + return material; - "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", +}; - "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", +// File:src/textures/Texture.js - "#endif", +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ - "#endif" +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - ].join("\n"), + Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } ); - envmap_vertex : [ + this.uuid = THREE.Math.generateUUID(); - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", + this.name = ''; + this.sourceFile = ''; - "vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", - "worldNormal = normalize( worldNormal );", + this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; + this.mipmaps = []; - "vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", + this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; - "if ( useRefract ) {", + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; - "vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; - "} else {", + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - "vReflect = reflect( cameraToVertex, worldNormal );", + this.format = format !== undefined ? format : THREE.RGBAFormat; + this.type = type !== undefined ? type : THREE.UnsignedByteType; - "}", + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); - "#endif" + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - ].join("\n"), + this._needsUpdate = false; + this.onUpdate = null; - // COLOR MAP (particles) +}; - map_particle_pars_fragment: [ +THREE.Texture.DEFAULT_IMAGE = undefined; +THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; - "#ifdef USE_MAP", +THREE.Texture.prototype = { - "uniform sampler2D map;", + constructor: THREE.Texture, - "#endif" + get needsUpdate () { - ].join("\n"), + return this._needsUpdate; + }, - map_particle_fragment: [ + set needsUpdate ( value ) { - "#ifdef USE_MAP", + if ( value === true ) this.update(); - "gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", + this._needsUpdate = value; - "#endif" + }, - ].join("\n"), + clone: function ( texture ) { - // COLOR MAP (triangles) + if ( texture === undefined ) texture = new THREE.Texture(); - map_pars_vertex: [ + texture.image = this.image; + texture.mipmaps = this.mipmaps.slice( 0 ); - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + texture.mapping = this.mapping; - "varying vec2 vUv;", - "uniform vec4 offsetRepeat;", + texture.wrapS = this.wrapS; + texture.wrapT = this.wrapT; - "#endif" + texture.magFilter = this.magFilter; + texture.minFilter = this.minFilter; - ].join("\n"), + texture.anisotropy = this.anisotropy; - map_pars_fragment: [ + texture.format = this.format; + texture.type = this.type; - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + texture.offset.copy( this.offset ); + texture.repeat.copy( this.repeat ); - "varying vec2 vUv;", + texture.generateMipmaps = this.generateMipmaps; + texture.premultiplyAlpha = this.premultiplyAlpha; + texture.flipY = this.flipY; + texture.unpackAlignment = this.unpackAlignment; - "#endif", + return texture; - "#ifdef USE_MAP", + }, - "uniform sampler2D map;", + update: function () { - "#endif" + this.dispatchEvent( { type: 'update' } ); - ].join("\n"), + }, - map_vertex: [ + dispose: function () { - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + this.dispatchEvent( { type: 'dispose' } ); - "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", + } - "#endif" +}; - ].join("\n"), +THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); - map_fragment: [ +THREE.TextureIdCount = 0; - "#ifdef USE_MAP", +// File:src/textures/CubeTexture.js - "vec4 texelColor = texture2D( map, vUv );", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#ifdef GAMMA_INPUT", +THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - "texelColor.xyz *= texelColor.xyz;", + mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; + + THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "#endif", + this.images = images; - "gl_FragColor = gl_FragColor * texelColor;", +}; - "#endif" +THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; - ].join("\n"), +THREE.CubeTexture.clone = function ( texture ) { - // LIGHT MAP + if ( texture === undefined ) texture = new THREE.CubeTexture(); - lightmap_pars_fragment: [ + THREE.Texture.prototype.clone.call( this, texture ); - "#ifdef USE_LIGHTMAP", + texture.images = this.images; - "varying vec2 vUv2;", - "uniform sampler2D lightMap;", + return texture; - "#endif" +}; - ].join("\n"), +// File:src/textures/CompressedTexture.js - lightmap_pars_vertex: [ +/** + * @author alteredq / http://alteredqualia.com/ + */ - "#ifdef USE_LIGHTMAP", +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - "varying vec2 vUv2;", + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "#endif" + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; - ].join("\n"), + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) - lightmap_fragment: [ + this.flipY = false; - "#ifdef USE_LIGHTMAP", + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files - "gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", + this.generateMipmaps = false; - "#endif" +}; - ].join("\n"), +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture; - lightmap_vertex: [ +THREE.CompressedTexture.prototype.clone = function () { - "#ifdef USE_LIGHTMAP", + var texture = new THREE.CompressedTexture(); - "vUv2 = uv2;", + THREE.Texture.prototype.clone.call( this, texture ); - "#endif" + return texture; - ].join("\n"), +}; - // BUMP MAP +// File:src/textures/DataTexture.js - bumpmap_pars_fragment: [ +/** + * @author alteredq / http://alteredqualia.com/ + */ - "#ifdef USE_BUMPMAP", +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - "uniform sampler2D bumpMap;", - "uniform float bumpScale;", + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen - // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + this.image = { data: data, width: width, height: height }; - // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) +}; - "vec2 dHdxy_fwd() {", +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.DataTexture.prototype.constructor = THREE.DataTexture; - "vec2 dSTdx = dFdx( vUv );", - "vec2 dSTdy = dFdy( vUv );", +THREE.DataTexture.prototype.clone = function () { - "float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", - "float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", - "float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", + var texture = new THREE.DataTexture(); - "return vec2( dBx, dBy );", + THREE.Texture.prototype.clone.call( this, texture ); - "}", + return texture; - "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", +}; - "vec3 vSigmaX = dFdx( surf_pos );", - "vec3 vSigmaY = dFdy( surf_pos );", - "vec3 vN = surf_norm;", // normalized +// File:src/textures/VideoTexture.js - "vec3 R1 = cross( vSigmaY, vN );", - "vec3 R2 = cross( vN, vSigmaX );", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "float fDet = dot( vSigmaX, R1 );", +THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", - "return normalize( abs( fDet ) * surf_norm - vGrad );", + THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - "}", + this.generateMipmaps = false; - "#endif" + var scope = this; - ].join("\n"), + var update = function () { - // NORMAL MAP + requestAnimationFrame( update ); - normalmap_pars_fragment: [ + if ( video.readyState === video.HAVE_ENOUGH_DATA ) { - "#ifdef USE_NORMALMAP", + scope.needsUpdate = true; - "uniform sampler2D normalMap;", - "uniform vec2 normalScale;", + } - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + }; - "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", + update(); - "vec3 q0 = dFdx( eye_pos.xyz );", - "vec3 q1 = dFdy( eye_pos.xyz );", - "vec2 st0 = dFdx( vUv.st );", - "vec2 st1 = dFdy( vUv.st );", +}; - "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", - "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", - "vec3 N = normalize( surf_norm );", +THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; - "vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", - "mapN.xy = normalScale * mapN.xy;", - "mat3 tsn = mat3( S, T, N );", - "return normalize( tsn * mapN );", +// File:src/objects/Group.js - "}", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#endif" +THREE.Group = function () { - ].join("\n"), + THREE.Object3D.call( this ); - // SPECULAR MAP + this.type = 'Group'; - specularmap_pars_fragment: [ +}; - "#ifdef USE_SPECULARMAP", +THREE.Group.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Group.prototype.constructor = THREE.Group; - "uniform sampler2D specularMap;", +// File:src/objects/PointCloud.js - "#endif" +/** + * @author alteredq / http://alteredqualia.com/ + */ - ].join("\n"), +THREE.PointCloud = function ( geometry, material ) { - specularmap_fragment: [ + THREE.Object3D.call( this ); - "float specularStrength;", + this.type = 'PointCloud'; - "#ifdef USE_SPECULARMAP", + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } ); - "vec4 texelSpecular = texture2D( specularMap, vUv );", - "specularStrength = texelSpecular.r;", +}; - "#else", +THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype ); +THREE.PointCloud.prototype.constructor = THREE.PointCloud; - "specularStrength = 1.0;", +THREE.PointCloud.prototype.raycast = ( function () { - "#endif" + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); - ].join("\n"), + return function ( raycaster, intersects ) { - // LIGHTS LAMBERT + var object = this; + var geometry = object.geometry; + var threshold = raycaster.params.PointCloud.threshold; - lights_lambert_pars_vertex: [ + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - "uniform vec3 ambient;", - "uniform vec3 diffuse;", - "uniform vec3 emissive;", + if ( geometry.boundingBox !== null ) { - "uniform vec3 ambientLightColor;", + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - "#if MAX_DIR_LIGHTS > 0", + return; - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + } - "#endif", + } - "#if MAX_HEMI_LIGHTS > 0", + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var position = new THREE.Vector3(); - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + var testPoint = function ( point, index ) { - "#endif", + var rayPointDistance = ray.distanceToPoint( point ); - "#if MAX_POINT_LIGHTS > 0", + if ( rayPointDistance < localThreshold ) { - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + var intersectPoint = ray.closestPointToPoint( point ); + intersectPoint.applyMatrix4( object.matrixWorld ); - "#endif", + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - "#if MAX_SPOT_LIGHTS > 0", + intersects.push( { - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + distance: distance, + distanceToRay: rayPointDistance, + point: intersectPoint.clone(), + index: index, + face: null, + object: object - "#endif", + } ); - "#ifdef WRAP_AROUND", + } - "uniform vec3 wrapRGB;", + }; - "#endif" + if ( geometry instanceof THREE.BufferGeometry ) { - ].join("\n"), + var attributes = geometry.attributes; + var positions = attributes.position.array; - lights_lambert_vertex: [ + if ( attributes.index !== undefined ) { - "vLightFront = vec3( 0.0 );", + var indices = attributes.index.array; + var offsets = geometry.offsets; - "#ifdef DOUBLE_SIDED", + if ( offsets.length === 0 ) { - "vLightBack = vec3( 0.0 );", + var offset = { + start: 0, + count: indices.length, + index: 0 + }; - "#endif", + offsets = [ offset ]; - "transformedNormal = normalize( transformedNormal );", + } - "#if MAX_DIR_LIGHTS > 0", + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", + for ( var i = start, il = start + count; i < il; i ++ ) { - "float dotProduct = dot( transformedNormal, dirVector );", - "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", + var a = index + indices[ i ]; - "#ifdef DOUBLE_SIDED", + position.fromArray( positions, a * 3 ); - "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + testPoint( position, a ); - "#ifdef WRAP_AROUND", + } - "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + } - "#endif", + } else { - "#endif", + var pointCount = positions.length / 3; - "#ifdef WRAP_AROUND", + for ( var i = 0; i < pointCount; i ++ ) { - "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", + position.set( + positions[ 3 * i ], + positions[ 3 * i + 1 ], + positions[ 3 * i + 2 ] + ); - "#ifdef DOUBLE_SIDED", + testPoint( position, i ); - "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", + } - "#endif", + } - "#endif", + } else { - "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", + var vertices = this.geometry.vertices; - "#ifdef DOUBLE_SIDED", + for ( var i = 0; i < vertices.length; i ++ ) { - "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", + testPoint( vertices[ i ], i ); - "#endif", + } - "}", + } - "#endif", + }; - "#if MAX_POINT_LIGHTS > 0", +}() ); - "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", +THREE.PointCloud.prototype.clone = function ( object ) { - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material ); - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + THREE.Object3D.prototype.clone.call( this, object ); - "lVector = normalize( lVector );", - "float dotProduct = dot( transformedNormal, lVector );", + return object; - "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", +}; - "#ifdef DOUBLE_SIDED", +// Backwards compatibility - "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", +THREE.ParticleSystem = function ( geometry, material ) { - "#ifdef WRAP_AROUND", + THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); + return new THREE.PointCloud( geometry, material ); - "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", +}; - "#endif", +// File:src/objects/Line.js - "#endif", +/** + * @author mrdoob / http://mrdoob.com/ + */ - "#ifdef WRAP_AROUND", +THREE.Line = function ( geometry, material, mode ) { - "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", + THREE.Object3D.call( this ); - "#ifdef DOUBLE_SIDED", + this.type = 'Line'; - "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - "#endif", + this.mode = mode !== undefined ? mode : THREE.LineStrip; - "#endif", +}; - "vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", +THREE.LineStrip = 0; +THREE.LinePieces = 1; - "#ifdef DOUBLE_SIDED", +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Line.prototype.constructor = THREE.Line; - "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", +THREE.Line.prototype.raycast = ( function () { - "#endif", + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - "}", + return function ( raycaster, intersects ) { - "#endif", + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; - "#if MAX_SPOT_LIGHTS > 0", + var geometry = this.geometry; - "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + // Checking boundingSphere distance to ray - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - "if ( spotEffect > spotLightAngleCos[ i ] ) {", + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + return; - "float lDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + } - "lVector = normalize( lVector );", + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - "float dotProduct = dot( transformedNormal, lVector );", - "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", + var vStart = new THREE.Vector3(); + var vEnd = new THREE.Vector3(); + var interSegment = new THREE.Vector3(); + var interRay = new THREE.Vector3(); + var step = this.mode === THREE.LineStrip ? 1 : 2; - "#ifdef DOUBLE_SIDED", + if ( geometry instanceof THREE.BufferGeometry ) { - "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + var attributes = geometry.attributes; - "#ifdef WRAP_AROUND", + if ( attributes.index !== undefined ) { - "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + var indices = attributes.index.array; + var positions = attributes.position.array; + var offsets = geometry.offsets; - "#endif", + if ( offsets.length === 0 ) { - "#endif", + offsets = [ { start: 0, count: indices.length, index: 0 } ]; - "#ifdef WRAP_AROUND", + } - "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", + for ( var oi = 0; oi < offsets.length; oi ++) { - "#ifdef DOUBLE_SIDED", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", + for ( var i = start; i < start + count - 1; i += step ) { - "#endif", + var a = index + indices[ i ]; + var b = index + indices[ i + 1 ]; - "#endif", + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); - "vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - "#ifdef DOUBLE_SIDED", + if ( distSq > precisionSq ) continue; - "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", + var distance = ray.origin.distanceTo( interRay ); - "#endif", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - "}", + intersects.push( { - "}", + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + offsetIndex: oi, + face: null, + faceIndex: null, + object: this - "#endif", + } ); - "#if MAX_HEMI_LIGHTS > 0", + } - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + } - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", + } else { - "float dotProduct = dot( transformedNormal, lVector );", + var positions = attributes.position.array; - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", + for ( var i = 0; i < positions.length / 3 - 1; i += step ) { - "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + vStart.fromArray( positions, 3 * i ); + vEnd.fromArray( positions, 3 * i + 3 ); - "#ifdef DOUBLE_SIDED", + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", + if ( distSq > precisionSq ) continue; - "#endif", + var distance = ray.origin.distanceTo( interRay ); - "}", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - "#endif", + intersects.push( { - "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this - "#ifdef DOUBLE_SIDED", + } ); - "vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", + } - "#endif" + } - ].join("\n"), + } else if ( geometry instanceof THREE.Geometry ) { - // LIGHTS PHONG + var vertices = geometry.vertices; + var nbVertices = vertices.length; - lights_phong_pars_vertex: [ + for ( var i = 0; i < nbVertices - 1; i += step ) { - "#ifndef PHONG_PER_PIXEL", + var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - "#if MAX_POINT_LIGHTS > 0", + if ( distSq > precisionSq ) continue; - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + var distance = ray.origin.distanceTo( interRay ); - "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];", + if ( distance < raycaster.near || distance > raycaster.far ) continue; - "#endif", + intersects.push( { - "#if MAX_SPOT_LIGHTS > 0", + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + } ); - "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];", + } - "#endif", + } - "#endif", + }; - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", +}() ); - "varying vec3 vWorldPosition;", +THREE.Line.prototype.clone = function ( object ) { - "#endif" + if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode ); - ].join("\n"), + THREE.Object3D.prototype.clone.call( this, object ); + return object; - lights_phong_vertex: [ +}; - "#ifndef PHONG_PER_PIXEL", +// File:src/objects/Mesh.js - "#if MAX_POINT_LIGHTS > 0", +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ - "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", +THREE.Mesh = function ( geometry, material ) { - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + THREE.Object3D.call( this ); - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + this.type = 'Mesh'; + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - "vPointLight[ i ] = vec4( lVector, lDistance );", + this.updateMorphTargets(); - "}", +}; - "#endif", +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Mesh.prototype.constructor = THREE.Mesh; - "#if MAX_SPOT_LIGHTS > 0", +THREE.Mesh.prototype.updateMorphTargets = function () { - "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + this.morphTargetBase = - 1; + this.morphTargetForcedOrder = []; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - "float lDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - "vSpotLight[ i ] = vec4( lVector, lDistance );", + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - "}", + } - "#endif", + } - "#endif", +}; - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - "vWorldPosition = worldPosition.xyz;", + if ( this.morphTargetDictionary[ name ] !== undefined ) { - "#endif" + return this.morphTargetDictionary[ name ]; - ].join("\n"), + } - lights_phong_pars_fragment: [ + THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); - "uniform vec3 ambientLightColor;", + return 0; - "#if MAX_DIR_LIGHTS > 0", +}; - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - "#endif", +THREE.Mesh.prototype.raycast = ( function () { - "#if MAX_HEMI_LIGHTS > 0", + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + var vA = new THREE.Vector3(); + var vB = new THREE.Vector3(); + var vC = new THREE.Vector3(); - "#endif", + return function ( raycaster, intersects ) { - "#if MAX_POINT_LIGHTS > 0", + var geometry = this.geometry; - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + // Checking boundingSphere distance to ray - "#ifdef PHONG_PER_PIXEL", + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - "#else", + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - "varying vec4 vPointLight[ MAX_POINT_LIGHTS ];", + return; - "#endif", + } - "#endif", + // Check boundingBox before continuing - "#if MAX_SPOT_LIGHTS > 0", + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + if ( geometry.boundingBox !== null ) { - "#ifdef PHONG_PER_PIXEL", + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + return; - "#else", + } - "varying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];", + } - "#endif", + if ( geometry instanceof THREE.BufferGeometry ) { - "#endif", + var material = this.material; - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + if ( material === undefined ) return; - "varying vec3 vWorldPosition;", + var attributes = geometry.attributes; - "#endif", + var a, b, c; + var precision = raycaster.precision; - "#ifdef WRAP_AROUND", + if ( attributes.index !== undefined ) { - "uniform vec3 wrapRGB;", + var indices = attributes.index.array; + var positions = attributes.position.array; + var offsets = geometry.offsets; - "#endif", + if ( offsets.length === 0 ) { - "varying vec3 vViewPosition;", - "varying vec3 vNormal;" + offsets = [ { start: 0, count: indices.length, index: 0 } ]; - ].join("\n"), + } - lights_phong_fragment: [ + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { - "vec3 normal = normalize( vNormal );", - "vec3 viewPosition = normalize( vViewPosition );", + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; - "#ifdef DOUBLE_SIDED", + for ( var i = start, il = start + count; i < il; i += 3 ) { - "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + a = index + indices[ i ]; + b = index + indices[ i + 1 ]; + c = index + indices[ i + 2 ]; - "#endif", + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - "#ifdef USE_NORMALMAP", + if ( material.side === THREE.BackSide ) { - "normal = perturbNormal2Arb( -vViewPosition, normal );", + var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - "#elif defined( USE_BUMPMAP )", + } else { - "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - "#endif", + } - "#if MAX_POINT_LIGHTS > 0", + if ( intersectionPoint === null ) continue; - "vec3 pointDiffuse = vec3( 0.0 );", - "vec3 pointSpecular = vec3( 0.0 );", + intersectionPoint.applyMatrix4( this.matrixWorld ); - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - "#ifdef PHONG_PER_PIXEL", + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + intersects.push( { - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + distance: distance, + point: intersectionPoint, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + faceIndex: null, + object: this - "lVector = normalize( lVector );", + } ); - "#else", + } - "vec3 lVector = normalize( vPointLight[ i ].xyz );", - "float lDistance = vPointLight[ i ].w;", + } - "#endif", + } else { - // diffuse + var positions = attributes.position.array; - "float dotProduct = dot( normal, lVector );", + for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) { - "#ifdef WRAP_AROUND", + a = i; + b = i + 1; + c = i + 2; - "float pointDiffuseWeightFull = max( dotProduct, 0.0 );", - "float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + vA.fromArray( positions, j ); + vB.fromArray( positions, j + 3 ); + vC.fromArray( positions, j + 6 ); - "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + if ( material.side === THREE.BackSide ) { - "#else", + var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); - "float pointDiffuseWeight = max( dotProduct, 0.0 );", + } else { - "#endif", + var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - "pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", + } - // specular + if ( intersectionPoint === null ) continue; - "vec3 pointHalfVector = normalize( lVector + viewPosition );", - "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + intersectionPoint.applyMatrix4( this.matrixWorld ); - "#ifdef PHYSICALLY_BASED_SHADING", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - // 2.0 => 2.0001 is hack to work around ANGLE bug + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + intersects.push( { - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );", - "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", + distance: distance, + point: intersectionPoint, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + faceIndex: null, + object: this - "#else", + } ); - "pointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;", + } - "#endif", + } - "}", + } else if ( geometry instanceof THREE.Geometry ) { - "#endif", + var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? this.material.materials : null; - "#if MAX_SPOT_LIGHTS > 0", + var a, b, c; + var precision = raycaster.precision; - "vec3 spotDiffuse = vec3( 0.0 );", - "vec3 spotSpecular = vec3( 0.0 );", + var vertices = geometry.vertices; - "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - "#ifdef PHONG_PER_PIXEL", + var face = geometry.faces[ f ]; - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material; - "float lDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + if ( material === undefined ) continue; - "lVector = normalize( lVector );", + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; - "#else", + if ( material.morphTargets === true ) { - "vec3 lVector = normalize( vSpotLight[ i ].xyz );", - "float lDistance = vSpotLight[ i ].w;", + var morphTargets = geometry.morphTargets; + var morphInfluences = this.morphTargetInfluences; - "#endif", + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - "if ( spotEffect > spotLightAngleCos[ i ] ) {", + var influence = morphInfluences[ t ]; - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + if ( influence === 0 ) continue; - // diffuse + var targets = morphTargets[ t ].vertices; - "float dotProduct = dot( normal, lVector );", + vA.x += ( targets[ face.a ].x - a.x ) * influence; + vA.y += ( targets[ face.a ].y - a.y ) * influence; + vA.z += ( targets[ face.a ].z - a.z ) * influence; - "#ifdef WRAP_AROUND", + vB.x += ( targets[ face.b ].x - b.x ) * influence; + vB.y += ( targets[ face.b ].y - b.y ) * influence; + vB.z += ( targets[ face.b ].z - b.z ) * influence; - "float spotDiffuseWeightFull = max( dotProduct, 0.0 );", - "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + vC.x += ( targets[ face.c ].x - c.x ) * influence; + vC.y += ( targets[ face.c ].y - c.y ) * influence; + vC.z += ( targets[ face.c ].z - c.z ) * influence; - "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + } - "#else", + vA.add( a ); + vB.add( b ); + vC.add( c ); - "float spotDiffuseWeight = max( dotProduct, 0.0 );", + a = vA; + b = vB; + c = vC; - "#endif", + } - "spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", + if ( material.side === THREE.BackSide ) { - // specular + var intersectionPoint = ray.intersectTriangle( c, b, a, true ); - "vec3 spotHalfVector = normalize( lVector + viewPosition );", - "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - "float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + } else { - "#ifdef PHYSICALLY_BASED_SHADING", + var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); - // 2.0 => 2.0001 is hack to work around ANGLE bug + } - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + if ( intersectionPoint === null ) continue; - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );", - "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", + intersectionPoint.applyMatrix4( this.matrixWorld ); - "#else", + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - "spotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;", + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - "#endif", + intersects.push( { - "}", + distance: distance, + point: intersectionPoint, + face: face, + faceIndex: f, + object: this - "}", + } ); - "#endif", + } - "#if MAX_DIR_LIGHTS > 0", + } - "vec3 dirDiffuse = vec3( 0.0 );", - "vec3 dirSpecular = vec3( 0.0 );" , + }; - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", +}() ); - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", +THREE.Mesh.prototype.clone = function ( object, recursive ) { - // diffuse + if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); - "float dotProduct = dot( normal, dirVector );", + THREE.Object3D.prototype.clone.call( this, object, recursive ); - "#ifdef WRAP_AROUND", + return object; - "float dirDiffuseWeightFull = max( dotProduct, 0.0 );", - "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", +}; - "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", +// File:src/objects/Bone.js - "#else", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - "float dirDiffuseWeight = max( dotProduct, 0.0 );", +THREE.Bone = function ( skin ) { - "#endif", + THREE.Object3D.call( this ); - "dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", + this.type = 'Bone'; - // specular + this.skin = skin; - "vec3 dirHalfVector = normalize( dirVector + viewPosition );", - "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", +}; - "#ifdef PHYSICALLY_BASED_SHADING", +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Bone.prototype.constructor = THREE.Bone; - /* - // fresnel term from skin shader - "const float F0 = 0.128;", +// File:src/objects/Skeleton.js - "float base = 1.0 - dot( viewPosition, dirHalfVector );", - "float exponential = pow( base, 5.0 );", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author michael guerrero / http://realitymeltdown.com + * @author ikerr / http://verold.com + */ - "float fresnel = exponential + F0 * ( 1.0 - exponential );", - */ +THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { - /* - // fresnel term from fresnel shader - "const float mFresnelBias = 0.08;", - "const float mFresnelScale = 0.3;", - "const float mFresnelPower = 5.0;", + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - "float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", - */ + this.identityMatrix = new THREE.Matrix4(); - // 2.0 => 2.0001 is hack to work around ANGLE bug + // copy the bone array - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + bones = bones || []; - //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", + this.bones = bones.slice( 0 ); - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", - "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + // create a bone texture or an array of floats - "#else", + if ( this.useVertexTexture ) { - "dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;", + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones (8 * 8 / 4) + // 16x16 pixel texture max 64 bones (16 * 16 / 4) + // 32x32 pixel texture max 256 bones (32 * 32 / 4) + // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - "#endif", + var size; - "}", + if ( this.bones.length > 256 ) + size = 64; + else if ( this.bones.length > 64 ) + size = 32; + else if ( this.bones.length > 16 ) + size = 16; + else + size = 8; - "#endif", + this.boneTextureWidth = size; + this.boneTextureHeight = size; - "#if MAX_HEMI_LIGHTS > 0", + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); + this.boneTexture.minFilter = THREE.NearestFilter; + this.boneTexture.magFilter = THREE.NearestFilter; + this.boneTexture.generateMipmaps = false; + this.boneTexture.flipY = false; - "vec3 hemiDiffuse = vec3( 0.0 );", - "vec3 hemiSpecular = vec3( 0.0 );" , + } else { - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + this.boneMatrices = new Float32Array( 16 * this.bones.length ); - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", + } - // diffuse + // use the supplied bone inverses or calculate the inverses - "float dotProduct = dot( normal, lVector );", - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + if ( boneInverses === undefined ) { - "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + this.calculateInverses(); - "hemiDiffuse += diffuse * hemiColor;", + } else { - // specular (sky light) + if ( this.bones.length === boneInverses.length ) { - "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", - "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + this.boneInverses = boneInverses.slice( 0 ); - // specular (ground light) + } else { - "vec3 lVectorGround = -lVector;", + THREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", - "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + this.boneInverses = []; - "#ifdef PHYSICALLY_BASED_SHADING", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "float dotProductGround = dot( normal, lVectorGround );", + this.boneInverses.push( new THREE.Matrix4() ); - // 2.0 => 2.0001 is hack to work around ANGLE bug + } - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + } - "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", - "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", - "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + } - "#else", +}; - "hemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;", +THREE.Skeleton.prototype.calculateInverses = function () { - "#endif", + this.boneInverses = []; - "}", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#endif", + var inverse = new THREE.Matrix4(); - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", + if ( this.bones[ b ] ) { - "#if MAX_DIR_LIGHTS > 0", + inverse.getInverse( this.bones[ b ].matrixWorld ); - "totalDiffuse += dirDiffuse;", - "totalSpecular += dirSpecular;", + } - "#endif", + this.boneInverses.push( inverse ); - "#if MAX_HEMI_LIGHTS > 0", + } - "totalDiffuse += hemiDiffuse;", - "totalSpecular += hemiSpecular;", +}; - "#endif", +THREE.Skeleton.prototype.pose = function () { - "#if MAX_POINT_LIGHTS > 0", + var bone; - "totalDiffuse += pointDiffuse;", - "totalSpecular += pointSpecular;", + // recover the bind-time world matrices - "#endif", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#if MAX_SPOT_LIGHTS > 0", + bone = this.bones[ b ]; - "totalDiffuse += spotDiffuse;", - "totalSpecular += spotSpecular;", + if ( bone ) { - "#endif", + bone.matrixWorld.getInverse( this.boneInverses[ b ] ); - "#ifdef METAL", + } - "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", + } - "#else", + // compute the local matrices, positions, rotations and scales - "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#endif" + bone = this.bones[ b ]; - ].join("\n"), + if ( bone ) { - // VERTEX COLORS + if ( bone.parent ) { - color_pars_fragment: [ + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( bone.matrixWorld ); - "#ifdef USE_COLOR", + } else { - "varying vec3 vColor;", + bone.matrix.copy( bone.matrixWorld ); - "#endif" + } - ].join("\n"), + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + } - color_fragment: [ + } - "#ifdef USE_COLOR", +}; - "gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", +THREE.Skeleton.prototype.update = ( function () { - "#endif" + var offsetMatrix = new THREE.Matrix4(); + + return function () { - ].join("\n"), + // flatten bone matrices to array - color_pars_vertex: [ + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - "#ifdef USE_COLOR", + // compute the offset between the current and the original transform - "varying vec3 vColor;", + var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; - "#endif" + offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); + offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); - ].join("\n"), + } + if ( this.useVertexTexture ) { - color_vertex: [ + this.boneTexture.needsUpdate = true; - "#ifdef USE_COLOR", + } + + }; - "#ifdef GAMMA_INPUT", +} )(); - "vColor = color * color;", - "#else", +// File:src/objects/SkinnedMesh.js - "vColor = color;", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - "#endif", +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - "#endif" + THREE.Mesh.call( this, geometry, material ); - ].join("\n"), + this.type = 'SkinnedMesh'; - // SKINNING + this.bindMode = "attached"; + this.bindMatrix = new THREE.Matrix4(); + this.bindMatrixInverse = new THREE.Matrix4(); - skinning_pars_vertex: [ + // init bones - "#ifdef USE_SKINNING", + // TODO: remove bone creation as there is no reason (other than + // convenience) for THREE.SkinnedMesh to do this. - "#ifdef BONE_TEXTURE", + var bones = []; - "uniform sampler2D boneTexture;", - "uniform int boneTextureWidth;", - "uniform int boneTextureHeight;", + if ( this.geometry && this.geometry.bones !== undefined ) { - "mat4 getBoneMatrix( const in float i ) {", + var bone, gbone, p, q, s; - "float j = i * 4.0;", - "float x = mod( j, float( boneTextureWidth ) );", - "float y = floor( j / float( boneTextureWidth ) );", + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - "float dx = 1.0 / float( boneTextureWidth );", - "float dy = 1.0 / float( boneTextureHeight );", + gbone = this.geometry.bones[ b ]; - "y = dy * ( y + 0.5 );", + p = gbone.pos; + q = gbone.rotq; + s = gbone.scl; - "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", - "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", - "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", - "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", + bone = new THREE.Bone( this ); + bones.push( bone ); - "mat4 bone = mat4( v1, v2, v3, v4 );", + bone.name = gbone.name; + bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] ); + bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] ); - "return bone;", + if ( s !== undefined ) { - "}", + bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] ); - "#else", + } else { - "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", + bone.scale.set( 1, 1, 1 ); - "mat4 getBoneMatrix( const in float i ) {", + } - "mat4 bone = boneGlobalMatrices[ int(i) ];", - "return bone;", + } - "}", + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - "#endif", + gbone = this.geometry.bones[ b ]; - "#endif" + if ( gbone.parent !== - 1 ) { - ].join("\n"), + bones[ gbone.parent ].add( bones[ b ] ); - skinbase_vertex: [ + } else { - "#ifdef USE_SKINNING", + this.add( bones[ b ] ); - "mat4 boneMatX = getBoneMatrix( skinIndex.x );", - "mat4 boneMatY = getBoneMatrix( skinIndex.y );", + } - "#endif" + } - ].join("\n"), + } - skinning_vertex: [ + this.normalizeSkinWeights(); - "#ifdef USE_SKINNING", + this.updateMatrixWorld( true ); + this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) ); - "#ifdef USE_MORPHTARGETS", +}; - "vec4 skinVertex = vec4( morphed, 1.0 );", - "#else", +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; - "vec4 skinVertex = vec4( position, 1.0 );", +THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { - "#endif", + this.skeleton = skeleton; - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", + if ( bindMatrix === undefined ) { - "#endif" + this.updateMatrixWorld( true ); - ].join("\n"), + bindMatrix = this.matrixWorld; - // MORPHING + } - morphtarget_pars_vertex: [ + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); - "#ifdef USE_MORPHTARGETS", +}; - "#ifndef USE_MORPHNORMALS", +THREE.SkinnedMesh.prototype.pose = function () { - "uniform float morphTargetInfluences[ 8 ];", + this.skeleton.pose(); - "#else", +}; - "uniform float morphTargetInfluences[ 4 ];", +THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - "#endif", + if ( this.geometry instanceof THREE.Geometry ) { - "#endif" + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - ].join("\n"), + var sw = this.geometry.skinWeights[ i ]; - morphtarget_vertex: [ + var scale = 1.0 / sw.lengthManhattan(); - "#ifdef USE_MORPHTARGETS", + if ( scale !== Infinity ) { - "vec3 morphed = vec3( 0.0 );", - "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", - "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", - "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", - "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", + sw.multiplyScalar( scale ); - "#ifndef USE_MORPHNORMALS", + } else { - "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", - "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", - "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", - "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", + sw.set( 1 ); // this will be normalized by the shader anyway - "#endif", + } - "morphed += position;", + } - "#endif" + } else { - ].join("\n"), + // skinning weights assumed to be normalized for THREE.BufferGeometry - default_vertex : [ + } - "vec4 mvPosition;", +}; - "#ifdef USE_SKINNING", +THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { - "mvPosition = modelViewMatrix * skinned;", + THREE.Mesh.prototype.updateMatrixWorld.call( this, true ); - "#endif", + if ( this.bindMode === "attached" ) { - "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", + this.bindMatrixInverse.getInverse( this.matrixWorld ); - "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", + } else if ( this.bindMode === "detached" ) { - "#endif", + this.bindMatrixInverse.getInverse( this.bindMatrix ); - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", + } else { - "mvPosition = modelViewMatrix * vec4( position, 1.0 );", + THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); - "#endif", + } - "gl_Position = projectionMatrix * mvPosition;" +}; - ].join("\n"), +THREE.SkinnedMesh.prototype.clone = function( object ) { - morphnormal_vertex: [ + if ( object === undefined ) { - "#ifdef USE_MORPHNORMALS", + object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); - "vec3 morphedNormal = vec3( 0.0 );", + } - "morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", - "morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", - "morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", - "morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", + THREE.Mesh.prototype.clone.call( this, object ); - "morphedNormal += normal;", + return object; - "#endif" +}; - ].join("\n"), - skinnormal_vertex: [ +// File:src/objects/MorphAnimMesh.js - "#ifdef USE_SKINNING", +/** + * @author alteredq / http://alteredqualia.com/ + */ - "mat4 skinMatrix = skinWeight.x * boneMatX;", - "skinMatrix += skinWeight.y * boneMatY;", +THREE.MorphAnimMesh = function ( geometry, material ) { - "#ifdef USE_MORPHNORMALS", + THREE.Mesh.call( this, geometry, material ); - "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", + this.type = 'MorphAnimMesh'; - "#else", + // API - "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", + this.duration = 1000; // milliseconds + this.mirroredLoop = false; + this.time = 0; - "#endif", + // internals - "#endif" + this.lastKeyframe = 0; + this.currentKeyframe = 0; - ].join("\n"), + this.direction = 1; + this.directionBackwards = false; - defaultnormal_vertex: [ + this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); - "vec3 objectNormal;", +}; - "#ifdef USE_SKINNING", +THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.MorphAnimMesh.prototype.constructor = THREE.MorphAnimMesh; - "objectNormal = skinnedNormal.xyz;", +THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { - "#endif", + this.startKeyframe = start; + this.endKeyframe = end; - "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", + this.length = this.endKeyframe - this.startKeyframe + 1; - "objectNormal = morphedNormal;", +}; - "#endif", +THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", + this.direction = 1; + this.directionBackwards = false; - "objectNormal = normal;", +}; - "#endif", +THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - "#ifdef FLIP_SIDED", + this.direction = - 1; + this.directionBackwards = true; - "objectNormal = -objectNormal;", +}; - "#endif", +THREE.MorphAnimMesh.prototype.parseAnimations = function () { - "vec3 transformedNormal = normalMatrix * objectNormal;" + var geometry = this.geometry; - ].join("\n"), + if ( ! geometry.animations ) geometry.animations = {}; - // SHADOW MAP + var firstAnimation, animations = geometry.animations; - // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples - // http://spidergl.org/example.php?id=6 - // http://fabiensanglard.net/shadowmapping + var pattern = /([a-z]+)_?(\d+)/; - shadowmap_pars_fragment: [ + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - "#ifdef USE_SHADOWMAP", + var morph = geometry.morphTargets[ i ]; + var parts = morph.name.match( pattern ); - "uniform sampler2D shadowMap[ MAX_SHADOWS ];", - "uniform vec2 shadowMapSize[ MAX_SHADOWS ];", + if ( parts && parts.length > 1 ) { - "uniform float shadowDarkness[ MAX_SHADOWS ];", - "uniform float shadowBias[ MAX_SHADOWS ];", + var label = parts[ 1 ]; - "varying vec4 vShadowCoord[ MAX_SHADOWS ];", + if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity }; - "float unpackDepth( const in vec4 rgba_depth ) {", + var animation = animations[ label ]; - "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", - "float depth = dot( rgba_depth, bit_shift );", - "return depth;", + if ( i < animation.start ) animation.start = i; + if ( i > animation.end ) animation.end = i; - "}", + if ( ! firstAnimation ) firstAnimation = label; - "#endif" + } - ].join("\n"), + } - shadowmap_fragment: [ + geometry.firstAnimation = firstAnimation; - "#ifdef USE_SHADOWMAP", +}; - "#ifdef SHADOWMAP_DEBUG", +THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { - "vec3 frustumColors[3];", - "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", - "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", - "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", + if ( ! this.geometry.animations ) this.geometry.animations = {}; - "#endif", + this.geometry.animations[ label ] = { start: start, end: end }; - "#ifdef SHADOWMAP_CASCADE", +}; - "int inFrustumCount = 0;", +THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { - "#endif", + var animation = this.geometry.animations[ label ]; - "float fDepth;", - "vec3 shadowColor = vec3( 1.0 );", + if ( animation ) { - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + this.setFrameRange( animation.start, animation.end ); + this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); + this.time = 0; - "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", + } else { - // "if ( something && something )" breaks ATI OpenGL shader compiler - // "if ( all( something, something ) )" using this instead + THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' ); - "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", - "bool inFrustum = all( inFrustumVec );", + } - // don't shadow pixels outside of light frustum - // use just first frustum (for cascades) - // don't shadow pixels behind far plane of light frustum +}; - "#ifdef SHADOWMAP_CASCADE", +THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { - "inFrustumCount += int( inFrustum );", - "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", + var frameTime = this.duration / this.length; - "#else", + this.time += this.direction * delta; - "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", + if ( this.mirroredLoop ) { - "#endif", + if ( this.time > this.duration || this.time < 0 ) { - "bool frustumTest = all( frustumTestVec );", + this.direction *= - 1; - "if ( frustumTest ) {", + if ( this.time > this.duration ) { - "shadowCoord.z += shadowBias[ i ];", + this.time = this.duration; + this.directionBackwards = true; - "#if defined( SHADOWMAP_TYPE_PCF )", + } - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ + if ( this.time < 0 ) { - "float shadow = 0.0;", + this.time = 0; + this.directionBackwards = false; - /* - // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL - // must enroll loop manually + } - "for ( float y = -1.25; y <= 1.25; y += 1.25 )", - "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", + } - "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", + } else { - // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup - //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", + this.time = this.time % this.duration; - "float fDepth = unpackDepth( rgbaDepth );", + if ( this.time < 0 ) this.time += this.duration; - "if ( fDepth < shadowCoord.z )", - "shadow += 1.0;", + } - "}", + var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); - "shadow /= 9.0;", + if ( keyframe !== this.currentKeyframe ) { - */ + this.morphTargetInfluences[ this.lastKeyframe ] = 0; + this.morphTargetInfluences[ this.currentKeyframe ] = 1; - "const float shadowDelta = 1.0 / 9.0;", + this.morphTargetInfluences[ keyframe ] = 0; - "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + this.lastKeyframe = this.currentKeyframe; + this.currentKeyframe = keyframe; - "float dx0 = -1.25 * xPixelOffset;", - "float dy0 = -1.25 * yPixelOffset;", - "float dx1 = 1.25 * xPixelOffset;", - "float dy1 = 1.25 * yPixelOffset;", + } - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + var mix = ( this.time % frameTime ) / frameTime; - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + if ( this.directionBackwards ) { - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + mix = 1 - mix; - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + } - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + this.morphTargetInfluences[ this.currentKeyframe ] = mix; + this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", +}; - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", +THREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) { - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + var influences = this.morphTargetInfluences; - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + for ( var i = 0, l = influences.length; i < l; i ++ ) { - "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + influences[ i ] = 0; - "#elif defined( SHADOWMAP_TYPE_PCF_SOFT )", + } - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ + if ( a > -1 ) influences[ a ] = 1 - t; + if ( b > -1 ) influences[ b ] = t; - "float shadow = 0.0;", +}; - "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", +THREE.MorphAnimMesh.prototype.clone = function ( object ) { - "float dx0 = -1.0 * xPixelOffset;", - "float dy0 = -1.0 * yPixelOffset;", - "float dx1 = 1.0 * xPixelOffset;", - "float dy1 = 1.0 * yPixelOffset;", + if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); - "mat3 shadowKernel;", - "mat3 depthKernel;", + object.duration = this.duration; + object.mirroredLoop = this.mirroredLoop; + object.time = this.time; - "depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - "depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - "depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - "depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - "depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - "depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - "depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - "depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - "depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + object.lastKeyframe = this.lastKeyframe; + object.currentKeyframe = this.currentKeyframe; - "vec3 shadowZ = vec3( shadowCoord.z );", - "shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", - "shadowKernel[0] *= vec3(0.25);", + object.direction = this.direction; + object.directionBackwards = this.directionBackwards; - "shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", - "shadowKernel[1] *= vec3(0.25);", + THREE.Mesh.prototype.clone.call( this, object ); - "shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", - "shadowKernel[2] *= vec3(0.25);", + return object; - "vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", +}; - "shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", - "shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", +// File:src/objects/LOD.js - "vec4 shadowValues;", - "shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", - "shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", - "shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", - "shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - "shadow = dot( shadowValues, vec4( 1.0 ) );", +THREE.LOD = function () { - "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + THREE.Object3D.call( this ); - "#else", + this.objects = []; - "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", - "float fDepth = unpackDepth( rgbaDepth );", +}; - "if ( fDepth < shadowCoord.z )", - // spot with multiple shadows is darker +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); +THREE.LOD.prototype.constructor = THREE.LOD; - "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", +THREE.LOD.prototype.addLevel = function ( object, distance ) { - // spot with multiple shadows has the same color as single shadow spot + if ( distance === undefined ) distance = 0; - //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", + distance = Math.abs( distance ); - "#endif", + for ( var l = 0; l < this.objects.length; l ++ ) { - "}", + if ( distance < this.objects[ l ].distance ) { + break; - "#ifdef SHADOWMAP_DEBUG", + } - "#ifdef SHADOWMAP_CASCADE", + } - "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", + this.objects.splice( l, 0, { distance: distance, object: object } ); + this.add( object ); - "#else", +}; - "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", +THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - "#endif", + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - "#endif", + if ( distance < this.objects[ i ].distance ) { - "}", + break; - "#ifdef GAMMA_OUTPUT", + } - "shadowColor *= shadowColor;", + } - "#endif", + return this.objects[ i - 1 ].object; - "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", +}; - "#endif" +THREE.LOD.prototype.raycast = ( function () { - ].join("\n"), + var matrixPosition = new THREE.Vector3(); - shadowmap_pars_vertex: [ + return function ( raycaster, intersects ) { - "#ifdef USE_SHADOWMAP", + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - "varying vec4 vShadowCoord[ MAX_SHADOWS ];", - "uniform mat4 shadowMatrix[ MAX_SHADOWS ];", + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - "#endif" + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - ].join("\n"), + }; - shadowmap_vertex: [ +}() ); - "#ifdef USE_SHADOWMAP", +THREE.LOD.prototype.update = function () { - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + return function ( camera ) { - "}", + if ( this.objects.length > 1 ) { - "#endif" + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); - ].join("\n"), + var distance = v1.distanceTo( v2 ); - // ALPHATEST + this.objects[ 0 ].object.visible = true; - alphatest_fragment: [ + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - "#ifdef ALPHATEST", + if ( distance >= this.objects[ i ].distance ) { - "if ( gl_FragColor.a < ALPHATEST ) discard;", + this.objects[ i - 1 ].object.visible = false; + this.objects[ i ].object.visible = true; - "#endif" + } else { - ].join("\n"), + break; - // LINEAR SPACE + } - linear_to_gamma_fragment: [ + } - "#ifdef GAMMA_OUTPUT", + for ( ; i < l; i ++ ) { - "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", + this.objects[ i ].object.visible = false; - "#endif" + } - ].join("\n") + } + }; -}; +}(); -THREE.UniformsUtils = { +THREE.LOD.prototype.clone = function ( object ) { - merge: function ( uniforms ) { + if ( object === undefined ) object = new THREE.LOD(); - var u, p, tmp, merged = {}; + THREE.Object3D.prototype.clone.call( this, object ); - for ( u = 0; u < uniforms.length; u ++ ) { + for ( var i = 0, l = this.objects.length; i < l; i ++ ) { + var x = this.objects[ i ].object.clone(); + x.visible = i === 0; + object.addLevel( x, this.objects[ i ].distance ); + } - tmp = this.clone( uniforms[ u ] ); + return object; - for ( p in tmp ) { +}; - merged[ p ] = tmp[ p ]; +// File:src/objects/Sprite.js - } +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.Sprite = ( function () { - return merged; + var indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); + var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] ); + var uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] ); - }, + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - clone: function ( uniforms_src ) { + return function ( material ) { - var u, p, parameter, parameter_src, uniforms_dst = {}; + THREE.Object3D.call( this ); - for ( u in uniforms_src ) { + this.type = 'Sprite'; - uniforms_dst[ u ] = {}; + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - for ( p in uniforms_src[ u ] ) { + }; - parameter_src = uniforms_src[ u ][ p ]; +} )(); - if ( parameter_src instanceof THREE.Color || - parameter_src instanceof THREE.Vector2 || - parameter_src instanceof THREE.Vector3 || - parameter_src instanceof THREE.Vector4 || - parameter_src instanceof THREE.Matrix4 || - parameter_src instanceof THREE.Texture ) { +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Sprite.prototype.constructor = THREE.Sprite; - uniforms_dst[ u ][ p ] = parameter_src.clone(); +THREE.Sprite.prototype.raycast = ( function () { - } else if ( parameter_src instanceof Array ) { + var matrixPosition = new THREE.Vector3(); - uniforms_dst[ u ][ p ] = parameter_src.slice(); + return function ( raycaster, intersects ) { - } else { + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - uniforms_dst[ u ][ p ] = parameter_src; + var distance = raycaster.ray.distanceToPoint( matrixPosition ); - } + if ( distance > this.scale.x ) { - } + return; } - return uniforms_dst; + intersects.push( { - } + distance: distance, + point: this.position, + face: null, + object: this -}; + } ); -THREE.UniformsLib = { + }; - common: { +}() ); - "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, +THREE.Sprite.prototype.clone = function ( object ) { - "map" : { type: "t", value: null }, - "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + if ( object === undefined ) object = new THREE.Sprite( this.material ); - "lightMap" : { type: "t", value: null }, - "specularMap" : { type: "t", value: null }, + THREE.Object3D.prototype.clone.call( this, object ); - "envMap" : { type: "t", value: null }, - "flipEnvMap" : { type: "f", value: -1 }, - "useRefract" : { type: "i", value: 0 }, - "reflectivity" : { type: "f", value: 1.0 }, - "refractionRatio" : { type: "f", value: 0.98 }, - "combine" : { type: "i", value: 0 }, + return object; - "morphTargetInfluences" : { type: "f", value: 0 } +}; - }, +// Backwards compatibility - bump: { +THREE.Particle = THREE.Sprite; - "bumpMap" : { type: "t", value: null }, - "bumpScale" : { type: "f", value: 1 } +// File:src/objects/LensFlare.js - }, +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - normalmap: { +THREE.LensFlare = function ( texture, size, distance, blending, color ) { - "normalMap" : { type: "t", value: null }, - "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } - }, + THREE.Object3D.call( this ); - fog : { + this.lensFlares = []; - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; - }, + if ( texture !== undefined ) { - lights: { + this.add( texture, size, distance, blending, color ); - "ambientLightColor" : { type: "fv", value: [] }, + } - "directionalLightDirection" : { type: "fv", value: [] }, - "directionalLightColor" : { type: "fv", value: [] }, +}; - "hemisphereLightDirection" : { type: "fv", value: [] }, - "hemisphereLightSkyColor" : { type: "fv", value: [] }, - "hemisphereLightGroundColor" : { type: "fv", value: [] }, +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); +THREE.LensFlare.prototype.constructor = THREE.LensFlare; - "pointLightColor" : { type: "fv", value: [] }, - "pointLightPosition" : { type: "fv", value: [] }, - "pointLightDistance" : { type: "fv1", value: [] }, - "spotLightColor" : { type: "fv", value: [] }, - "spotLightPosition" : { type: "fv", value: [] }, - "spotLightDirection" : { type: "fv", value: [] }, - "spotLightDistance" : { type: "fv1", value: [] }, - "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] } +/* + * Add: adds another flare + */ - }, +THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { - particle: { + if ( size === undefined ) size = - 1; + if ( distance === undefined ) distance = 0; + if ( opacity === undefined ) opacity = 1; + if ( color === undefined ) color = new THREE.Color( 0xffffff ); + if ( blending === undefined ) blending = THREE.NormalBlending; - "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - "size" : { type: "f", value: 1.0 }, - "scale" : { type: "f", value: 1.0 }, - "map" : { type: "t", value: null }, + distance = Math.min( distance, Math.max( 0, distance ) ); - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + this.lensFlares.push( { + texture: texture, // THREE.Texture + size: size, // size in pixels (-1 = use texture.width) + distance: distance, // distance (0-1) from light source (0=at light source) + x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back + scale: 1, // scale + rotation: 1, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending // blending + } ); - }, +}; - shadowmap: { +/* + * Update lens flares update positions on all flares based on the screen position + * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. + */ - "shadowMap": { type: "tv", value: [] }, - "shadowMapSize": { type: "v2v", value: [] }, +THREE.LensFlare.prototype.updateLensFlares = function () { - "shadowBias" : { type: "fv1", value: [] }, - "shadowDarkness": { type: "fv1", value: [] }, + var f, fl = this.lensFlares.length; + var flare; + var vecX = - this.positionScreen.x * 2; + var vecY = - this.positionScreen.y * 2; - "shadowMatrix" : { type: "m4v", value: [] } + for ( f = 0; f < fl; f ++ ) { - } + flare = this.lensFlares[ f ]; -}; + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; -THREE.ShaderLib = { + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - 'basic': { + } - uniforms: THREE.UniformsUtils.merge( [ +}; - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "shadowmap" ] - ] ), +// File:src/scenes/Scene.js - vertexShader: [ +/** + * @author mrdoob / http://mrdoob.com/ + */ - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], +THREE.Scene = function () { - "void main() {", + THREE.Object3D.call( this ); - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], + this.type = 'Scene'; - "#ifdef USE_ENVMAP", + this.fog = null; + this.overrideMaterial = null; - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], + this.autoUpdate = true; // checked by the renderer - "#endif", +}; - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Scene.prototype.constructor = THREE.Scene; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +THREE.Scene.prototype.clone = function ( object ) { - "}" + if ( object === undefined ) object = new THREE.Scene(); - ].join("\n"), + THREE.Object3D.prototype.clone.call( this, object ); - fragmentShader: [ + if ( this.fog !== null ) object.fog = this.fog.clone(); + if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); - "uniform vec3 diffuse;", - "uniform float opacity;", + object.autoUpdate = this.autoUpdate; + object.matrixAutoUpdate = this.matrixAutoUpdate; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], + return object; - "void main() {", +}; - "gl_FragColor = vec4( diffuse, opacity );", +// File:src/scenes/Fog.js - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], +THREE.Fog = function ( color, near, far ) { - THREE.ShaderChunk[ "fog_fragment" ], + this.name = ''; - "}" + this.color = new THREE.Color( color ); - ].join("\n") + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; - }, +}; - 'lambert': { +THREE.Fog.prototype.clone = function () { - uniforms: THREE.UniformsUtils.merge( [ + return new THREE.Fog( this.color.getHex(), this.near, this.far ); - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], +}; - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } +// File:src/scenes/FogExp2.js - ] ), +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - vertexShader: [ +THREE.FogExp2 = function ( color, density ) { - "#define LAMBERT", + this.name = ''; - "varying vec3 vLightFront;", + this.color = new THREE.Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; - "#ifdef DOUBLE_SIDED", +}; - "varying vec3 vLightBack;", +THREE.FogExp2.prototype.clone = function () { - "#endif", + return new THREE.FogExp2( this.color.getHex(), this.density ); - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], +}; - "void main() {", +// File:src/renderers/shaders/ShaderChunk.js - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk = {}; - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], +// File:src/renderers/shaders/ShaderChunk/common.glsl - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], +THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n float distance = dot( planeNormal, point-pointOnPlane );\n return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n if ( decayExponent > 0.0 ) {\n return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n }\n return 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\n"; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_lambert_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +// File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl - "}" +THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; - ].join("\n"), +// File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl - fragmentShader: [ +THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, dirVector );\n vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n #endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n float dotProduct = dot( transformedNormal, lVector );\n\n vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n #endif\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float dotProduct = dot( transformedNormal, lVector );\n vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n #endif\n\n }\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, lVector );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n #endif\n\n }\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n vLightBack += ambientLightColor;\n\n#endif\n"; - "uniform float opacity;", +// File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl - "varying vec3 vLightFront;", +THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform vec4 offsetRepeat;\n uniform sampler2D map;\n\n#endif\n"; - "#ifdef DOUBLE_SIDED", +// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl - "varying vec3 vLightBack;", +THREE.ShaderChunk[ 'default_vertex'] = "#ifdef USE_SKINNING\n\n vec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n vec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; - "#endif", +// File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], +THREE.ShaderChunk[ 'map_pars_fragment'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n uniform sampler2D map;\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl - "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", +THREE.ShaderChunk[ 'skinnormal_vertex'] = "#ifdef USE_SKINNING\n\n mat4 skinMatrix = mat4( 0.0 );\n skinMatrix += skinWeight.x * boneMatX;\n skinMatrix += skinWeight.y * boneMatY;\n skinMatrix += skinWeight.z * boneMatZ;\n skinMatrix += skinWeight.w * boneMatW;\n skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\n #ifdef USE_MORPHNORMALS\n\n vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n #else\n\n vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n #endif\n\n#endif\n"; - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl - "#ifdef DOUBLE_SIDED", +THREE.ShaderChunk[ 'logdepthbuf_pars_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n varying float vFragDepth;\n\n #endif\n\n uniform float logDepthBufFC;\n\n#endif"; - //"float isFront = float( gl_FrontFacing );", - //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", +// File:src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl - "if ( gl_FrontFacing )", - "gl_FragColor.xyz *= vLightFront;", - "else", - "gl_FragColor.xyz *= vLightBack;", +THREE.ShaderChunk[ 'lightmap_pars_vertex'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n\n#endif"; - "#else", +// File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl - "gl_FragColor.xyz *= vLightFront;", +THREE.ShaderChunk[ 'lights_phong_fragment'] = "#ifndef FLAT_SHADED\n\n vec3 normal = normalize( vNormal );\n\n #ifdef DOUBLE_SIDED\n\n normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n #endif\n\n#else\n\n vec3 fdx = dFdx( vViewPosition );\n vec3 fdy = dFdy( vViewPosition );\n vec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n // specular\n\n vec3 pointHalfVector = normalize( lVector + viewPosition );\n float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n // specular\n\n vec3 spotHalfVector = normalize( lVector + viewPosition );\n float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n }\n\n }\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, dirVector );\n\n #ifdef WRAP_AROUND\n\n float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n // specular\n\n vec3 dirHalfVector = normalize( dirVector + viewPosition );\n float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n /*\n // fresnel term from skin shader\n const float F0 = 0.128;\n\n float base = 1.0 - dot( viewPosition, dirHalfVector );\n float exponential = pow( base, 5.0 );\n\n float fresnel = exponential + F0 * ( 1.0 - exponential );\n */\n\n /*\n // fresnel term from fresnel shader\n const float mFresnelBias = 0.08;\n const float mFresnelScale = 0.3;\n const float mFresnelPower = 5.0;\n\n float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n */\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n // dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n totalDiffuseLight += hemiColor;\n\n // specular (sky light)\n\n vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n // specular (ground light)\n\n vec3 lVectorGround = -lVector;\n\n vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n float dotProductGround = dot( normal, lVectorGround );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n }\n\n#endif\n\n#ifdef METAL\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; - "#endif", +// File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +THREE.ShaderChunk[ 'fog_pars_fragment'] = "#ifdef USE_FOG\n\n uniform vec3 fogColor;\n\n #ifdef FOG_EXP2\n\n uniform float fogDensity;\n\n #else\n\n uniform float fogNear;\n uniform float fogFar;\n #endif\n\n#endif"; - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], +// File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n vec3 morphedNormal = vec3( 0.0 );\n\n morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n morphedNormal += normal;\n\n#endif"; - "}" +// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl - ].join("\n") +THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n uniform float reflectivity;\n #ifdef ENVMAP_TYPE_CUBE\n uniform samplerCube envMap;\n #else\n uniform sampler2D envMap;\n #endif\n uniform float flipEnvMap;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n uniform float refractionRatio;\n\n #else\n\n varying vec3 vReflect;\n\n #endif\n\n#endif\n"; - }, +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl - 'phong': { +THREE.ShaderChunk[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bump" ], - THREE.UniformsLib[ "normalmap" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], +THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform vec2 normalScale;\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( vUv.st );\n vec2 st1 = dFdy( vUv.st );\n\n vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n vec3 N = normalize( surf_norm );\n\n vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n mapN.xy = normalScale * mapN.xy;\n mat3 tsn = mat3( S, T, N );\n return normalize( tsn * mapN );\n\n }\n\n#endif\n"; - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, - "shininess": { type: "f", value: 30 }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } +// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl - ] ), +THREE.ShaderChunk[ 'lights_phong_pars_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n"; - vertexShader: [ +// File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl - "#define PHONG", +THREE.ShaderChunk[ 'lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n varying vec2 vUv2;\n uniform sampler2D lightMap;\n\n#endif"; - "varying vec3 vViewPosition;", - "varying vec3 vNormal;", +// File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_phong_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], +THREE.ShaderChunk[ 'shadowmap_vertex'] = "#ifdef USE_SHADOWMAP\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n }\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n vWorldPosition = worldPosition.xyz;\n\n#endif"; - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], +// File:src/renderers/shaders/ShaderChunk/map_fragment.glsl - "vNormal = normalize( transformedNormal );", +THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n vec4 texelColor = texture2D( map, vUv );\n\n texelColor.xyz = inputToLinear( texelColor.xyz );\n\n diffuseColor *= texelColor;\n\n#endif"; - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], +// File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl - "vViewPosition = -mvPosition.xyz;", +THREE.ShaderChunk[ 'lightmap_vertex'] = "#ifdef USE_LIGHTMAP\n\n vUv2 = uv2;\n\n#endif"; - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], - THREE.ShaderChunk[ "lights_phong_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +// File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl - "}" +THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; - ].join("\n"), +// File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl - fragmentShader: [ +THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif\n"; - "uniform vec3 diffuse;", - "uniform float opacity;", +// File:src/renderers/shaders/ShaderChunk/color_vertex.glsl - "uniform vec3 ambient;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", +THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n vColor.xyz = inputToLinear( color.xyz );\n\n#endif"; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "lights_phong_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], +// File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl - "void main() {", +THREE.ShaderChunk[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n #ifdef USE_MORPHTARGETS\n\n vec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n #endif\n\n vec4 skinned = vec4( 0.0 );\n skinned += boneMatX * skinVertex * skinWeight.x;\n skinned += boneMatY * skinVertex * skinWeight.y;\n skinned += boneMatZ * skinVertex * skinWeight.z;\n skinned += boneMatW * skinVertex * skinWeight.w;\n skinned = bindMatrixInverse * skinned;\n\n#endif\n"; - "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", +// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], +THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n varying vec3 vReflect;\n\n uniform float refractionRatio;\n\n#endif\n"; - THREE.ShaderChunk[ "lights_phong_fragment" ], +// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], +THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n outgoingLight = linearToOutput( outgoingLight );\n"; - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], +// File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif"; - "}" +// File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl - ].join("\n") +THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n"; - }, +// File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl - 'particle_basic': { +THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n varying vec2 vUv;\n uniform vec4 offsetRepeat;\n\n#endif\n"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl - THREE.UniformsLib[ "particle" ], - THREE.UniformsLib[ "shadowmap" ] +THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // Transforming Normal Vectors with the Inverse Transformation\n vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n #else\n\n vec3 reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n #else\n float flipNormal = 1.0;\n #endif\n\n #ifdef ENVMAP_TYPE_CUBE\n vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #elif defined( ENVMAP_TYPE_EQUIREC )\n vec2 sampleUV;\n sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n vec4 envColor = texture2D( envMap, sampleUV );\n\n #elif defined( ENVMAP_TYPE_SPHERE )\n vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n #endif\n\n envColor.xyz = inputToLinear( envColor.xyz );\n\n #ifdef ENVMAP_BLENDING_MULTIPLY\n\n outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_MIX )\n\n outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_ADD )\n\n outgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n #endif\n\n#endif\n"; - ] ), +// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl - vertexShader: [ +THREE.ShaderChunk[ 'specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n uniform sampler2D specularMap;\n\n#endif"; - "uniform float size;", - "uniform float scale;", +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], +THREE.ShaderChunk[ 'logdepthbuf_vertex'] = "#ifdef USE_LOGDEPTHBUF\n\n gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n vFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n #endif\n\n#endif"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'morphtarget_pars_vertex'] = "#ifdef USE_MORPHTARGETS\n\n #ifndef USE_MORPHNORMALS\n\n uniform float morphTargetInfluences[ 8 ];\n\n #else\n\n uniform float morphTargetInfluences[ 4 ];\n\n #endif\n\n#endif"; - "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", +// File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl - "#ifdef USE_SIZEATTENUATION", - "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", - "#else", - "gl_PointSize = size;", - "#endif", +THREE.ShaderChunk[ 'specularmap_fragment'] = "float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n vec4 texelSpecular = texture2D( specularMap, vUv );\n specularStrength = texelSpecular.r;\n\n#else\n\n specularStrength = 1.0;\n\n#endif"; - "gl_Position = projectionMatrix * mvPosition;", +// File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], +THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n #else\n\n float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n #endif\n\n #ifdef FOG_EXP2\n\n float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n fogFactor = whiteCompliment( fogFactor );\n\n #else\n\n float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n #endif\n \n outgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; - "}" +// File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl - ].join("\n"), +THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n uniform sampler2D bumpMap;\n uniform float bumpScale;\n\n // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n vec2 dHdxy_fwd() {\n\n vec2 dSTdx = dFdx( vUv );\n vec2 dSTdy = dFdy( vUv );\n\n float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n return vec2( dBx, dBy );\n\n }\n\n vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n vec3 vSigmaX = dFdx( surf_pos );\n vec3 vSigmaY = dFdy( surf_pos );\n vec3 vN = surf_norm; // normalized\n\n vec3 R1 = cross( vSigmaY, vN );\n vec3 R2 = cross( vN, vSigmaX );\n\n float fDet = dot( vSigmaX, R1 );\n\n vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n return normalize( abs( fDet ) * surf_norm - vGrad );\n\n }\n\n#endif\n"; - fragmentShader: [ +// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl - "uniform vec3 psColor;", - "uniform float opacity;", +THREE.ShaderChunk[ 'defaultnormal_vertex'] = "#ifdef USE_SKINNING\n\n vec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n vec3 objectNormal = morphedNormal;\n\n#else\n\n vec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n objectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_particle_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], +// File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl - "void main() {", +THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n varying vec3 vNormal;\n\n#endif\n"; - "gl_FragColor = vec4( psColor, opacity );", +// File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl - THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], +THREE.ShaderChunk[ 'skinbase_vertex'] = "#ifdef USE_SKINNING\n\n mat4 boneMatX = getBoneMatrix( skinIndex.x );\n mat4 boneMatY = getBoneMatrix( skinIndex.y );\n mat4 boneMatZ = getBoneMatrix( skinIndex.z );\n mat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif"; - "}" +// File:src/renderers/shaders/ShaderChunk/map_vertex.glsl - ].join("\n") +THREE.ShaderChunk[ 'map_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n vUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; - }, +// File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl - 'dashed': { +THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif"; - uniforms: THREE.UniformsUtils.merge( [ +// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], +THREE.ShaderChunk[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n uniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif"; - { - "scale": { type: "f", value: 1 }, - "dashSize": { type: "f", value: 1 }, - "totalSize": { type: "f", value: 2 } - } +// File:src/renderers/shaders/ShaderChunk/color_fragment.glsl - ] ), +THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n diffuseColor.rgb *= vColor;\n\n#endif"; - vertexShader: [ +// File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl - "uniform float scale;", - "attribute float lineDistance;", +THREE.ShaderChunk[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n vec3 morphed = vec3( 0.0 );\n morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n #ifndef USE_MORPHNORMALS\n\n morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n #endif\n\n morphed += position;\n\n#endif"; - "varying float vLineDistance;", +// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl - THREE.ShaderChunk[ "color_pars_vertex" ], +THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n vec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vReflect = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n#endif\n"; - "void main() {", +// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl - THREE.ShaderChunk[ "color_vertex" ], +THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n #ifdef SHADOWMAP_DEBUG\n\n vec3 frustumColors[3];\n frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n #endif\n\n #ifdef SHADOWMAP_CASCADE\n\n int inFrustumCount = 0;\n\n #endif\n\n float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n // if ( something && something ) breaks ATI OpenGL shader compiler\n // if ( all( something, something ) ) using this instead\n\n bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n bool inFrustum = all( inFrustumVec );\n\n // don't shadow pixels outside of light frustum\n // use just first frustum (for cascades)\n // don't shadow pixels behind far plane of light frustum\n\n #ifdef SHADOWMAP_CASCADE\n\n inFrustumCount += int( inFrustum );\n bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n #else\n\n bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n #endif\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest ) {\n\n shadowCoord.z += shadowBias[ i ];\n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\n\n for ( float y = -1.25; y <= 1.25; y += 1.25 )\n for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n\n }\n\n shadow /= 9.0;\n\n */\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.25 * xPixelOffset;\n float dy0 = -1.25 * yPixelOffset;\n float dx1 = 1.25 * xPixelOffset;\n float dy1 = 1.25 * yPixelOffset;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.0 * xPixelOffset;\n float dy0 = -1.0 * yPixelOffset;\n float dx1 = 1.0 * xPixelOffset;\n float dy1 = 1.0 * yPixelOffset;\n\n mat3 shadowKernel;\n mat3 depthKernel;\n\n depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n vec3 shadowZ = vec3( shadowCoord.z );\n shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n shadowKernel[0] *= vec3(0.25);\n\n shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n shadowKernel[1] *= vec3(0.25);\n\n shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n shadowKernel[2] *= vec3(0.25);\n\n vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n vec4 shadowValues;\n shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n shadow = dot( shadowValues, vec4( 1.0 ) );\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #else\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n\n // spot with multiple shadows is darker\n\n shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n #ifdef SHADOWMAP_CASCADE\n\n if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n #else\n\n if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n #endif\n\n #endif\n\n }\n\n // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n shadowColor = inputToLinear( shadowColor );\n\n outgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; - "vLineDistance = scale * lineDistance;", +// File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl - "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - "gl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk[ 'worldpos_vertex'] = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n #ifdef USE_SKINNING\n\n vec4 worldPosition = modelMatrix * skinned;\n\n #elif defined( USE_MORPHTARGETS )\n\n vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n #else\n\n vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n #endif\n\n#endif\n"; - "}" +// File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl - ].join("\n"), +THREE.ShaderChunk[ 'shadowmap_pars_fragment'] = "#ifdef USE_SHADOWMAP\n\n uniform sampler2D shadowMap[ MAX_SHADOWS ];\n uniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n uniform float shadowDarkness[ MAX_SHADOWS ];\n uniform float shadowBias[ MAX_SHADOWS ];\n\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n float unpackDepth( const in vec4 rgba_depth ) {\n\n const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n float depth = dot( rgba_depth, bit_shift );\n return depth;\n\n }\n\n#endif"; - fragmentShader: [ +// File:src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl - "uniform vec3 diffuse;", - "uniform float opacity;", +THREE.ShaderChunk[ 'skinning_pars_vertex'] = "#ifdef USE_SKINNING\n\n uniform mat4 bindMatrix;\n uniform mat4 bindMatrixInverse;\n\n #ifdef BONE_TEXTURE\n\n uniform sampler2D boneTexture;\n uniform int boneTextureWidth;\n uniform int boneTextureHeight;\n\n mat4 getBoneMatrix( const in float i ) {\n\n float j = i * 4.0;\n float x = mod( j, float( boneTextureWidth ) );\n float y = floor( j / float( boneTextureWidth ) );\n\n float dx = 1.0 / float( boneTextureWidth );\n float dy = 1.0 / float( boneTextureHeight );\n\n y = dy * ( y + 0.5 );\n\n vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n mat4 bone = mat4( v1, v2, v3, v4 );\n\n return bone;\n\n }\n\n #else\n\n uniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n mat4 getBoneMatrix( const in float i ) {\n\n mat4 bone = boneGlobalMatrices[ int(i) ];\n return bone;\n\n }\n\n #endif\n\n#endif\n"; - "uniform float dashSize;", - "uniform float totalSize;", +// File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl - "varying float vLineDistance;", +THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n uniform float logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n #extension GL_EXT_frag_depth : enable\n varying float vFragDepth;\n\n #endif\n\n#endif"; - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], +// File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl - "void main() {", +THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; - "if ( mod( vLineDistance, totalSize ) > dashSize ) {", +// File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl - "discard;", +THREE.ShaderChunk[ 'alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n uniform sampler2D alphaMap;\n\n#endif\n"; - "}", +// File:src/renderers/shaders/UniformsUtils.js - "gl_FragColor = vec4( diffuse, opacity );", +/** + * Uniform Utilities + */ - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], +THREE.UniformsUtils = { - "}" + merge: function ( uniforms ) { - ].join("\n") + var merged = {}; - }, + for ( var u = 0; u < uniforms.length; u ++ ) { - 'depth': { + var tmp = this.clone( uniforms[ u ] ); - uniforms: { + for ( var p in tmp ) { - "mNear": { type: "f", value: 1.0 }, - "mFar" : { type: "f", value: 2000.0 }, - "opacity" : { type: "f", value: 1.0 } + merged[ p ] = tmp[ p ]; - }, + } - vertexShader: [ + } - "void main() {", + return merged; - "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + }, - "}" + clone: function ( uniforms_src ) { - ].join("\n"), + var uniforms_dst = {}; - fragmentShader: [ + for ( var u in uniforms_src ) { - "uniform float mNear;", - "uniform float mFar;", - "uniform float opacity;", + uniforms_dst[ u ] = {}; - "void main() {", + for ( var p in uniforms_src[ u ] ) { - "float depth = gl_FragCoord.z / gl_FragCoord.w;", - "float color = 1.0 - smoothstep( mNear, mFar, depth );", - "gl_FragColor = vec4( vec3( color ), opacity );", + var parameter_src = uniforms_src[ u ][ p ]; - "}" + if ( parameter_src instanceof THREE.Color || + parameter_src instanceof THREE.Vector2 || + parameter_src instanceof THREE.Vector3 || + parameter_src instanceof THREE.Vector4 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { - ].join("\n") + uniforms_dst[ u ][ p ] = parameter_src.clone(); - }, + } else if ( parameter_src instanceof Array ) { - 'normal': { + uniforms_dst[ u ][ p ] = parameter_src.slice(); - uniforms: { + } else { - "opacity" : { type: "f", value: 1.0 } + uniforms_dst[ u ][ p ] = parameter_src; - }, + } - vertexShader: [ + } - "varying vec3 vNormal;", + } - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + return uniforms_dst; - "void main() {", + } - "vNormal = normalize( normalMatrix * normal );", +}; - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], +// File:src/renderers/shaders/UniformsLib.js - "}" +/** + * Uniforms library for shared webgl shaders + */ - ].join("\n"), +THREE.UniformsLib = { - fragmentShader: [ + common: { - "uniform float opacity;", - "varying vec3 vNormal;", + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, - "void main() {", + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + "lightMap" : { type: "t", value: null }, + "specularMap" : { type: "t", value: null }, + "alphaMap" : { type: "t", value: null }, - "}" + "envMap" : { type: "t", value: null }, + "flipEnvMap" : { type: "f", value: - 1 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 }, - ].join("\n") + "morphTargetInfluences" : { type: "f", value: 0 } }, - /* ------------------------------------------------------------------------- - // Normal map shader - // - Blinn-Phong - // - normal + diffuse + specular + AO + displacement + reflection + shadow maps - // - point and directional lights (use with "lights: true" material option) - ------------------------------------------------------------------------- */ + bump: { - 'normalmap' : { + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 } - uniforms: THREE.UniformsUtils.merge( [ + }, - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], + normalmap: { - { + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } + }, + + fog : { - "enableAO" : { type: "i", value: 0 }, - "enableDiffuse" : { type: "i", value: 0 }, - "enableSpecular" : { type: "i", value: 0 }, - "enableReflection": { type: "i", value: 0 }, - "enableDisplacement": { type: "i", value: 0 }, + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture - "tDiffuse" : { type: "t", value: null }, - "tCube" : { type: "t", value: null }, - "tNormal" : { type: "t", value: null }, - "tSpecular" : { type: "t", value: null }, - "tAO" : { type: "t", value: null }, + }, - "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + lights: { - "uDisplacementBias": { type: "f", value: 0.0 }, - "uDisplacementScale": { type: "f", value: 1.0 }, + "ambientLightColor" : { type: "fv", value: [] }, - "uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) }, - "uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) }, - "uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) }, - "uShininess": { type: "f", value: 30 }, - "uOpacity": { type: "f", value: 1 }, + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, - "useRefract": { type: "i", value: 0 }, - "uRefractionRatio": { type: "f", value: 0.98 }, - "uReflectivity": { type: "f", value: 0.5 }, + "hemisphereLightDirection" : { type: "fv", value: [] }, + "hemisphereLightSkyColor" : { type: "fv", value: [] }, + "hemisphereLightGroundColor" : { type: "fv", value: [] }, - "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, - "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + "pointLightColor" : { type: "fv", value: [] }, + "pointLightPosition" : { type: "fv", value: [] }, + "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecay" : { type: "fv1", value: [] }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + "spotLightColor" : { type: "fv", value: [] }, + "spotLightPosition" : { type: "fv", value: [] }, + "spotLightDirection" : { type: "fv", value: [] }, + "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightAngleCos" : { type: "fv1", value: [] }, + "spotLightExponent" : { type: "fv1", value: [] }, + "spotLightDecay" : { type: "fv1", value: [] } - } + }, - ] ), + particle: { - fragmentShader: [ + "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + "size" : { type: "f", value: 1.0 }, + "scale" : { type: "f", value: 1.0 }, + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "uniform vec3 uAmbientColor;", - "uniform vec3 uDiffuseColor;", - "uniform vec3 uSpecularColor;", - "uniform float uShininess;", - "uniform float uOpacity;", + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - "uniform bool enableDiffuse;", - "uniform bool enableSpecular;", - "uniform bool enableAO;", - "uniform bool enableReflection;", + }, - "uniform sampler2D tDiffuse;", - "uniform sampler2D tNormal;", - "uniform sampler2D tSpecular;", - "uniform sampler2D tAO;", + shadowmap: { - "uniform samplerCube tCube;", + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, - "uniform vec2 uNormalScale;", + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, - "uniform bool useRefract;", - "uniform float uRefractionRatio;", - "uniform float uReflectivity;", + "shadowMatrix" : { type: "m4v", value: [] } - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", + } - "uniform vec3 ambientLightColor;", +}; - "#if MAX_DIR_LIGHTS > 0", +// File:src/renderers/shaders/ShaderLib.js - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", +/** + * Webgl Shader Library for three.js + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + */ - "#endif", - "#if MAX_HEMI_LIGHTS > 0", +THREE.ShaderLib = { - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + 'basic': { - "#endif", + uniforms: THREE.UniformsUtils.merge( [ - "#if MAX_POINT_LIGHTS > 0", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + ] ), - "#endif", + vertexShader: [ - "#if MAX_SPOT_LIGHTS > 0", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "void main() {", - "#endif", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], - "#ifdef WRAP_AROUND", + " #ifdef USE_ENVMAP", - "uniform vec3 wrapRGB;", + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - "#endif", + " #endif", - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "void main() {", + "}" - "gl_FragColor = vec4( vec3( 1.0 ), uOpacity );", + ].join("\n"), - "vec3 specularTex = vec3( 1.0 );", + fragmentShader: [ - "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", - "normalTex.xy *= uNormalScale;", - "normalTex = normalize( normalTex );", + "uniform vec3 diffuse;", + "uniform float opacity;", - "if( enableDiffuse ) {", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "#ifdef GAMMA_INPUT", + "void main() {", - "vec4 texelColor = texture2D( tDiffuse, vUv );", - "texelColor.xyz *= texelColor.xyz;", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - "gl_FragColor = gl_FragColor * texelColor;", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - "#else", + " outgoingLight = diffuseColor.rgb;", // simple shader - "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", + THREE.ShaderChunk[ "lightmap_fragment" ], // TODO: Light map on an otherwise unlit surface doesn't make sense. + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], // TODO: Shadows on an otherwise unlit surface doesn't make sense. - "#endif", + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - "}", + THREE.ShaderChunk[ "fog_fragment" ], - "if( enableAO ) {", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - "#ifdef GAMMA_INPUT", + "}" - "vec4 aoColor = texture2D( tAO, vUv );", - "aoColor.xyz *= aoColor.xyz;", + ].join("\n") - "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", + }, - "#else", + 'lambert': { - "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", + uniforms: THREE.UniformsUtils.merge( [ - "#endif", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - "}", + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } - "if( enableSpecular )", - "specularTex = texture2D( tSpecular, vUv ).xyz;", + ] ), - "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", - "vec3 finalNormal = tsb * normalTex;", + vertexShader: [ - "#ifdef FLIP_SIDED", + "#define LAMBERT", - "finalNormal = -finalNormal;", + "varying vec3 vLightFront;", - "#endif", + "#ifdef DOUBLE_SIDED", - "vec3 normal = normalize( finalNormal );", - "vec3 viewPosition = normalize( vViewPosition );", + " varying vec3 vLightBack;", - // point lights + "#endif", - "#if MAX_POINT_LIGHTS > 0", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "vec3 pointDiffuse = vec3( 0.0 );", - "vec3 pointSpecular = vec3( 0.0 );", + "void main() {", - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - "float pointDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "pointVector = normalize( pointVector );", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - // diffuse + "}" - "#ifdef WRAP_AROUND", + ].join("\n"), - "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", - "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", + fragmentShader: [ - "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform float opacity;", - "#else", + "varying vec3 vLightFront;", - "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", + "#ifdef DOUBLE_SIDED", - "#endif", + " varying vec3 vLightBack;", - "pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;", + "#endif", - // specular + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "vec3 pointHalfVector = normalize( pointVector + viewPosition );", - "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );", + "void main() {", - "#ifdef PHYSICALLY_BASED_SHADING", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - // 2.0 => 2.0001 is hack to work around ANGLE bug + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + " #ifdef DOUBLE_SIDED", - "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", - "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", + //"float isFront = float( gl_FrontFacing );", + //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", - "#else", + " if ( gl_FrontFacing )", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", + " else", + " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", - "pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;", + " #else", - "#endif", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - "}", + " #endif", - "#endif", + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - // spot lights + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - "#if MAX_SPOT_LIGHTS > 0", + THREE.ShaderChunk[ "fog_fragment" ], - "vec3 spotDiffuse = vec3( 0.0 );", - "vec3 spotSpecular = vec3( 0.0 );", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + "}" - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", + ].join("\n") - "float spotDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", + }, - "spotVector = normalize( spotVector );", + 'phong': { - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + uniforms: THREE.UniformsUtils.merge( [ - "if ( spotEffect > spotLightAngleCos[ i ] ) {", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bump" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } - // diffuse + ] ), - "#ifdef WRAP_AROUND", + vertexShader: [ - "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", - "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", + "#define PHONG", - "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + "varying vec3 vViewPosition;", - "#else", + "#ifndef FLAT_SHADED", - "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", + " varying vec3 vNormal;", - "#endif", + "#endif", - "spotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "envmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_phong_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - // specular + "void main() {", - "vec3 spotHalfVector = normalize( spotVector + viewPosition );", - "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );", + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - "#ifdef PHYSICALLY_BASED_SHADING", + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - // 2.0 => 2.0001 is hack to work around ANGLE bug + "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED - "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + " vNormal = normalize( transformedNormal );", - "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", - "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", + "#endif", - "#else", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "spotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;", + " vViewPosition = -mvPosition.xyz;", - "#endif", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "}", + "}" - "}", + ].join("\n"), - "#endif", + fragmentShader: [ - // directional lights + "#define PHONG", - "#if MAX_DIR_LIGHTS > 0", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", - "vec3 dirDiffuse = vec3( 0.0 );", - "vec3 dirSpecular = vec3( 0.0 );", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_phong_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", + "void main() {", - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - // diffuse + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - "#ifdef WRAP_AROUND", + THREE.ShaderChunk[ "lights_phong_fragment" ], - "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", - "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - "#else", + THREE.ShaderChunk[ "fog_fragment" ], - "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - "#endif", + "}" - "dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;", + ].join("\n") - // specular + }, - "vec3 dirHalfVector = normalize( dirVector + viewPosition );", - "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );", + 'particle_basic': { - "#ifdef PHYSICALLY_BASED_SHADING", + uniforms: THREE.UniformsUtils.merge( [ - // 2.0 => 2.0001 is hack to work around ANGLE bug + THREE.UniformsLib[ "particle" ], + THREE.UniformsLib[ "shadowmap" ] - "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + ] ), - "vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", - "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + vertexShader: [ - "#else", + "uniform float size;", + "uniform float scale;", - "dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "#endif", + "void main() {", - "}", + THREE.ShaderChunk[ "color_vertex" ], - "#endif", + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - // hemisphere lights + " #ifdef USE_SIZEATTENUATION", + " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + " #else", + " gl_PointSize = size;", + " #endif", - "#if MAX_HEMI_LIGHTS > 0", + " gl_Position = projectionMatrix * mvPosition;", - "vec3 hemiDiffuse = vec3( 0.0 );", - "vec3 hemiSpecular = vec3( 0.0 );" , + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + "}" - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", + ].join("\n"), - // diffuse + fragmentShader: [ - "float dotProduct = dot( normal, lVector );", - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + "uniform vec3 psColor;", + "uniform float opacity;", - "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_particle_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "hemiDiffuse += uDiffuseColor * hemiColor;", + "void main() {", - // specular (sky light) + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( psColor, opacity );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_particle_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], - "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", - "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );", + " outgoingLight = diffuseColor.rgb;", // simple shader - // specular (ground light) + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], - "vec3 lVectorGround = -lVector;", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", - "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );", + "}" - "#ifdef PHYSICALLY_BASED_SHADING", + ].join("\n") - "float dotProductGround = dot( normal, lVectorGround );", + }, - // 2.0 => 2.0001 is hack to work around ANGLE bug + 'dashed': { - "float specularNormalization = ( uShininess + 2.0001 ) / 8.0;", + uniforms: THREE.UniformsUtils.merge( [ - "vec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", - "vec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", - "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], - "#else", + { + "scale" : { type: "f", value: 1 }, + "dashSize" : { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } - "hemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;", + ] ), - "#endif", + vertexShader: [ - "}", + "uniform float scale;", + "attribute float lineDistance;", - "#endif", + "varying float vLineDistance;", - // all lights contribution summation + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", + "void main() {", - "#if MAX_DIR_LIGHTS > 0", + THREE.ShaderChunk[ "color_vertex" ], - "totalDiffuse += dirDiffuse;", - "totalSpecular += dirSpecular;", + " vLineDistance = scale * lineDistance;", - "#endif", + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * mvPosition;", - "#if MAX_HEMI_LIGHTS > 0", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "totalDiffuse += hemiDiffuse;", - "totalSpecular += hemiSpecular;", + "}" - "#endif", + ].join("\n"), - "#if MAX_POINT_LIGHTS > 0", + fragmentShader: [ - "totalDiffuse += pointDiffuse;", - "totalSpecular += pointSpecular;", + "uniform vec3 diffuse;", + "uniform float opacity;", - "#endif", + "uniform float dashSize;", + "uniform float totalSize;", - "#if MAX_SPOT_LIGHTS > 0", + "varying float vLineDistance;", - "totalDiffuse += spotDiffuse;", - "totalSpecular += spotSpecular;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "#endif", + "void main() {", - "#ifdef METAL", + " if ( mod( vLineDistance, totalSize ) > dashSize ) {", - "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );", + " discard;", - "#else", + " }", - "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", - "#endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], - "if ( enableReflection ) {", + " outgoingLight = diffuseColor.rgb;", // simple shader - "vec3 vReflect;", - "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + THREE.ShaderChunk[ "fog_fragment" ], - "if ( useRefract ) {", + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - "vReflect = refract( cameraToVertex, normal, uRefractionRatio );", + "}" - "} else {", + ].join("\n") - "vReflect = reflect( cameraToVertex, normal );", + }, - "}", + 'depth': { - "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", + uniforms: { - "#ifdef GAMMA_INPUT", + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } - "cubeColor.xyz *= cubeColor.xyz;", + }, - "#endif", + vertexShader: [ - "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "}", + "void main() {", - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join("\n"), - vertexShader: [ - - "attribute vec4 tangent;", + fragmentShader: [ - "uniform vec2 uOffset;", - "uniform vec2 uRepeat;", + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", - "uniform bool enableDisplacement;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "#ifdef VERTEX_TEXTURES", + "void main() {", - "uniform sampler2D tDisplacement;", - "uniform float uDisplacementScale;", - "uniform float uDisplacementBias;", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - "#endif", + " #ifdef USE_LOGDEPTHBUF_EXT", - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", + " float depth = gl_FragDepthEXT / gl_FragCoord.w;", - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", + " #else", - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + " float depth = gl_FragCoord.z / gl_FragCoord.w;", - "void main() {", + " #endif", - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], + " float color = 1.0 - smoothstep( mNear, mFar, depth );", + " gl_FragColor = vec4( vec3( color ), opacity );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects - // normal, tangent and binormal vectors + "}" - "#ifdef USE_SKINNING", + ].join("\n") - "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + }, - "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", - "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + 'normal': { - "#else", + uniforms: { - "vNormal = normalize( normalMatrix * normal );", - "vTangent = normalize( normalMatrix * tangent.xyz );", + "opacity" : { type: "f", value: 1.0 } - "#endif", + }, - "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + vertexShader: [ - "vUv = uv * uRepeat + uOffset;", + "varying vec3 vNormal;", - // displacement mapping + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "vec3 displacedPosition;", + "void main() {", - "#ifdef VERTEX_TEXTURES", + " vNormal = normalize( normalMatrix * normal );", - "if ( enableDisplacement ) {", + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "vec3 dv = texture2D( tDisplacement, uv ).xyz;", - "float df = uDisplacementScale * dv.x + uDisplacementBias;", - "displacedPosition = position + normalize( normal ) * df;", + "}" - "} else {", + ].join("\n"), - "#ifdef USE_SKINNING", + fragmentShader: [ - "vec4 skinVertex = vec4( position, 1.0 );", + "uniform float opacity;", + "varying vec3 vNormal;", - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "displacedPosition = skinned.xyz;", + "void main() {", - "#else", + " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", - "displacedPosition = position;", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - "#endif", + "}" - "}", + ].join("\n") - "#else", + }, - "#ifdef USE_SKINNING", + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - "vec4 skinVertex = vec4( position, 1.0 );", + 'cube': { - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, - "displacedPosition = skinned.xyz;", + vertexShader: [ - "#else", + "varying vec3 vWorldPosition;", - "displacedPosition = position;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - "#endif", + "void main() {", - "#endif", + " vWorldPosition = transformDirection( position, modelMatrix );", - // + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", - "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "gl_Position = projectionMatrix * mvPosition;", + "}" - // + ].join("\n"), - "vWorldPosition = worldPosition.xyz;", - "vViewPosition = -mvPosition.xyz;", + fragmentShader: [ - // shadows + "uniform samplerCube tCube;", + "uniform float tFlip;", - "#ifdef USE_SHADOWMAP", + "varying vec3 vWorldPosition;", - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + "void main() {", - "}", + " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", - "#endif", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], "}" @@ -19509,21 +17692,25 @@ THREE.ShaderLib = { // Cube map shader ------------------------------------------------------------------------- */ - 'cube': { + 'equirect': { - uniforms: { "tCube": { type: "t", value: null }, - "tFlip": { type: "f", value: -1 } }, + uniforms: { "tEquirect": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, vertexShader: [ "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], + "void main() {", - "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", - "vWorldPosition = worldPosition.xyz;", + " vWorldPosition = transformDirection( position, modelMatrix );", - "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" @@ -19531,14 +17718,24 @@ THREE.ShaderLib = { fragmentShader: [ - "uniform samplerCube tCube;", + "uniform sampler2D tEquirect;", "uniform float tFlip;", "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + "void main() {", - "gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + // " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + "vec3 direction = normalize( vWorldPosition );", + "vec2 sampleUV;", + "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", + "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", + "gl_FragColor = texture2D( tEquirect, sampleUV );", + + THREE.ShaderChunk[ "logdepthbuf_fragment" ], "}" @@ -19546,13 +17743,17 @@ THREE.ShaderLib = { }, - // Depth encoding into RGBA texture - // based on SpiderGL shadow map example - // http://spidergl.org/example.php?id=6 - // originally from - // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD - // see also here: - // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + /* Depth encoding into RGBA texture + * + * based on SpiderGL shadow map example + * http://spidergl.org/example.php?id=6 + * + * originally from + * http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + * + * see also + * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + */ 'depthRGBA': { @@ -19560,8 +17761,10 @@ THREE.ShaderLib = { vertexShader: [ + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", @@ -19569,6 +17772,7 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" @@ -19576,19 +17780,32 @@ THREE.ShaderLib = { fragmentShader: [ + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], + "vec4 pack_depth( const in float depth ) {", - "const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - "const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - "vec4 res = fract( depth * bit_shift );", - "res -= res.xxyz * bit_mask;", - "return res;", + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", "}", "void main() {", - "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + + " #ifdef USE_LOGDEPTHBUF_EXT", + + " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", + + " #else", + + " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + + " #endif", //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", @@ -19603,6 +17820,8 @@ THREE.ShaderLib = { }; +// File:src/renderers/WebGLRenderer.js + /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ @@ -19617,27 +17836,38 @@ THREE.WebGLRenderer = function ( parameters ) { parameters = parameters || {}; var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, + + pixelRatio = 1, _precision = parameters.precision !== undefined ? parameters.precision : 'highp', - _alpha = parameters.alpha !== undefined ? parameters.alpha : true, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _alpha = parameters.alpha !== undefined ? parameters.alpha : false, + _depth = parameters.depth !== undefined ? parameters.depth : true, _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + _logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false, _clearColor = new THREE.Color( 0x000000 ), _clearAlpha = 0; + var lights = []; + + var _webglObjects = {}; + var _webglObjectsImmediate = []; + + var opaqueObjects = []; + var transparentObjects = []; + + var sprites = []; + var lensFlares = []; + // public properties this.domElement = _canvas; this.context = null; - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; // clearing @@ -19649,18 +17879,16 @@ THREE.WebGLRenderer = function ( parameters ) { // scene graph this.sortObjects = true; - this.autoUpdateObjects = true; // physically based shading + this.gammaFactor = 2.0; // for backwards compatibility this.gammaInput = false; this.gammaOutput = false; - this.physicallyBasedShading = false; // shadow map this.shadowMapEnabled = false; - this.shadowMapAutoUpdate = true; this.shadowMapType = THREE.PCFShadowMap; this.shadowMapCullFace = THREE.CullFaceFront; this.shadowMapDebug = false; @@ -19675,11 +17903,6 @@ THREE.WebGLRenderer = function ( parameters ) { this.autoScaleCubemaps = true; - // custom render plugins - - this.renderPluginsPre = []; - this.renderPluginsPost = []; - // info this.info = { @@ -19708,39 +17931,17 @@ THREE.WebGLRenderer = function ( parameters ) { var _this = this, _programs = [], - _programs_counter = 0, // internal state cache _currentProgram = null, _currentFramebuffer = null, - _currentMaterialId = -1, - _currentGeometryGroupHash = null, + _currentMaterialId = - 1, + _currentGeometryProgram = '', _currentCamera = null, - _geometryGroupCounter = 0, _usedTextureUnits = 0, - // GL state cache - - _oldDoubleSided = -1, - _oldFlipSided = -1, - - _oldBlending = -1, - - _oldBlendEquation = -1, - _oldBlendSrc = -1, - _oldBlendDst = -1, - - _oldDepthTest = -1, - _oldDepthWrite = -1, - - _oldPolygonOffset = null, - _oldPolygonOffsetFactor = null, - _oldPolygonOffsetUnits = null, - - _oldLineWidth = null, - _viewportX = 0, _viewportY = 0, _viewportWidth = _canvas.width, @@ -19748,8 +17949,6 @@ THREE.WebGLRenderer = function ( parameters ) { _currentWidth = 0, _currentHeight = 0, - _enabledAttributes = {}, - // frustum _frustum = new THREE.Frustum(), @@ -19757,7 +17956,6 @@ THREE.WebGLRenderer = function ( parameters ) { // camera matrices cache _projScreenMatrix = new THREE.Matrix4(), - _projScreenMatrixPS = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), @@ -19770,10 +17968,10 @@ THREE.WebGLRenderer = function ( parameters ) { _lights = { ambient: [ 0, 0, 0 ], - directional: { length: 0, colors: new Array(), positions: new Array() }, - point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, - spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, - hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } + directional: { length: 0, colors:[], positions: [] }, + point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, + spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, + hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } }; @@ -19781,17 +17979,135 @@ THREE.WebGLRenderer = function ( parameters ) { var _gl; - var _glExtensionTextureFloat; - var _glExtensionTextureFloatLinear; - var _glExtensionStandardDerivatives; - var _glExtensionTextureFilterAnisotropic; - var _glExtensionCompressedTextureS3TC; + try { + + var attributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer + }; + + _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); + + if ( _gl === null ) { + + if ( _canvas.getContext( 'webgl') !== null ) { + + throw 'Error creating WebGL context with your selected attributes.'; + + } else { + + throw 'Error creating WebGL context.'; + + } + + } + + _canvas.addEventListener( 'webglcontextlost', function ( event ) { + + event.preventDefault(); + + resetGLState(); + setDefaultGLState(); + + _webglObjects = {}; + + }, false); + + } catch ( error ) { + + THREE.error( 'THREE.WebGLRenderer: ' + error ); + + } + + var state = new THREE.WebGLState( _gl, paramThreeToGL ); + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function () { + + return { + 'rangeMin': 1, + 'rangeMax': 1, + 'precision': 1 + }; + + } + + } + + var extensions = new THREE.WebGLExtensions( _gl ); + + extensions.get( 'OES_texture_float' ); + extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); + extensions.get( 'OES_standard_derivatives' ); + + if ( _logarithmicDepthBuffer ) { + + extensions.get( 'EXT_frag_depth' ); + + } + + // + + var glClearColor = function ( r, g, b, a ) { + + if ( _premultipliedAlpha === true ) { + + r *= a; g *= a; b *= a; + + } + + _gl.clearColor( r, g, b, a ); + + }; + + var setDefaultGLState = function () { + + _gl.clearColor( 0, 0, 0, 1 ); + _gl.clearDepth( 1 ); + _gl.clearStencil( 0 ); + + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthFunc( _gl.LEQUAL ); + + _gl.frontFace( _gl.CCW ); + _gl.cullFace( _gl.BACK ); + _gl.enable( _gl.CULL_FACE ); + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + var resetGLState = function () { - initGL(); + _currentProgram = null; + _currentCamera = null; + + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + + _lightsNeedUpdate = true; + + state.reset(); + + }; setDefaultGLState(); this.context = _gl; + this.state = state; // GPU capabilities @@ -19800,59 +18116,84 @@ THREE.WebGLRenderer = function ( parameters ) { var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; - - var _supportsVertexTextures = ( _maxVertexTextures > 0 ); - var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; - - var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; + var _supportsVertexTextures = _maxVertexTextures > 0; + var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' ); // var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); - var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); - var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); - var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); - var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); - var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); + var getCompressedTextureFormats = ( function () { + + var array; + + return function () { + + if ( array !== undefined ) { + + return array; + + } + + array = []; + + if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { + + var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); + + for ( var i = 0; i < formats.length; i ++ ) { + + array.push( formats[ i ] ); + + } + + } + + return array; + + }; - var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); - var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); - var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); + } )(); // clamp precision to maximum available var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; - if ( _precision === "highp" && ! highpAvailable ) { + if ( _precision === 'highp' && ! highpAvailable ) { if ( mediumpAvailable ) { - _precision = "mediump"; - console.warn( "WebGLRenderer: highp not supported, using mediump" ); + _precision = 'mediump'; + THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); } else { - _precision = "lowp"; - console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); + _precision = 'lowp'; + THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); } } - if ( _precision === "mediump" && ! mediumpAvailable ) { + if ( _precision === 'mediump' && ! mediumpAvailable ) { - _precision = "lowp"; - console.warn( "WebGLRenderer: mediump not supported, using lowp" ); + _precision = 'lowp'; + THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); } + // Plugins + + var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate ); + + var spritePlugin = new THREE.SpritePlugin( this, sprites ); + var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); + // API this.getContext = function () { @@ -19861,6 +18202,12 @@ THREE.WebGLRenderer = function ( parameters ) { }; + this.forceContextLoss = function () { + + extensions.get( 'WEBGL_lose_context' ).loseContext(); + + }; + this.supportsVertexTextures = function () { return _supportsVertexTextures; @@ -19869,57 +18216,103 @@ THREE.WebGLRenderer = function ( parameters ) { this.supportsFloatTextures = function () { - return _glExtensionTextureFloat; + return extensions.get( 'OES_texture_float' ); + + }; + + this.supportsHalfFloatTextures = function () { + + return extensions.get( 'OES_texture_half_float' ); }; this.supportsStandardDerivatives = function () { - return _glExtensionStandardDerivatives; + return extensions.get( 'OES_standard_derivatives' ); }; this.supportsCompressedTextureS3TC = function () { - return _glExtensionCompressedTextureS3TC; + return extensions.get( 'WEBGL_compressed_texture_s3tc' ); }; - this.getMaxAnisotropy = function () { + this.supportsCompressedTexturePVRTC = function () { - return _maxAnisotropy; + return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); }; + this.supportsBlendMinMax = function () { + + return extensions.get( 'EXT_blend_minmax' ); + + }; + + this.getMaxAnisotropy = ( function () { + + var value; + + return function () { + + if ( value !== undefined ) { + + return value; + + } + + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + + value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; + + return value; + + } + + } )(); + this.getPrecision = function () { return _precision; }; + this.getPixelRatio = function () { + + return pixelRatio; + + }; + + this.setPixelRatio = function ( value ) { + + pixelRatio = value; + + }; + this.setSize = function ( width, height, updateStyle ) { - _canvas.width = width * this.devicePixelRatio; - _canvas.height = height * this.devicePixelRatio; + _canvas.width = width * pixelRatio; + _canvas.height = height * pixelRatio; - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + if ( updateStyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } - this.setViewport( 0, 0, _canvas.width, _canvas.height ); + this.setViewport( 0, 0, width, height ); }; this.setViewport = function ( x, y, width, height ) { - _viewportX = x !== undefined ? x : 0; - _viewportY = y !== undefined ? y : 0; + _viewportX = x * pixelRatio; + _viewportY = y * pixelRatio; - _viewportWidth = width !== undefined ? width : _canvas.width; - _viewportHeight = height !== undefined ? height : _canvas.height; + _viewportWidth = width * pixelRatio; + _viewportHeight = height * pixelRatio; _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); @@ -19927,7 +18320,12 @@ THREE.WebGLRenderer = function ( parameters ) { this.setScissor = function ( x, y, width, height ) { - _gl.scissor( x, y, width, height ); + _gl.scissor( + x * pixelRatio, + y * pixelRatio, + width * pixelRatio, + height * pixelRatio + ); }; @@ -19939,31 +18337,33 @@ THREE.WebGLRenderer = function ( parameters ) { // Clearing + this.getClearColor = function () { + + return _clearColor; + + }; + this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; - this.setClearColorHex = function ( hex, alpha ) { + this.getClearAlpha = function () { - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); + return _clearAlpha; }; - this.getClearColor = function () { - - return _clearColor; - - }; + this.setClearAlpha = function ( alpha ) { - this.getClearAlpha = function () { + _clearAlpha = alpha; - return _clearAlpha; + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -19979,48 +18379,34 @@ THREE.WebGLRenderer = function ( parameters ) { }; - this.clearTarget = function ( renderTarget, color, depth, stencil ) { + this.clearColor = function () { - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); + _gl.clear( _gl.COLOR_BUFFER_BIT ); }; - // Plugins - - this.addPostPlugin = function ( plugin ) { + this.clearDepth = function () { - plugin.init( this ); - this.renderPluginsPost.push( plugin ); + _gl.clear( _gl.DEPTH_BUFFER_BIT ); }; - this.addPrePlugin = function ( plugin ) { + this.clearStencil = function () { - plugin.init( this ); - this.renderPluginsPre.push( plugin ); + _gl.clear( _gl.STENCIL_BUFFER_BIT ); }; - // Rendering - - this.updateShadowMap = function ( scene, camera ) { - - _currentProgram = null; - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; - _lightsNeedUpdate = true; - _oldDoubleSided = -1; - _oldFlipSided = -1; + this.clearTarget = function ( renderTarget, color, depth, stencil ) { - this.shadowMapPlugin.update( scene, camera ); + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); }; - // Internal functions + // Reset + + this.resetGLState = resetGLState; // Buffer allocation @@ -20058,13 +18444,13 @@ THREE.WebGLRenderer = function ( parameters ) { geometryGroup.__webglFaceBuffer = _gl.createBuffer(); geometryGroup.__webglLineBuffer = _gl.createBuffer(); - var m, ml; + var numMorphTargets = geometryGroup.numMorphTargets; - if ( geometryGroup.numMorphTargets ) { + if ( numMorphTargets ) { geometryGroup.__webglMorphTargetsBuffers = []; - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); @@ -20072,11 +18458,13 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( geometryGroup.numMorphNormals ) { + var numMorphNormals = geometryGroup.numMorphNormals; + + if ( numMorphNormals ) { geometryGroup.__webglMorphNormalsBuffers = []; - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); @@ -20090,6 +18478,20 @@ THREE.WebGLRenderer = function ( parameters ) { // Events + var onObjectRemoved = function ( event ) { + + var object = event.target; + + object.traverse( function ( child ) { + + child.removeEventListener( 'remove', onObjectRemoved ); + + removeObject( child ); + + } ); + + }; + var onGeometryDispose = function ( event ) { var geometry = event.target; @@ -20131,38 +18533,57 @@ THREE.WebGLRenderer = function ( parameters ) { material.removeEventListener( 'dispose', onMaterialDispose ); - deallocateMaterial( material ); + deallocateMaterial( material ); + + }; + + // Buffer deallocation + + var deleteBuffers = function ( geometry ) { + + var buffers = [ + '__webglVertexBuffer', + '__webglNormalBuffer', + '__webglTangentBuffer', + '__webglColorBuffer', + '__webglUVBuffer', + '__webglUV2Buffer', + + '__webglSkinIndicesBuffer', + '__webglSkinWeightsBuffer', + + '__webglFaceBuffer', + '__webglLineBuffer', + + '__webglLineDistanceBuffer' + ]; + + for ( var i = 0, l = buffers.length; i < l; i ++ ) { - }; + var name = buffers[ i ]; - // Buffer deallocation + if ( geometry[ name ] !== undefined ) { - var deleteBuffers = function ( geometry ) { + _gl.deleteBuffer( geometry[ name ] ); - if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); - if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); - if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); - if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); - if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); - if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); + delete geometry[ name ]; - if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); - if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); + } - if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); - if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); + } - if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); // custom attributes if ( geometry.__webglCustomAttributesList !== undefined ) { - for ( var id in geometry.__webglCustomAttributesList ) { + for ( var name in geometry.__webglCustomAttributesList ) { - _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); + _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer ); } + delete geometry.__webglCustomAttributesList; + } _this.info.memory.geometries --; @@ -20171,17 +18592,19 @@ THREE.WebGLRenderer = function ( parameters ) { var deallocateGeometry = function ( geometry ) { - geometry.__webglInit = undefined; + delete geometry.__webglInit; if ( geometry instanceof THREE.BufferGeometry ) { - var attributes = geometry.attributes; + for ( var name in geometry.attributes ) { - for ( var key in attributes ) { + var attribute = geometry.attributes[ name ]; - if ( attributes[ key ].buffer !== undefined ) { + if ( attribute.buffer !== undefined ) { - _gl.deleteBuffer( attributes[ key ].buffer ); + _gl.deleteBuffer( attribute.buffer ); + + delete attribute.buffer; } @@ -20191,11 +18614,13 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - if ( geometry.geometryGroups !== undefined ) { + var geometryGroupsList = geometryGroups[ geometry.id ]; + + if ( geometryGroupsList !== undefined ) { - for ( var g in geometry.geometryGroups ) { + for ( var i = 0, l = geometryGroupsList.length; i < l; i ++ ) { - var geometryGroup = geometry.geometryGroups[ g ]; + var geometryGroup = geometryGroupsList[ i ]; if ( geometryGroup.numMorphTargets !== undefined ) { @@ -20205,6 +18630,8 @@ THREE.WebGLRenderer = function ( parameters ) { } + delete geometryGroup.__webglMorphTargetsBuffers; + } if ( geometryGroup.numMorphNormals !== undefined ) { @@ -20215,12 +18642,16 @@ THREE.WebGLRenderer = function ( parameters ) { } + delete geometryGroup.__webglMorphNormalsBuffers; + } deleteBuffers( geometryGroup ); } + delete geometryGroups[ geometry.id ]; + } else { deleteBuffers( geometry ); @@ -20229,6 +18660,10 @@ THREE.WebGLRenderer = function ( parameters ) { } + // TOFIX: Workaround for deleted geometry being currently bound + + _currentGeometryProgram = ''; + }; var deallocateTexture = function ( texture ) { @@ -20239,25 +18674,31 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.deleteTexture( texture.image.__webglTextureCube ); + delete texture.image.__webglTextureCube; + } else { // 2D texture - if ( ! texture.__webglInit ) return; + if ( texture.__webglInit === undefined ) return; - texture.__webglInit = false; _gl.deleteTexture( texture.__webglTexture ); + delete texture.__webglTexture; + delete texture.__webglInit; + } }; var deallocateRenderTarget = function ( renderTarget ) { - if ( !renderTarget || ! renderTarget.__webglTexture ) return; + if ( ! renderTarget || renderTarget.__webglTexture === undefined ) return; _gl.deleteTexture( renderTarget.__webglTexture ); + delete renderTarget.__webglTexture; + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { for ( var i = 0; i < 6; i ++ ) { @@ -20274,11 +18715,14 @@ THREE.WebGLRenderer = function ( parameters ) { } + delete renderTarget.__webglFramebuffer; + delete renderTarget.__webglRenderbuffer; + }; var deallocateMaterial = function ( material ) { - var program = material.program; + var program = material.program.program; if ( program === undefined ) return; @@ -20341,12 +18785,13 @@ THREE.WebGLRenderer = function ( parameters ) { // Buffer initialization - function initCustomAttributes ( geometry, object ) { - - var nvertices = geometry.vertices.length; + function initCustomAttributes ( object ) { + var geometry = object.geometry; var material = object.material; + var nvertices = geometry.vertices.length; + if ( material.attributes ) { if ( geometry.__webglCustomAttributesList === undefined ) { @@ -20355,27 +18800,27 @@ THREE.WebGLRenderer = function ( parameters ) { } - for ( var a in material.attributes ) { + for ( var name in material.attributes ) { - var attribute = material.attributes[ a ]; + var attribute = material.attributes[ name ]; - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { attribute.__webglInitialized = true; - var size = 1; // "f" and "i" + var size = 1; // "f" and "i" - if ( attribute.type === "v2" ) size = 2; - else if ( attribute.type === "v3" ) size = 3; - else if ( attribute.type === "v4" ) size = 4; - else if ( attribute.type === "c" ) size = 3; + if ( attribute.type === 'v2' ) size = 2; + else if ( attribute.type === 'v3' ) size = 3; + else if ( attribute.type === 'v4' ) size = 4; + else if ( attribute.type === 'c' ) size = 3; attribute.size = size; attribute.array = new Float32Array( nvertices * size ); attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; + attribute.buffer.belongsToAttribute = name; attribute.needsUpdate = true; @@ -20396,11 +18841,9 @@ THREE.WebGLRenderer = function ( parameters ) { geometry.__vertexArray = new Float32Array( nvertices * 3 ); geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__sortArray = []; - geometry.__webglParticleCount = nvertices; - initCustomAttributes ( geometry, object ); + initCustomAttributes( object ); }; @@ -20414,7 +18857,7 @@ THREE.WebGLRenderer = function ( parameters ) { geometry.__webglLineCount = nvertices; - initCustomAttributes ( geometry, object ); + initCustomAttributes( object ); }; @@ -20427,19 +18870,16 @@ THREE.WebGLRenderer = function ( parameters ) { ntris = faces3.length * 1, nlines = faces3.length * 3, - material = getBufferMaterial( object, geometryGroup ), - - uvType = bufferGuessUVType( material ), - normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ); - - // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); + material = getBufferMaterial( object, geometryGroup ); geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); - if ( normalType ) { + if ( geometry.faceVertexUvs.length > 1 ) { - geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); } @@ -20449,28 +18889,6 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( vertexColorType ) { - - geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); - - } - - if ( uvType ) { - - if ( geometry.faceVertexUvs.length > 0 ) { - - geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); - - } - - if ( geometry.faceVertexUvs.length > 1 ) { - - geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); - - } - - } - if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); @@ -20478,16 +18896,19 @@ THREE.WebGLRenderer = function ( parameters ) { } - geometryGroup.__faceArray = new Uint16Array( ntris * 3 ); - geometryGroup.__lineArray = new Uint16Array( nlines * 2 ); + var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3 + + geometryGroup.__typeArray = UintArray; + geometryGroup.__faceArray = new UintArray( ntris * 3 ); + geometryGroup.__lineArray = new UintArray( nlines * 2 ); - var m, ml; + var numMorphTargets = geometryGroup.numMorphTargets; - if ( geometryGroup.numMorphTargets ) { + if ( numMorphTargets ) { geometryGroup.__morphTargetsArrays = []; - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + for ( var m = 0, ml = numMorphTargets; m < ml; m ++ ) { geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); @@ -20495,11 +18916,13 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( geometryGroup.numMorphNormals ) { + var numMorphNormals = geometryGroup.numMorphNormals; + + if ( numMorphNormals ) { geometryGroup.__morphNormalsArrays = []; - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + for ( var m = 0, ml = numMorphNormals; m < ml; m ++ ) { geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); @@ -20521,12 +18944,12 @@ THREE.WebGLRenderer = function ( parameters ) { } - for ( var a in material.attributes ) { + for ( var name in material.attributes ) { // Do a shallow copy of the attribute object so different geometryGroup chunks use different // attribute buffers which are correctly indexed in the setMeshBuffers function - var originalAttribute = material.attributes[ a ]; + var originalAttribute = material.attributes[ name ]; var attribute = {}; @@ -20536,23 +18959,23 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + if ( ! attribute.__webglInitialized || attribute.createUniqueBuffers ) { attribute.__webglInitialized = true; - var size = 1; // "f" and "i" + var size = 1; // "f" and "i" - if( attribute.type === "v2" ) size = 2; - else if( attribute.type === "v3" ) size = 3; - else if( attribute.type === "v4" ) size = 4; - else if( attribute.type === "c" ) size = 3; + if ( attribute.type === 'v2' ) size = 2; + else if ( attribute.type === 'v3' ) size = 3; + else if ( attribute.type === 'v4' ) size = 4; + else if ( attribute.type === 'c' ) size = 3; attribute.size = size; attribute.array = new Float32Array( nvertices * size ); attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; + attribute.buffer.belongsToAttribute = name; originalAttribute.needsUpdate = true; attribute.__original = originalAttribute; @@ -20572,110 +18995,22 @@ THREE.WebGLRenderer = function ( parameters ) { function getBufferMaterial( object, geometryGroup ) { return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ geometryGroup.materialIndex ] - : object.material; - - }; - - function materialNeedsSmoothNormals ( material ) { - - return material && material.shading !== undefined && material.shading === THREE.SmoothShading; - - }; - - function bufferGuessNormalType ( material ) { - - // only MeshBasicMaterial and MeshDepthMaterial don't need normals - - if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { - - return false; - - } - - if ( materialNeedsSmoothNormals( material ) ) { - - return THREE.SmoothShading; - - } else { - - return THREE.FlatShading; - - } + ? object.material.materials[ geometryGroup.materialIndex ] + : object.material; - }; - - function bufferGuessVertexColorType( material ) { - - if ( material.vertexColors ) { - - return material.vertexColors; - - } - - return false; - - }; - - function bufferGuessUVType( material ) { - - // material must use some texture to require uvs - - if ( material.map || - material.lightMap || - material.bumpMap || - material.normalMap || - material.specularMap || - material instanceof THREE.ShaderMaterial ) { - - return true; - - } - - return false; - - }; - - // - - function initDirectBuffers( geometry ) { - - var a, attribute, type; - - for ( a in geometry.attributes ) { - - if ( a === "index" ) { - - type = _gl.ELEMENT_ARRAY_BUFFER; - - } else { - - type = _gl.ARRAY_BUFFER; - - } - - attribute = geometry.attributes[ a ]; - - if ( attribute.numItems === undefined ) { - - attribute.numItems = attribute.array.length; - - } - - attribute.buffer = _gl.createBuffer(); + } - _gl.bindBuffer( type, attribute.buffer ); - _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW ); + function materialNeedsFaceNormals ( material ) { - } + return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading; - }; + } // Buffer setting function setParticleBuffers ( geometry, hint, object ) { - var v, c, vertex, offset, index, color, + var v, c, vertex, offset, color, vertices = geometry.vertices, vl = vertices.length, @@ -20686,39 +19021,20 @@ THREE.WebGLRenderer = function ( parameters ) { vertexArray = geometry.__vertexArray, colorArray = geometry.__colorArray, - sortArray = geometry.__sortArray, - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, dirtyColors = geometry.colorsNeedUpdate, customAttributes = geometry.__webglCustomAttributesList, i, il, - a, ca, cal, value, + ca, cal, value, customAttribute; - if ( object.sortParticles ) { - - _projScreenMatrixPS.copy( _projScreenMatrix ); - _projScreenMatrixPS.multiply( object.matrixWorld ); + if ( dirtyVertices ) { for ( v = 0; v < vl; v ++ ) { vertex = vertices[ v ]; - _vector3.copy( vertex ); - _vector3.applyProjection( _projScreenMatrixPS ); - - sortArray[ v ] = [ _vector3.z, v ]; - - } - - sortArray.sort( numericalSort ); - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ sortArray[v][1] ]; - offset = v * 3; vertexArray[ offset ] = vertex.x; @@ -20727,11 +19043,18 @@ THREE.WebGLRenderer = function ( parameters ) { } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors ) { + for ( c = 0; c < cl; c ++ ) { - offset = c * 3; + color = colors[ c ]; - color = colors[ sortArray[c][1] ]; + offset = c * 3; colorArray[ offset ] = color.r; colorArray[ offset + 1 ] = color.g; @@ -20739,25 +19062,28 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( customAttributes ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + } - customAttribute = customAttributes[ i ]; + if ( customAttributes ) { - if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - offset = 0; + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { cal = customAttribute.value.length; + offset = 0; + if ( customAttribute.size === 1 ) { for ( ca = 0; ca < cal; ca ++ ) { - index = sortArray[ ca ][ 1 ]; - - customAttribute.array[ ca ] = customAttribute.value[ index ]; + customAttribute.array[ ca ] = customAttribute.value[ ca ]; } @@ -20765,11 +19091,9 @@ THREE.WebGLRenderer = function ( parameters ) { for ( ca = 0; ca < cal; ca ++ ) { - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; offset += 2; @@ -20778,15 +19102,13 @@ THREE.WebGLRenderer = function ( parameters ) { } else if ( customAttribute.size === 3 ) { - if ( customAttribute.type === "c" ) { + if ( customAttribute.type === 'c' ) { for ( ca = 0; ca < cal; ca ++ ) { - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset ] = value.r; customAttribute.array[ offset + 1 ] = value.g; customAttribute.array[ offset + 2 ] = value.b; @@ -20798,11 +19120,9 @@ THREE.WebGLRenderer = function ( parameters ) { for ( ca = 0; ca < cal; ca ++ ) { - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; + value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; @@ -20816,9 +19136,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( ca = 0; ca < cal; ca ++ ) { - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; + value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; @@ -20833,167 +19151,16 @@ THREE.WebGLRenderer = function ( parameters ) { } - } - - } else { - - if ( dirtyVertices ) { - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - } - - if ( dirtyColors ) { - - for ( c = 0; c < cl; c ++ ) { - - color = colors[ c ]; - - offset = c * 3; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices") ) { - - cal = customAttribute.value.length; - - offset = 0; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - customAttribute.array[ ca ] = customAttribute.value[ ca ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === "c" ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - } - - } - - } - - } - - if ( dirtyVertices || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyColors || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - } + customAttribute.needsUpdate = false; } } - - }; + } function setLineBuffers ( geometry, hint ) { @@ -21018,7 +19185,7 @@ THREE.WebGLRenderer = function ( parameters ) { customAttributes = geometry.__webglCustomAttributesList, i, il, - a, ca, cal, value, + ca, cal, value, customAttribute; if ( dirtyVertices ) { @@ -21078,9 +19245,7 @@ THREE.WebGLRenderer = function ( parameters ) { customAttribute = customAttributes[ i ]; - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices" ) ) { + if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) ) { offset = 0; @@ -21100,7 +19265,7 @@ THREE.WebGLRenderer = function ( parameters ) { value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; offset += 2; @@ -21109,13 +19274,13 @@ THREE.WebGLRenderer = function ( parameters ) { } else if ( customAttribute.size === 3 ) { - if ( customAttribute.type === "c" ) { + if ( customAttribute.type === 'c' ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset ] = value.r; customAttribute.array[ offset + 1 ] = value.g; customAttribute.array[ offset + 2 ] = value.b; @@ -21129,7 +19294,7 @@ THREE.WebGLRenderer = function ( parameters ) { value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; @@ -21145,7 +19310,7 @@ THREE.WebGLRenderer = function ( parameters ) { value = customAttribute.value[ ca ]; - customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; customAttribute.array[ offset + 3 ] = value.w; @@ -21159,13 +19324,15 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + customAttribute.needsUpdate = false; + } } } - }; + } function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { @@ -21175,27 +19342,20 @@ THREE.WebGLRenderer = function ( parameters ) { } - var normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ), - uvType = bufferGuessUVType( material ), - - needsSmoothNormals = ( normalType === THREE.SmoothShading ); + var needsFaceNormals = materialNeedsFaceNormals( material ); var f, fl, fi, face, - vertexNormals, faceNormal, normal, + vertexNormals, faceNormal, vertexColors, faceColor, vertexTangents, - uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, - c1, c2, c3, c4, - sw1, sw2, sw3, sw4, - si1, si2, si3, si4, - sa1, sa2, sa3, sa4, - sb1, sb2, sb3, sb4, - m, ml, i, il, + uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3, + c1, c2, c3, + sw1, sw2, sw3, + si1, si2, si3, + i, il, vn, uvi, uv2i, vk, vkl, vka, nka, chf, faceVertexNormals, - a, vertexIndex = 0, @@ -21210,7 +19370,6 @@ THREE.WebGLRenderer = function ( parameters ) { offset_skin = 0, offset_morphTarget = 0, offset_custom = 0, - offset_customSrc = 0, value, @@ -21250,8 +19409,6 @@ THREE.WebGLRenderer = function ( parameters ) { obj_uvs = geometry.faceVertexUvs[ 0 ], obj_uvs2 = geometry.faceVertexUvs[ 1 ], - obj_colors = geometry.colors, - obj_skinIndices = geometry.skinIndices, obj_skinWeights = geometry.skinWeights, @@ -21308,7 +19465,7 @@ THREE.WebGLRenderer = function ( parameters ) { vka = morphTargetsArrays[ vk ]; - vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget ] = v1.x; vka[ offset_morphTarget + 1 ] = v1.y; vka[ offset_morphTarget + 2 ] = v1.z; @@ -21324,7 +19481,13 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.morphNormals ) { - if ( needsSmoothNormals ) { + if ( needsFaceNormals ) { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } else { faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; @@ -21332,17 +19495,11 @@ THREE.WebGLRenderer = function ( parameters ) { n2 = faceVertexNormals.b; n3 = faceVertexNormals.c; - } else { - - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; - } nka = morphNormalsArrays[ vk ]; - nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget ] = n1.x; nka[ offset_morphTarget + 1 ] = n1.y; nka[ offset_morphTarget + 2 ] = n1.z; @@ -21380,7 +19537,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; // weights @@ -21440,16 +19597,16 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( dirtyColors && vertexColorType ) { + if ( dirtyColors ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; vertexColors = face.vertexColors; faceColor = face.color; - if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { + if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) { c1 = vertexColors[ 0 ]; c2 = vertexColors[ 1 ]; @@ -21492,7 +19649,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; vertexTangents = face.vertexTangents; @@ -21524,16 +19681,16 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( dirtyNormals && normalType ) { + if ( dirtyNormals ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; vertexNormals = face.vertexNormals; faceNormal = face.normal; - if ( vertexNormals.length === 3 && needsSmoothNormals ) { + if ( vertexNormals.length === 3 && needsFaceNormals === false ) { for ( i = 0; i < 3; i ++ ) { @@ -21568,7 +19725,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( dirtyUvs && obj_uvs && uvType ) { + if ( dirtyUvs && obj_uvs ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21600,7 +19757,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( dirtyUvs && obj_uvs2 && uvType ) { + if ( dirtyUvs && obj_uvs2 ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21636,7 +19793,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face ] = vertexIndex; faceArray[ offset_face + 1 ] = vertexIndex + 1; faceArray[ offset_face + 2 ] = vertexIndex + 2; @@ -21674,17 +19831,16 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! customAttribute.__original.needsUpdate ) continue; offset_custom = 0; - offset_customSrc = 0; if ( customAttribute.size === 1 ) { - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; @@ -21692,13 +19848,13 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faces" ) { + } else if ( customAttribute.boundTo === 'faces' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; - customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom ] = value; customAttribute.array[ offset_custom + 1 ] = value; customAttribute.array[ offset_custom + 2 ] = value; @@ -21710,17 +19866,17 @@ THREE.WebGLRenderer = function ( parameters ) { } else if ( customAttribute.size === 2 ) { - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; - customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v2.x; @@ -21733,7 +19889,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faces" ) { + } else if ( customAttribute.boundTo === 'faces' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21743,7 +19899,7 @@ THREE.WebGLRenderer = function ( parameters ) { v2 = value; v3 = value; - customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v2.x; @@ -21762,27 +19918,27 @@ THREE.WebGLRenderer = function ( parameters ) { var pp; - if ( customAttribute.type === "c" ) { + if ( customAttribute.type === 'c' ) { - pp = [ "r", "g", "b" ]; + pp = [ 'r', 'g', 'b' ]; } else { - pp = [ "x", "y", "z" ]; + pp = [ 'x', 'y', 'z' ]; } - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; @@ -21798,7 +19954,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faces" ) { + } else if ( customAttribute.boundTo === 'faces' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21808,7 +19964,7 @@ THREE.WebGLRenderer = function ( parameters ) { v2 = value; v3 = value; - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; @@ -21824,7 +19980,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faceVertices" ) { + } else if ( customAttribute.boundTo === 'faceVertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21834,7 +19990,7 @@ THREE.WebGLRenderer = function ( parameters ) { v2 = value[ 1 ]; v3 = value[ 2 ]; - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; @@ -21854,17 +20010,17 @@ THREE.WebGLRenderer = function ( parameters ) { } else if ( customAttribute.size === 4 ) { - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === 'vertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - face = obj_faces[ chunk_faces3[ f ] ]; + face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; - customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; @@ -21883,7 +20039,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faces" ) { + } else if ( customAttribute.boundTo === 'faces' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21893,7 +20049,7 @@ THREE.WebGLRenderer = function ( parameters ) { v2 = value; v3 = value; - customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; @@ -21912,7 +20068,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - } else if ( customAttribute.boundTo === "faceVertices" ) { + } else if ( customAttribute.boundTo === 'faceVertices' ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { @@ -21922,7 +20078,7 @@ THREE.WebGLRenderer = function ( parameters ) { v2 = value[ 1 ]; v3 = value[ 2 ]; - customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; @@ -21970,48 +20126,12 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function setDirectBuffers ( geometry, hint, dispose ) { - - var attributes = geometry.attributes; - - var attributeName, attributeItem; - - for ( attributeName in attributes ) { - - attributeItem = attributes[ attributeName ]; - - if ( attributeItem.needsUpdate ) { - - if ( attributeName === 'index' ) { - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); - - } else { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); - - } - - attributeItem.needsUpdate = false; - - } - - if ( dispose && ! attributeItem.dynamic ) { - - attributeItem.array = null; - - } - - } - - }; - // Buffer rendering this.renderBufferImmediate = function ( object, program, material ) { + state.initAttributes(); + 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(); @@ -22021,7 +20141,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.position ); + + state.enableAttribute( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -22030,14 +20152,15 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - if ( material.shading === THREE.FlatShading ) { + if ( material instanceof THREE.MeshPhongMaterial === false && + material.shading === THREE.FlatShading ) { var nx, ny, nz, nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, normalArray, i, il = object.count * 3; - for( i = 0; i < il; i += 9 ) { + for ( i = 0; i < il; i += 9 ) { normalArray = object.normalArray; @@ -22057,7 +20180,7 @@ THREE.WebGLRenderer = function ( parameters ) { ny = ( nay + nby + ncy ) / 3; nz = ( naz + nbz + ncz ) / 3; - normalArray[ i ] = nx; + normalArray[ i ] = nx; normalArray[ i + 1 ] = ny; normalArray[ i + 2 ] = nz; @@ -22074,7 +20197,9 @@ THREE.WebGLRenderer = function ( parameters ) { } _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.normal ); + + state.enableAttribute( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -22083,7 +20208,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.uv ); + + state.enableAttribute( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } @@ -22092,1688 +20219,1295 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.color ); + + state.enableAttribute( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } + state.disableUnusedAttributes(); + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); object.count = 0; }; - this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { - - if ( material.visible === false ) return; - - var linewidth, a, attribute; - var attributeItem, attributeName, attributePointer, attributeSize; - - var program = setProgram( camera, lights, fog, material, object ); + function setupVertexAttributes( material, program, geometry, startIndex ) { - var programAttributes = program.attributes; var geometryAttributes = geometry.attributes; - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; - - if ( geometryHash !== _currentGeometryGroupHash ) { - - _currentGeometryGroupHash = geometryHash; - updateBuffers = true; - - } - - if ( updateBuffers ) { - - disableAttributes(); - - } - - // render mesh - - if ( object instanceof THREE.Mesh ) { - - var index = geometryAttributes[ "index" ]; - - // indexed triangles - - if ( index ) { - - var offsets = geometry.offsets; - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - if ( offsets.length > 1 ) updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 - - } else if ( material.defaultAttributeValues ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - // indices - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed triangles - - _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16 - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - _this.info.render.faces += offsets[ i ].count / 3; - - } - - // non-indexed triangles - - } else { - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - if ( attributeName === 'index') continue; - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - } - - var position = geometry.attributes[ "position" ]; - - // render non-indexed triangles - - _gl.drawArrays( _gl.TRIANGLES, 0, position.numItems / 3 ); - - _this.info.render.calls ++; - _this.info.render.vertices += position.numItems / 3; - _this.info.render.faces += position.numItems / 3 / 3; - - } - - // render particles + var programAttributes = program.attributes; + var programAttributesKeys = program.attributesKeys; - } else if ( object instanceof THREE.ParticleSystem ) { + for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) { - if ( updateBuffers ) { + var key = programAttributesKeys[ i ]; + var programAttribute = programAttributes[ key ]; - for ( attributeName in programAttributes ) { + if ( programAttribute >= 0 ) { - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; + var geometryAttribute = geometryAttributes[ key ]; - if ( attributePointer >= 0 ) { + if ( geometryAttribute !== undefined ) { - if ( attributeItem ) { + var size = geometryAttribute.itemSize; - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); - } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { + state.enableAttribute( programAttribute ); - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + } else if ( material.defaultAttributeValues !== undefined ) { - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + if ( material.defaultAttributeValues[ key ].length === 2 ) { - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] ); - } + } else if ( material.defaultAttributeValues[ key ].length === 3 ) { - } + _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] ); } } - var position = geometryAttributes[ "position" ]; - - // render particles - - _gl.drawArrays( _gl.POINTS, 0, position.numItems / 3 ); - - _this.info.render.calls ++; - _this.info.render.points += position.numItems / 3; - } - } else if ( object instanceof THREE.Line ) { - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - // render lines - - var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - - setLineWidth( material.linewidth ); - - var position = geometryAttributes[ "position" ]; - - _gl.drawArrays( primitives, 0, position.numItems / 3 ); - - _this.info.render.calls ++; - _this.info.render.points += position.numItems; - - } + } - } + state.disableUnusedAttributes(); - }; + } - this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { + this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { if ( material.visible === false ) return; - var linewidth, a, attribute, i, il; + updateObject( object ); var program = setProgram( camera, lights, fog, material, object ); - var attributes = program.attributes; - var updateBuffers = false, wireframeBit = material.wireframe ? 1 : 0, - geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit; - if ( geometryGroupHash !== _currentGeometryGroupHash ) { + if ( geometryProgram !== _currentGeometryProgram ) { - _currentGeometryGroupHash = geometryGroupHash; + _currentGeometryProgram = geometryProgram; updateBuffers = true; } if ( updateBuffers ) { - disableAttributes(); - - } - - // vertices - - if ( !material.morphTargets && attributes.position >= 0 ) { - - if ( updateBuffers ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - } else { - - if ( object.morphTargetBase ) { - - setupMorphTargets( material, geometryGroup, object ); - - } + state.initAttributes(); } + // render mesh - if ( updateBuffers ) { - - // custom attributes - - // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers - - if ( geometryGroup.__webglCustomAttributesList ) { - - for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { - - attribute = geometryGroup.__webglCustomAttributesList[ i ]; - - if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); - - } - - } - - } - - - // colors - - if ( attributes.color >= 0 ) { - - if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - enableAttribute( attributes.color ); - _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues ) { - + if ( object instanceof THREE.Mesh ) { - _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); + var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES; - } + var index = geometry.attributes.index; - } + if ( index ) { - // normals + // indexed triangles - if ( attributes.normal >= 0 ) { + var type, size; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - enableAttribute( attributes.normal ); - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - } + type = _gl.UNSIGNED_INT; + size = 4; - // tangents + } else { - if ( attributes.tangent >= 0 ) { + type = _gl.UNSIGNED_SHORT; + size = 2; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - enableAttribute( attributes.tangent ); - _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); + } - } + var offsets = geometry.offsets; - // uvs + if ( offsets.length === 0 ) { - if ( attributes.uv >= 0 ) { + if ( updateBuffers ) { - if ( object.geometry.faceVertexUvs[0] ) { + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - enableAttribute( attributes.uv ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + } - } else if ( material.defaultAttributeValues ) { + _gl.drawElements( mode, index.array.length, type, 0 ); + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + _this.info.render.faces += index.array.length / 3; - _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); + } else { - } + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - } + updateBuffers = true; - if ( attributes.uv2 >= 0 ) { + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - if ( object.geometry.faceVertexUvs[1] ) { + var startIndex = offsets[ i ].index; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - enableAttribute( attributes.uv2 ); - _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); + if ( updateBuffers ) { - } else if ( material.defaultAttributeValues ) { + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + } - _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); + // render indexed triangles - } + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - } + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + _this.info.render.faces += offsets[ i ].count / 3; - if ( material.skinning && - attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - enableAttribute( attributes.skinIndex ); - _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - enableAttribute( attributes.skinWeight ); - _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); + } else { - } + // non-indexed triangles - // line distances + if ( updateBuffers ) { - if ( attributes.lineDistance >= 0 ) { + setupVertexAttributes( material, program, geometry, 0 ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - enableAttribute( attributes.lineDistance ); - _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); + } - } + var position = geometry.attributes[ 'position' ]; - } + // render non-indexed triangles - // render mesh + _gl.drawArrays( mode, 0, position.array.length / position.itemSize ); - if ( object instanceof THREE.Mesh ) { + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / position.itemSize; + _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); - // wireframe + } - if ( material.wireframe ) { + } else if ( object instanceof THREE.PointCloud ) { - setLineWidth( material.wireframeLinewidth ); + // render particles - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 ); + var mode = _gl.POINTS; - // triangles + var index = geometry.attributes.index; - } else { + if ( index ) { - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 ); + // indexed points - } + var type, size; - _this.info.render.calls ++; - _this.info.render.vertices += geometryGroup.__webglFaceCount; - _this.info.render.faces += geometryGroup.__webglFaceCount / 3; + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - // render lines + type = _gl.UNSIGNED_INT; + size = 4; - } else if ( object instanceof THREE.Line ) { + } else { - var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + type = _gl.UNSIGNED_SHORT; + size = 2; - setLineWidth( material.linewidth ); + } - _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount ); + var offsets = geometry.offsets; - _this.info.render.calls ++; + if ( offsets.length === 0 ) { - // render particles + if ( updateBuffers ) { - } else if ( object instanceof THREE.ParticleSystem ) { + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); + } - _this.info.render.calls ++; - _this.info.render.points += geometryGroup.__webglParticleCount; + _gl.drawElements( mode, index.array.length, type, 0); - } + _this.info.render.calls ++; + _this.info.render.points += index.array.length; - }; + } else { - function enableAttribute( attribute ) { + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - if ( ! _enabledAttributes[ attribute ] ) { + if ( offsets.length > 1 ) updateBuffers = true; - _gl.enableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = true; + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - } + var startIndex = offsets[ i ].index; - }; + if ( updateBuffers ) { - function disableAttributes() { + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - for ( var attribute in _enabledAttributes ) { + } - if ( _enabledAttributes[ attribute ] ) { + // render indexed points - _gl.disableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = false; + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); - } + _this.info.render.calls ++; + _this.info.render.points += offsets[ i ].count; - } + } - }; + } - function setupMorphTargets ( material, geometryGroup, object ) { + } else { - // set base + // non-indexed points - var attributes = material.program.attributes; + if ( updateBuffers ) { - if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { + setupVertexAttributes( material, program, geometry, 0 ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + } - } else if ( attributes.position >= 0 ) { + var position = geometry.attributes.position; + var offsets = geometry.offsets; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + if ( offsets.length === 0 ) { - } + _gl.drawArrays( mode, 0, position.array.length / 3 ); - if ( object.morphTargetForcedOrder.length ) { + _this.info.render.calls ++; + _this.info.render.points += position.array.length / 3; - // set forced order + } else { - var m = 0; - var order = object.morphTargetForcedOrder; - var influences = object.morphTargetInfluences; + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - while ( m < material.numSupportedMorphTargets && m < order.length ) { + _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - if ( attributes[ "morphTarget" + m ] >= 0 ) { + _this.info.render.calls ++; + _this.info.render.points += offsets[ i ].count; - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + } } - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + } else if ( object instanceof THREE.Line ) { - } + var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; + state.setLineWidth( material.linewidth * pixelRatio ); - m ++; - } + var index = geometry.attributes.index; - } else { + if ( index ) { - // find the most influencing + // indexed lines - var influence, activeInfluenceIndices = []; - var influences = object.morphTargetInfluences; - var i, il = influences.length; + var type, size; - for ( i = 0; i < il; i ++ ) { + if ( index.array instanceof Uint32Array ) { - influence = influences[ i ]; + type = _gl.UNSIGNED_INT; + size = 4; - if ( influence > 0 ) { + } else { - activeInfluenceIndices.push( [ influence, i ] ); + type = _gl.UNSIGNED_SHORT; + size = 2; } - } + var offsets = geometry.offsets; - if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { + if ( offsets.length === 0 ) { - activeInfluenceIndices.sort( numericalSort ); - activeInfluenceIndices.length = material.numSupportedMorphTargets; + if ( updateBuffers ) { - } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { + setupVertexAttributes( material, program, geometry, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - activeInfluenceIndices.sort( numericalSort ); + } - } else if ( activeInfluenceIndices.length === 0 ) { + _gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array - activeInfluenceIndices.push( [ 0, 0 ] ); + _this.info.render.calls ++; + _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared - }; + } else { - var influenceIndex, m = 0; + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change - while ( m < material.numSupportedMorphTargets ) { + if ( offsets.length > 1 ) updateBuffers = true; - if ( activeInfluenceIndices[ m ] ) { + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - influenceIndex = activeInfluenceIndices[ m ][ 1 ]; + var startIndex = offsets[ i ].index; - if ( attributes[ "morphTarget" + m ] >= 0 ) { + if ( updateBuffers ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + setupVertexAttributes( material, program, geometry, startIndex ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - } + } - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + // render indexed lines - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared } - object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; - - } else { - - /* - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + } - if ( material.morphNormals ) { + } else { - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + // non-indexed lines - } - */ + if ( updateBuffers ) { - object.__webglMorphTargetInfluences[ m ] = 0; + setupVertexAttributes( material, program, geometry, 0 ); } - m ++; - - } - - } - - // load updated influences uniform + var position = geometry.attributes.position; + var offsets = geometry.offsets; - if ( material.program.uniforms.morphTargetInfluences !== null ) { + if ( offsets.length === 0 ) { - _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); + _gl.drawArrays( mode, 0, position.array.length / 3 ); - } + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / 3; - }; + } else { - // Sorting + for ( var i = 0, il = offsets.length; i < il; i ++ ) { - function painterSortStable ( a, b ) { + _gl.drawArrays( mode, offsets[ i ].index, offsets[ i ].count ); - if ( a.z !== b.z ) { + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; - return b.z - a.z; + } - } else { + } - return a.id - b.id; + } } }; - function numericalSort ( a, b ) { + this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { - return b[ 0 ] - a[ 0 ]; + if ( material.visible === false ) return; - }; + updateObject( object ); + var program = setProgram( camera, lights, fog, material, object ); - // Rendering + var attributes = program.attributes; - this.render = function ( scene, camera, renderTarget, forceClear ) { + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryProgram = geometryGroup.id + '_' + program.id + '_' + wireframeBit; - if ( camera instanceof THREE.Camera === false ) { + if ( geometryProgram !== _currentGeometryProgram ) { - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + _currentGeometryProgram = geometryProgram; + updateBuffers = true; } - var i, il, + if ( updateBuffers ) { - webglObject, object, - renderList, + state.initAttributes(); - lights = scene.__lights, - fog = scene.fog; + } - // reset caching for this frame + // vertices - _currentMaterialId = -1; - _lightsNeedUpdate = true; + if ( ! material.morphTargets && attributes.position >= 0 ) { - // update scene graph + if ( updateBuffers ) { - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - // update camera matrices and frustum + state.enableAttribute( attributes.position ); - if ( camera.parent === undefined ) camera.updateMatrixWorld(); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + } - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + } else { - // update WebGL objects + if ( object.morphTargetBase ) { - if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); + setupMorphTargets( material, geometryGroup, object ); - // custom render plugins (pre pass) + } - renderPlugins( this.renderPluginsPre, scene, camera ); + } - // - _this.info.render.calls = 0; - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - _this.info.render.points = 0; + if ( updateBuffers ) { - this.setRenderTarget( renderTarget ); + // custom attributes - if ( this.autoClear || forceClear ) { + // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers - this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + if ( geometryGroup.__webglCustomAttributesList ) { - } + for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { - // set matrices for regular objects (frustum culled) + var attribute = geometryGroup.__webglCustomAttributesList[ i ]; - renderList = scene.__webglObjects; + if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { - for ( i = 0, il = renderList.length; i < il; i ++ ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - webglObject = renderList[ i ]; - object = webglObject.object; + state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - webglObject.id = i; - webglObject.render = false; + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); - if ( object.visible ) { + } - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + } - setupMatrices( object, camera ); + } - unrollBufferMaterial( webglObject ); - webglObject.render = true; + // colors - if ( this.sortObjects === true ) { + if ( attributes.color >= 0 ) { - if ( object.renderDepth !== null ) { + if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { - webglObject.z = object.renderDepth; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - } else { + state.enableAttribute( attributes.color ); - _vector3.getPositionFromMatrix( object.matrixWorld ); - _vector3.applyProjection( _projScreenMatrix ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - webglObject.z = _vector3.z; + } else if ( material.defaultAttributeValues !== undefined ) { - } - } + _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); } } - } + // normals - if ( this.sortObjects ) { + if ( attributes.normal >= 0 ) { - renderList.sort( painterSortStable ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - } + state.enableAttribute( attributes.normal ); - // set matrices for immediate objects + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - renderList = scene.__webglObjectsImmediate; + } - for ( i = 0, il = renderList.length; i < il; i ++ ) { + // tangents - webglObject = renderList[ i ]; - object = webglObject.object; + if ( attributes.tangent >= 0 ) { - if ( object.visible ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - setupMatrices( object, camera ); + state.enableAttribute( attributes.tangent ); - unrollImmediateBufferMaterial( webglObject ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); } - } - - if ( scene.overrideMaterial ) { + // uvs - var material = scene.overrideMaterial; + if ( attributes.uv >= 0 ) { - this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - this.setDepthTest( material.depthTest ); - this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + if ( object.geometry.faceVertexUvs[ 0 ] ) { - renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - } else { + state.enableAttribute( attributes.uv ); - var material = null; + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - // opaque pass (front-to-back order) + } else if ( material.defaultAttributeValues !== undefined ) { - this.setBlending( THREE.NoBlending ); - renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); + _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); - // transparent pass (back-to-front order) + } - renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); + } - } + if ( attributes.uv2 >= 0 ) { - // custom render plugins (post pass) + if ( object.geometry.faceVertexUvs[ 1 ] ) { - renderPlugins( this.renderPluginsPost, scene, camera ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + state.enableAttribute( attributes.uv2 ); - // Generate mipmap if we're using any kind of mipmap filtering + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); - if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + } else if ( material.defaultAttributeValues !== undefined ) { - updateRenderTargetMipmap( renderTarget ); - } + _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); - // Ensure depth buffer writing is enabled so it can be cleared on next render + } - this.setDepthTest( true ); - this.setDepthWrite( true ); + } - // _gl.finish(); + if ( material.skinning && + attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { - }; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - function renderPlugins( plugins, scene, camera ) { + state.enableAttribute( attributes.skinIndex ); - if ( ! plugins.length ) return; + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); - for ( var i = 0, il = plugins.length; i < il; i ++ ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - // reset state for plugin (to start from clean slate) + state.enableAttribute( attributes.skinWeight ); - _currentProgram = null; - _currentCamera = null; + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; + } - _lightsNeedUpdate = true; + // line distances - plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); + if ( attributes.lineDistance >= 0 ) { - // reset state after plugin (anything could have changed) + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - _currentProgram = null; - _currentCamera = null; + state.enableAttribute( attributes.lineDistance ); - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); - _lightsNeedUpdate = true; + } } - }; - - function renderObjects ( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { - - var webglObject, object, buffer, material, start, end, delta; + state.disableUnusedAttributes(); - if ( reverse ) { - - start = renderList.length - 1; - end = -1; - delta = -1; + // render mesh - } else { + if ( object instanceof THREE.Mesh ) { - start = 0; - end = renderList.length; - delta = 1; - } + var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; - for ( var i = start; i !== end; i += delta ) { + // wireframe - webglObject = renderList[ i ]; + if ( material.wireframe ) { - if ( webglObject.render ) { + state.setLineWidth( material.wireframeLinewidth * pixelRatio ); - object = webglObject.object; - buffer = webglObject.buffer; + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); - if ( overrideMaterial ) { + // triangles - material = overrideMaterial; + } else { - } else { + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, type, 0 ); - material = webglObject[ materialType ]; + } - if ( ! material ) continue; + _this.info.render.calls ++; + _this.info.render.vertices += geometryGroup.__webglFaceCount; + _this.info.render.faces += geometryGroup.__webglFaceCount / 3; - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + // render lines - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + } else if ( object instanceof THREE.Line ) { - } + var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - _this.setMaterialFaces( material ); + state.setLineWidth( material.linewidth * pixelRatio ); - if ( buffer instanceof THREE.BufferGeometry ) { + _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); - _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); + _this.info.render.calls ++; - } else { + // render particles - _this.renderBuffer( camera, lights, fog, material, buffer, object ); + } else if ( object instanceof THREE.PointCloud ) { - } + _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); - } + _this.info.render.calls ++; + _this.info.render.points += geometryGroup.__webglParticleCount; } }; - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { - - var webglObject, object, material, program; - - for ( var i = 0, il = renderList.length; i < il; i ++ ) { - - webglObject = renderList[ i ]; - object = webglObject.object; - - if ( object.visible ) { + function setupMorphTargets ( material, geometryGroup, object ) { - if ( overrideMaterial ) { + // set base - material = overrideMaterial; + var attributes = material.program.attributes; - } else { + if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { - material = webglObject[ materialType ]; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - if ( ! material ) continue; + state.enableAttribute( attributes.position ); - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + } else if ( attributes.position >= 0 ) { - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - _this.renderImmediateObject( camera, lights, fog, material, object ); + state.enableAttribute( attributes.position ); - } + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } - }; + if ( object.morphTargetForcedOrder.length ) { - this.renderImmediateObject = function ( camera, lights, fog, material, object ) { + // set forced order - var program = setProgram( camera, lights, fog, material, object ); + var m = 0; + var order = object.morphTargetForcedOrder; + var influences = object.morphTargetInfluences; - _currentGeometryGroupHash = -1; + var attribute; - _this.setMaterialFaces( material ); + while ( m < material.numSupportedMorphTargets && m < order.length ) { - if ( object.immediateRenderCallback ) { + attribute = attributes[ 'morphTarget' + m ]; - object.immediateRenderCallback( program, _gl, _frustum ); + if ( attribute >= 0 ) { - } else { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); + state.enableAttribute( attribute ); - } + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - }; + } - function unrollImmediateBufferMaterial ( globject ) { + attribute = attributes[ 'morphNormal' + m ]; - var object = globject.object, - material = object.material; + if ( attribute >= 0 && material.morphNormals ) { - if ( material.transparent ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - globject.transparent = material; - globject.opaque = null; + state.enableAttribute( attribute ); - } else { + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - globject.opaque = material; - globject.transparent = null; + } - } + object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; - }; + m ++; - function unrollBufferMaterial ( globject ) { + } - var object = globject.object, - buffer = globject.buffer, - material, materialIndex, meshMaterial; + } else { - meshMaterial = object.material; + // find the most influencing - if ( meshMaterial instanceof THREE.MeshFaceMaterial ) { + var activeInfluenceIndices = []; + var influences = object.morphTargetInfluences; + var morphTargets = object.geometry.morphTargets; - materialIndex = buffer.materialIndex; + if ( influences.length > morphTargets.length ) { - material = meshMaterial.materials[ materialIndex ]; + console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' ); + influences.length = morphTargets.length; - if ( material.transparent ) { + } - globject.transparent = material; - globject.opaque = null; + for ( var i = 0, il = influences.length; i < il; i ++ ) { - } else { + var influence = influences[ i ]; - globject.opaque = material; - globject.transparent = null; + activeInfluenceIndices.push( [ influence, i ] ); } - } else { - - material = meshMaterial; - - if ( material ) { + if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { - if ( material.transparent ) { + activeInfluenceIndices.sort( numericalSort ); + activeInfluenceIndices.length = material.numSupportedMorphTargets; - globject.transparent = material; - globject.opaque = null; + } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { - } else { + activeInfluenceIndices.sort( numericalSort ); - globject.opaque = material; - globject.transparent = null; + } else if ( activeInfluenceIndices.length === 0 ) { - } + activeInfluenceIndices.push( [ 0, 0 ] ); } - } + var attribute; - }; + for ( var m = 0, ml = material.numSupportedMorphTargets; m < ml; m ++ ) { - // Geometry splitting + if ( activeInfluenceIndices[ m ] ) { - function sortFacesByMaterial ( geometry, material ) { + var influenceIndex = activeInfluenceIndices[ m ][ 1 ]; - var f, fl, face, materialIndex, vertices, - groupHash, hash_map = {}; + attribute = attributes[ 'morphTarget' + m ]; - var numMorphTargets = geometry.morphTargets.length; - var numMorphNormals = geometry.morphNormals.length; + if ( attribute >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - var usesFaceMaterial = material instanceof THREE.MeshFaceMaterial; + state.enableAttribute( attribute ); - geometry.geometryGroups = {}; + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + } - face = geometry.faces[ f ]; - materialIndex = usesFaceMaterial ? face.materialIndex : 0; + attribute = attributes[ 'morphNormal' + m ]; - if ( hash_map[ materialIndex ] === undefined ) { + if ( attribute >= 0 && material.morphNormals ) { - hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - } + state.enableAttribute( attribute ); - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); - if ( geometry.geometryGroups[ groupHash ] === undefined ) { + } - geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; - } + } else { - vertices = 3; + /* + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - if ( geometry.geometryGroups[ groupHash ].vertices + vertices > 65535 ) { + if ( material.morphNormals ) { - hash_map[ materialIndex ].counter += 1; - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - if ( geometry.geometryGroups[ groupHash ] === undefined ) { + } + */ - geometry.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + object.__webglMorphTargetInfluences[ m ] = 0; } } - geometry.geometryGroups[ groupHash ].faces3.push( f ); - geometry.geometryGroups[ groupHash ].vertices += vertices; - } - geometry.geometryGroupsList = []; - - for ( var g in geometry.geometryGroups ) { + // load updated influences uniform - geometry.geometryGroups[ g ].id = _geometryGroupCounter ++; + if ( material.program.uniforms.morphTargetInfluences !== null ) { - geometry.geometryGroupsList.push( geometry.geometryGroups[ g ] ); + _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); } - }; + } - // Objects refresh + // Sorting - this.initWebGLObjects = function ( scene ) { + function painterSortStable ( a, b ) { - if ( !scene.__webglObjects ) { + if ( a.object.renderOrder !== b.object.renderOrder ) { - scene.__webglObjects = []; - scene.__webglObjectsImmediate = []; - scene.__webglSprites = []; - scene.__webglFlares = []; + return a.object.renderOrder - b.object.renderOrder; - } + } else if ( a.material.id !== b.material.id ) { - while ( scene.__objectsAdded.length ) { + return a.material.id - b.material.id; - addObject( scene.__objectsAdded[ 0 ], scene ); - scene.__objectsAdded.splice( 0, 1 ); + } else if ( a.z !== b.z ) { - } + return a.z - b.z; - while ( scene.__objectsRemoved.length ) { + } else { - removeObject( scene.__objectsRemoved[ 0 ], scene ); - scene.__objectsRemoved.splice( 0, 1 ); + return a.id - b.id; } - // update must be called after objects adding / removal + } - for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { + function reversePainterSortStable ( a, b ) { - var object = scene.__webglObjects[ o ].object; + if ( a.object.renderOrder !== b.object.renderOrder ) { - // TODO: Remove this hack (WebGLRenderer refactoring) + return a.object.renderOrder - b.object.renderOrder; - if ( object.__webglInit === undefined ) { + } if ( a.z !== b.z ) { - if ( object.__webglActive !== undefined ) { + return b.z - a.z; - removeObject( object, scene ); + } else { - } + return a.id - b.id; - addObject( object, scene ); + } - } + } - updateObject( object ); + function numericalSort ( a, b ) { - } + return b[ 0 ] - a[ 0 ]; - }; + } - // Objects adding + // Rendering - function addObject( object, scene ) { + this.render = function ( scene, camera, renderTarget, forceClear ) { - var g, geometry, material, geometryGroup; + if ( camera instanceof THREE.Camera === false ) { - if ( object.__webglInit === undefined ) { + THREE.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - object.__webglInit = true; + } - object._modelViewMatrix = new THREE.Matrix4(); - object._normalMatrix = new THREE.Matrix3(); + var fog = scene.fog; - if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) { + // reset caching for this frame - object.geometry.__webglInit = true; - object.geometry.addEventListener( 'dispose', onGeometryDispose ); + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + _currentCamera = null; + _lightsNeedUpdate = true; - } + // update scene graph - geometry = object.geometry; + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - if ( geometry === undefined ) { + // update camera matrices and frustum - // fail silently for now + if ( camera.parent === undefined ) camera.updateMatrixWorld(); - } else if ( geometry instanceof THREE.BufferGeometry ) { + // update Skeleton objects - initDirectBuffers( geometry ); + scene.traverse( function ( object ) { - } else if ( object instanceof THREE.Mesh ) { + if ( object instanceof THREE.SkinnedMesh ) { - material = object.material; + object.skeleton.update(); - if ( geometry.geometryGroups === undefined ) { + } - sortFacesByMaterial( geometry, material ); + } ); - } + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - // create separate VBOs per geometry chunk + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - for ( g in geometry.geometryGroups ) { + lights.length = 0; + opaqueObjects.length = 0; + transparentObjects.length = 0; - geometryGroup = geometry.geometryGroups[ g ]; + sprites.length = 0; + lensFlares.length = 0; - // initialise VBO on the first access + projectObject( scene ); - if ( ! geometryGroup.__webglVertexBuffer ) { + if ( _this.sortObjects === true ) { - createMeshBuffers( geometryGroup ); - initMeshBuffers( geometryGroup, object ); + opaqueObjects.sort( painterSortStable ); + transparentObjects.sort( reversePainterSortStable ); - geometry.verticesNeedUpdate = true; - geometry.morphTargetsNeedUpdate = true; - geometry.elementsNeedUpdate = true; - geometry.uvsNeedUpdate = true; - geometry.normalsNeedUpdate = true; - geometry.tangentsNeedUpdate = true; - geometry.colorsNeedUpdate = true; + } - } + // custom render plugins (pre pass) - } + shadowMapPlugin.render( scene, camera ); - } else if ( object instanceof THREE.Line ) { + // + + _this.info.render.calls = 0; + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + _this.info.render.points = 0; + + this.setRenderTarget( renderTarget ); - if ( ! geometry.__webglVertexBuffer ) { + if ( this.autoClear || forceClear ) { - createLineBuffers( geometry ); - initLineBuffers( geometry, object ); + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - geometry.lineDistancesNeedUpdate = true; + } - } + // set matrices for immediate objects - } else if ( object instanceof THREE.ParticleSystem ) { + for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) { - if ( ! geometry.__webglVertexBuffer ) { + var webglObject = _webglObjectsImmediate[ i ]; + var object = webglObject.object; - createParticleBuffers( geometry ); - initParticleBuffers( geometry, object ); + if ( object.visible ) { - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; + setupMatrices( object, camera ); - } + unrollImmediateBufferMaterial( webglObject ); } } - if ( object.__webglActive === undefined ) { + if ( scene.overrideMaterial ) { - if ( object instanceof THREE.Mesh ) { + var overrideMaterial = scene.overrideMaterial; - geometry = object.geometry; + setMaterial( overrideMaterial ); - if ( geometry instanceof THREE.BufferGeometry ) { + renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); + renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); + renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial ); - addBuffer( scene.__webglObjects, geometry, object ); + } else { - } else if ( geometry instanceof THREE.Geometry ) { + // opaque pass (front-to-back order) - for ( g in geometry.geometryGroups ) { + state.setBlending( THREE.NoBlending ); - geometryGroup = geometry.geometryGroups[ g ]; + renderObjects( opaqueObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null ); - addBuffer( scene.__webglObjects, geometryGroup, object ); + // transparent pass (back-to-front order) - } + renderObjects( transparentObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null ); - } + } - } else if ( object instanceof THREE.Line || - object instanceof THREE.ParticleSystem ) { + // custom render plugins (post pass) - geometry = object.geometry; - addBuffer( scene.__webglObjects, geometry, object ); + spritePlugin.render( scene, camera ); + lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + // Generate mipmap if we're using any kind of mipmap filtering - addBufferImmediate( scene.__webglObjectsImmediate, object ); + if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { - } else if ( object instanceof THREE.Sprite ) { + updateRenderTargetMipmap( renderTarget ); - scene.__webglSprites.push( object ); + } - } else if ( object instanceof THREE.LensFlare ) { + // Ensure depth buffer writing is enabled so it can be cleared on next render - scene.__webglFlares.push( object ); + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); - } + // _gl.finish(); - object.__webglActive = true; + }; - } + function projectObject( object ) { - }; + if ( object.visible === false ) return; - function addBuffer( objlist, buffer, object ) { + if ( object instanceof THREE.Scene || object instanceof THREE.Group ) { - objlist.push( - { - id: null, - buffer: buffer, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); + // skip - }; + } else { - function addBufferImmediate( objlist, object ) { + initObject( object ); - objlist.push( - { - id: null, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); + if ( object instanceof THREE.Light ) { - }; + lights.push( object ); - // Objects updates + } else if ( object instanceof THREE.Sprite ) { - function updateObject( object ) { + sprites.push( object ); - var geometry = object.geometry, - geometryGroup, customAttributesDirty, material; + } else if ( object instanceof THREE.LensFlare ) { - if ( geometry instanceof THREE.BufferGeometry ) { + lensFlares.push( object ); - setDirectBuffers( geometry, _gl.DYNAMIC_DRAW, !geometry.dynamic ); + } else { - } else if ( object instanceof THREE.Mesh ) { + var webglObjects = _webglObjects[ object.id ]; - // check all geometry groups + if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { - for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { + for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - geometryGroup = geometry.geometryGroupsList[ i ]; + var webglObject = webglObjects[ i ]; - material = getBufferMaterial( object, geometryGroup ); + unrollBufferMaterial( webglObject ); - if ( geometry.buffersNeedUpdate ) { + webglObject.render = true; - initMeshBuffers( geometryGroup, object ); + if ( _this.sortObjects === true ) { - } + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + webglObject.z = _vector3.z; - if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || - geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || - geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { + } - setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); + } } } - geometry.verticesNeedUpdate = false; - geometry.morphTargetsNeedUpdate = false; - geometry.elementsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.tangentsNeedUpdate = false; + } - geometry.buffersNeedUpdate = false; + for ( var i = 0, l = object.children.length; i < l; i ++ ) { - material.attributes && clearCustomAttributes( material ); + projectObject( object.children[ i ] ); - } else if ( object instanceof THREE.Line ) { + } - material = getBufferMaterial( object, geometry ); + } - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { + var material; - setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - } + var webglObject = renderList[ i ]; - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.lineDistancesNeedUpdate = false; + var object = webglObject.object; + var buffer = webglObject.buffer; - material.attributes && clearCustomAttributes( material ); + setupMatrices( object, camera ); + if ( overrideMaterial ) { - } else if ( object instanceof THREE.ParticleSystem ) { + material = overrideMaterial; - material = getBufferMaterial( object, geometry ); + } else { - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + material = webglObject.material; - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { + if ( ! material ) continue; - setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); + setMaterial( material ); } - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } + _this.setMaterialFaces( material ); - }; + if ( buffer instanceof THREE.BufferGeometry ) { - // Objects updates - custom attributes check + _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); - function areCustomAttributesDirty( material ) { + } else { - for ( var a in material.attributes ) { + _this.renderBuffer( camera, lights, fog, material, buffer, object ); - if ( material.attributes[ a ].needsUpdate ) return true; + } } - return false; + } - }; + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) { - function clearCustomAttributes( material ) { + var material; - for ( var a in material.attributes ) { + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - material.attributes[ a ].needsUpdate = false; + var webglObject = renderList[ i ]; + var object = webglObject.object; - } + if ( object.visible ) { - }; + if ( overrideMaterial ) { - // Objects removal + material = overrideMaterial; - function removeObject( object, scene ) { + } else { - if ( object instanceof THREE.Mesh || - object instanceof THREE.ParticleSystem || - object instanceof THREE.Line ) { + material = webglObject[ materialType ]; - removeInstances( scene.__webglObjects, object ); + if ( ! material ) continue; - } else if ( object instanceof THREE.Sprite ) { + setMaterial( material ); - removeInstancesDirect( scene.__webglSprites, object ); + } - } else if ( object instanceof THREE.LensFlare ) { + _this.renderImmediateObject( camera, lights, fog, material, object ); - removeInstancesDirect( scene.__webglFlares, object ); + } - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + } - removeInstances( scene.__webglObjectsImmediate, object ); + } - } + this.renderImmediateObject = function ( camera, lights, fog, material, object ) { - delete object.__webglActive; + var program = setProgram( camera, lights, fog, material, object ); - }; + _currentGeometryProgram = ''; - function removeInstances( objlist, object ) { + _this.setMaterialFaces( material ); - for ( var o = objlist.length - 1; o >= 0; o -- ) { + if ( object.immediateRenderCallback ) { - if ( objlist[ o ].object === object ) { + object.immediateRenderCallback( program, _gl, _frustum ); - objlist.splice( o, 1 ); + } else { - } + object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } ); } }; - function removeInstancesDirect( objlist, object ) { - - for ( var o = objlist.length - 1; o >= 0; o -- ) { - - if ( objlist[ o ] === object ) { - - objlist.splice( o, 1 ); + function unrollImmediateBufferMaterial ( globject ) { - } + var object = globject.object, + material = object.material; - } + if ( material.transparent ) { - }; + globject.transparent = material; + globject.opaque = null; - // Materials + } else { - this.initMaterial = function ( material, lights, fog, object ) { + globject.opaque = material; + globject.transparent = null; - material.addEventListener( 'dispose', onMaterialDispose ); + } - var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; + } - if ( material instanceof THREE.MeshDepthMaterial ) { + function unrollBufferMaterial ( globject ) { - shaderID = 'depth'; + var object = globject.object; + var buffer = globject.buffer; - } else if ( material instanceof THREE.MeshNormalMaterial ) { + var geometry = object.geometry; + var material = object.material; - shaderID = 'normal'; + if ( material instanceof THREE.MeshFaceMaterial ) { - } else if ( material instanceof THREE.MeshBasicMaterial ) { + var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; - shaderID = 'basic'; + material = material.materials[ materialIndex ]; - } else if ( material instanceof THREE.MeshLambertMaterial ) { + globject.material = material; - shaderID = 'lambert'; + if ( material.transparent ) { - } else if ( material instanceof THREE.MeshPhongMaterial ) { + transparentObjects.push( globject ); - shaderID = 'phong'; + } else { - } else if ( material instanceof THREE.LineBasicMaterial ) { + opaqueObjects.push( globject ); - shaderID = 'basic'; + } - } else if ( material instanceof THREE.LineDashedMaterial ) { + } else if ( material ) { - shaderID = 'dashed'; + globject.material = material; - } else if ( material instanceof THREE.ParticleSystemMaterial ) { + if ( material.transparent ) { - shaderID = 'particle_basic'; + transparentObjects.push( globject ); - } + } else { - if ( shaderID ) { + opaqueObjects.push( globject ); - setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); + } } - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) + } - maxLightCount = allocateLights( lights ); + function initObject( object ) { - maxShadows = allocateShadows( lights ); + if ( object.__webglInit === undefined ) { - maxBones = allocateBones( object ); + object.__webglInit = true; + object._modelViewMatrix = new THREE.Matrix4(); + object._normalMatrix = new THREE.Matrix3(); - parameters = { + object.addEventListener( 'removed', onObjectRemoved ); - map: !!material.map, - envMap: !!material.envMap, - lightMap: !!material.lightMap, - bumpMap: !!material.bumpMap, - normalMap: !!material.normalMap, - specularMap: !!material.specularMap, + } - vertexColors: material.vertexColors, + var geometry = object.geometry; - fog: fog, - useFog: material.fog, - fogExp: fog instanceof THREE.FogExp2, + if ( geometry === undefined ) { - sizeAttenuation: material.sizeAttenuation, + // ImmediateRenderObject - skinning: material.skinning, - maxBones: maxBones, - useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, + } else if ( geometry.__webglInit === undefined ) { - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: this.maxMorphTargets, - maxMorphNormals: this.maxMorphNormals, + geometry.__webglInit = true; + geometry.addEventListener( 'dispose', onGeometryDispose ); - maxDirLights: maxLightCount.directional, - maxPointLights: maxLightCount.point, - maxSpotLights: maxLightCount.spot, - maxHemiLights: maxLightCount.hemi, + if ( geometry instanceof THREE.BufferGeometry ) { - maxShadows: maxShadows, - shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow, - shadowMapType: this.shadowMapType, - shadowMapDebug: this.shadowMapDebug, - shadowMapCascade: this.shadowMapCascade, + _this.info.memory.geometries ++; - alphaTest: material.alphaTest, - metal: material.metal, - perPixel: material.perPixel, - wrapAround: material.wrapAround, - doubleSided: material.side === THREE.DoubleSide, - flipSided: material.side === THREE.BackSide + } else if ( object instanceof THREE.Mesh ) { - }; + initGeometryGroups( object, geometry ); - material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName ); + } else if ( object instanceof THREE.Line ) { - var attributes = material.program.attributes; + if ( geometry.__webglVertexBuffer === undefined ) { - if ( material.morphTargets ) { + createLineBuffers( geometry ); + initLineBuffers( geometry, object ); - material.numSupportedMorphTargets = 0; + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.lineDistancesNeedUpdate = true; - var id, base = "morphTarget"; + } - for ( i = 0; i < this.maxMorphTargets; i ++ ) { + } else if ( object instanceof THREE.PointCloud ) { - id = base + i; + if ( geometry.__webglVertexBuffer === undefined ) { - if ( attributes[ id ] >= 0 ) { + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); - material.numSupportedMorphTargets ++; + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; } @@ -23781,1646 +21515,1744 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( material.morphNormals ) { + if ( object.__webglActive === undefined) { - material.numSupportedMorphNormals = 0; + object.__webglActive = true; - var id, base = "morphNormal"; + if ( object instanceof THREE.Mesh ) { - for ( i = 0; i < this.maxMorphNormals; i ++ ) { + if ( geometry instanceof THREE.BufferGeometry ) { - id = base + i; + addBuffer( _webglObjects, geometry, object ); - if ( attributes[ id ] >= 0 ) { + } else if ( geometry instanceof THREE.Geometry ) { - material.numSupportedMorphNormals ++; + var geometryGroupsList = geometryGroups[ geometry.id ]; + + for ( var i = 0,l = geometryGroupsList.length; i < l; i ++ ) { + + addBuffer( _webglObjects, geometryGroupsList[ i ], object ); + + } } + } else if ( object instanceof THREE.Line || object instanceof THREE.PointCloud ) { + + addBuffer( _webglObjects, geometry, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + addBufferImmediate( _webglObjectsImmediate, object ); + } } - material.uniformsList = []; + } - for ( u in material.uniforms ) { + // Geometry splitting - material.uniformsList.push( [ material.uniforms[ u ], u ] ); + var geometryGroups = {}; + var geometryGroupCounter = 0; - } + function makeGroups( geometry, usesFaceMaterial ) { - }; + var maxVerticesInGroup = extensions.get( 'OES_element_index_uint' ) ? 4294967296 : 65535; - function setMaterialShaders( material, shaders ) { + var groupHash, hash_map = {}; - material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); - material.vertexShader = shaders.vertexShader; - material.fragmentShader = shaders.fragmentShader; + var numMorphTargets = geometry.morphTargets.length; + var numMorphNormals = geometry.morphNormals.length; - }; + var group; + var groups = {}; + var groupsList = []; - function setProgram( camera, lights, fog, material, object ) { + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - _usedTextureUnits = 0; + var face = geometry.faces[ f ]; + var materialIndex = usesFaceMaterial ? face.materialIndex : 0; - if ( material.needsUpdate ) { + if ( ! ( materialIndex in hash_map ) ) { - if ( material.program ) deallocateMaterial( material ); + hash_map[ materialIndex ] = { hash: materialIndex, counter: 0 }; - _this.initMaterial( material, lights, fog, object ); - material.needsUpdate = false; + } - } + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - if ( material.morphTargets ) { + if ( ! ( groupHash in groups ) ) { - if ( ! object.__webglMorphTargetInfluences ) { + group = { + id: geometryGroupCounter ++, + faces3: [], + materialIndex: materialIndex, + vertices: 0, + numMorphTargets: numMorphTargets, + numMorphNormals: numMorphNormals + }; - object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); + groups[ groupHash ] = group; + groupsList.push( group ); } - } - - var refreshMaterial = false; + if ( groups[ groupHash ].vertices + 3 > maxVerticesInGroup ) { - var program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.uniforms; + hash_map[ materialIndex ].counter += 1; + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - if ( program !== _currentProgram ) { + if ( ! ( groupHash in groups ) ) { - _gl.useProgram( program ); - _currentProgram = program; + group = { + id: geometryGroupCounter ++, + faces3: [], + materialIndex: materialIndex, + vertices: 0, + numMorphTargets: numMorphTargets, + numMorphNormals: numMorphNormals + }; - refreshMaterial = true; + groups[ groupHash ] = group; + groupsList.push( group ); - } + } - if ( material.id !== _currentMaterialId ) { + } - _currentMaterialId = material.id; - refreshMaterial = true; + groups[ groupHash ].faces3.push( f ); + groups[ groupHash ].vertices += 3; } - if ( refreshMaterial || camera !== _currentCamera ) { + return groupsList; - _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + } - if ( camera !== _currentCamera ) _currentCamera = camera; + function initGeometryGroups( object, geometry ) { - } + var material = object.material, addBuffers = false; - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen + if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) { - if ( material.skinning ) { + delete _webglObjects[ object.id ]; - if ( _supportsBoneTextures && object.useVertexTexture ) { + geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial ); - if ( p_uniforms.boneTexture !== null ) { + geometry.groupsNeedUpdate = false; - var textureUnit = getTextureUnit(); + } - _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); - _this.setTexture( object.boneTexture, textureUnit ); + var geometryGroupsList = geometryGroups[ geometry.id ]; - } + // create separate VBOs per geometry chunk - if ( p_uniforms.boneTextureWidth !== null ) { + for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); + var geometryGroup = geometryGroupsList[ i ]; - } + // initialise VBO on the first access - if ( p_uniforms.boneTextureHeight !== null ) { + if ( geometryGroup.__webglVertexBuffer === undefined ) { - _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); - } + geometry.verticesNeedUpdate = true; + geometry.morphTargetsNeedUpdate = true; + geometry.elementsNeedUpdate = true; + geometry.uvsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + geometry.tangentsNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + addBuffers = true; } else { - if ( p_uniforms.boneGlobalMatrices !== null ) { + addBuffers = false; - _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); + } - } + if ( addBuffers || object.__webglActive === undefined ) { + + addBuffer( _webglObjects, geometryGroup, object ); } } - if ( refreshMaterial ) { - - // refresh uniforms common to several materials + object.__webglActive = true; - if ( fog && material.fog ) { + } - refreshUniformsFog( m_uniforms, fog ); + function addBuffer( objlist, buffer, object ) { + var id = object.id; + objlist[id] = objlist[id] || []; + objlist[id].push( + { + id: id, + buffer: buffer, + object: object, + material: null, + z: 0 } + ); - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material.lights ) { - - if ( _lightsNeedUpdate ) { + }; - setupLights( program, lights ); - _lightsNeedUpdate = false; + function addBufferImmediate( objlist, object ) { - } + objlist.push( + { + id: null, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); - refreshUniformsLights( m_uniforms, _lights ); + }; - } + // Objects updates - if ( material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial ) { + function updateObject( object ) { - refreshUniformsCommon( m_uniforms, material ); + var geometry = object.geometry; - } + if ( geometry instanceof THREE.BufferGeometry ) { - // refresh single material specific uniforms + var attributes = geometry.attributes; + var attributesKeys = geometry.attributesKeys; - if ( material instanceof THREE.LineBasicMaterial ) { + for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) { - refreshUniformsLine( m_uniforms, material ); + var key = attributesKeys[ i ]; + var attribute = attributes[ key ]; + var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; - } else if ( material instanceof THREE.LineDashedMaterial ) { + if ( attribute.buffer === undefined ) { - refreshUniformsLine( m_uniforms, material ); - refreshUniformsDash( m_uniforms, material ); + attribute.buffer = _gl.createBuffer(); + _gl.bindBuffer( bufferType, attribute.buffer ); + _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW ); - } else if ( material instanceof THREE.ParticleSystemMaterial ) { + attribute.needsUpdate = false; - refreshUniformsParticle( m_uniforms, material ); + } else if ( attribute.needsUpdate === true ) { - } else if ( material instanceof THREE.MeshPhongMaterial ) { + _gl.bindBuffer( bufferType, attribute.buffer ); - refreshUniformsPhong( m_uniforms, material ); + if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges - } else if ( material instanceof THREE.MeshLambertMaterial ) { + _gl.bufferSubData( bufferType, 0, attribute.array ); - refreshUniformsLambert( m_uniforms, material ); + } else if ( attribute.updateRange.count === 0 ) { - } else if ( material instanceof THREE.MeshDepthMaterial ) { + console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' ); - m_uniforms.mNear.value = camera.near; - m_uniforms.mFar.value = camera.far; - m_uniforms.opacity.value = material.opacity; + } else { - } else if ( material instanceof THREE.MeshNormalMaterial ) { + _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT, + attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) ); - m_uniforms.opacity.value = material.opacity; + attribute.updateRange.count = 0; // reset range - } + } - if ( object.receiveShadow && ! material._shadowPass ) { + attribute.needsUpdate = false; - refreshUniformsShadow( m_uniforms, lights ); + } } - // load common uniforms + } else if ( object instanceof THREE.Mesh ) { - loadUniformsGeneric( program, material.uniformsList ); + // check all geometry groups - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + if ( geometry.groupsNeedUpdate === true ) { - if ( material instanceof THREE.ShaderMaterial || - material instanceof THREE.MeshPhongMaterial || - material.envMap ) { + initGeometryGroups( object, geometry ); - if ( p_uniforms.cameraPosition !== null ) { + } - _vector3.getPositionFromMatrix( camera.matrixWorld ); - _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); + var geometryGroupsList = geometryGroups[ geometry.id ]; - } + for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) { - } + var geometryGroup = geometryGroupsList[ i ]; + var material = getBufferMaterial( object, geometryGroup ); - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.ShaderMaterial || - material.skinning ) { + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - if ( p_uniforms.viewMatrix !== null ) { + if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { - _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); + setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, ! geometry.dynamic, material ); } } - } - - loadUniformsMatrices( p_uniforms, object ); - - if ( p_uniforms.modelMatrix !== null ) { + geometry.verticesNeedUpdate = false; + geometry.morphTargetsNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; - _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); + material.attributes && clearCustomAttributes( material ); - } + } else if ( object instanceof THREE.Line ) { - return program; + var material = getBufferMaterial( object, geometry ); + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - }; + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { - // Uniforms (refresh uniforms objects) + setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); - function refreshUniformsCommon ( uniforms, material ) { + } - uniforms.opacity.value = material.opacity; + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.lineDistancesNeedUpdate = false; - if ( _this.gammaInput ) { + material.attributes && clearCustomAttributes( material ); - uniforms.diffuse.value.copyGammaToLinear( material.color ); + } else if ( object instanceof THREE.PointCloud ) { - } else { + var material = getBufferMaterial( object, geometry ); + var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - uniforms.diffuse.value = material.color; + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || customAttributesDirty ) { - } + setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); - uniforms.map.value = material.map; - uniforms.lightMap.value = material.lightMap; - uniforms.specularMap.value = material.specularMap; + } - if ( material.bumpMap ) { + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + material.attributes && clearCustomAttributes( material ); } - if ( material.normalMap ) { + } - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); + // Objects updates - custom attributes check - } + function areCustomAttributesDirty( material ) { - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map + for ( var name in material.attributes ) { - var uvScaleMap; + if ( material.attributes[ name ].needsUpdate ) return true; - if ( material.map ) { + } - uvScaleMap = material.map; + return false; - } else if ( material.specularMap ) { + } - uvScaleMap = material.specularMap; + function clearCustomAttributes( material ) { - } else if ( material.normalMap ) { + for ( var name in material.attributes ) { - uvScaleMap = material.normalMap; + material.attributes[ name ].needsUpdate = false; - } else if ( material.bumpMap ) { + } - uvScaleMap = material.bumpMap; + } - } + // Objects removal - if ( uvScaleMap !== undefined ) { + function removeObject( object ) { - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; + if ( object instanceof THREE.Mesh || + object instanceof THREE.PointCloud || + object instanceof THREE.Line ) { - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + delete _webglObjects[ object.id ]; - } + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + removeInstances( _webglObjectsImmediate, object ); - if ( _this.gammaInput ) { + } - //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; - uniforms.reflectivity.value = material.reflectivity; + delete object.__webglInit; + delete object._modelViewMatrix; + delete object._normalMatrix; - } else { + delete object.__webglActive; - uniforms.reflectivity.value = material.reflectivity; + } - } + function removeInstances( objlist, object ) { - uniforms.refractionRatio.value = material.refractionRatio; - uniforms.combine.value = material.combine; - uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; + for ( var o = objlist.length - 1; o >= 0; o -- ) { - }; + if ( objlist[ o ].object === object ) { - function refreshUniformsLine ( uniforms, material ) { + objlist.splice( o, 1 ); - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; + } - }; + } - function refreshUniformsDash ( uniforms, material ) { + } - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; + // Materials + var shaderIDs = { + MeshDepthMaterial: 'depth', + MeshNormalMaterial: 'normal', + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + LineBasicMaterial: 'basic', + LineDashedMaterial: 'dashed', + PointCloudMaterial: 'particle_basic' }; - function refreshUniformsParticle ( uniforms, material ) { + function initMaterial( material, lights, fog, object ) { - uniforms.psColor.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size; - uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. + material.addEventListener( 'dispose', onMaterialDispose ); - uniforms.map.value = material.map; + var shaderID = shaderIDs[ material.type ]; - }; + if ( shaderID ) { - function refreshUniformsFog ( uniforms, fog ) { + var shader = THREE.ShaderLib[ shaderID ]; - uniforms.fogColor.value = fog.color; + material.__webglShader = { + uniforms: THREE.UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + } - if ( fog instanceof THREE.Fog ) { + } else { - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + material.__webglShader = { + uniforms: material.uniforms, + vertexShader: material.vertexShader, + fragmentShader: material.fragmentShader + } - } else if ( fog instanceof THREE.FogExp2 ) { + } - uniforms.fogDensity.value = fog.density; + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) - } + var maxLightCount = allocateLights( lights ); + var maxShadows = allocateShadows( lights ); + var maxBones = allocateBones( object ); - }; + var parameters = { - function refreshUniformsPhong ( uniforms, material ) { + precision: _precision, + supportsVertexTextures: _supportsVertexTextures, - uniforms.shininess.value = material.shininess; + map: !! material.map, + envMap: !! material.envMap, + envMapMode: material.envMap && material.envMap.mapping, + lightMap: !! material.lightMap, + bumpMap: !! material.bumpMap, + normalMap: !! material.normalMap, + specularMap: !! material.specularMap, + alphaMap: !! material.alphaMap, - if ( _this.gammaInput ) { + combine: material.combine, - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - uniforms.specular.value.copyGammaToLinear( material.specular ); + vertexColors: material.vertexColors, - } else { + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; + flatShading: material.shading === THREE.FlatShading, - } + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: _logarithmicDepthBuffer, - if ( material.wrapAround ) { + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture, - uniforms.wrapRGB.value.copy( material.wrapRGB ); + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: _this.maxMorphTargets, + maxMorphNormals: _this.maxMorphNormals, - } + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, - }; + maxShadows: maxShadows, + shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, + shadowMapType: _this.shadowMapType, + shadowMapDebug: _this.shadowMapDebug, + shadowMapCascade: _this.shadowMapCascade, - function refreshUniformsLambert ( uniforms, material ) { + alphaTest: material.alphaTest, + metal: material.metal, + wrapAround: material.wrapAround, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide - if ( _this.gammaInput ) { + }; - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); + // Generate code - } else { + var chunks = []; - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; + if ( shaderID ) { - } + chunks.push( shaderID ); - if ( material.wrapAround ) { + } else { - uniforms.wrapRGB.value.copy( material.wrapRGB ); + chunks.push( material.fragmentShader ); + chunks.push( material.vertexShader ); } - }; + if ( material.defines !== undefined ) { - function refreshUniformsLights ( uniforms, lights ) { + for ( var name in material.defines ) { - uniforms.ambientLightColor.value = lights.ambient; + chunks.push( name ); + chunks.push( material.defines[ name ] ); - uniforms.directionalLightColor.value = lights.directional.colors; - uniforms.directionalLightDirection.value = lights.directional.positions; + } - uniforms.pointLightColor.value = lights.point.colors; - uniforms.pointLightPosition.value = lights.point.positions; - uniforms.pointLightDistance.value = lights.point.distances; + } - uniforms.spotLightColor.value = lights.spot.colors; - uniforms.spotLightPosition.value = lights.spot.positions; - uniforms.spotLightDistance.value = lights.spot.distances; - uniforms.spotLightDirection.value = lights.spot.directions; - uniforms.spotLightAngleCos.value = lights.spot.anglesCos; - uniforms.spotLightExponent.value = lights.spot.exponents; + for ( var name in parameters ) { - uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; - uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; - uniforms.hemisphereLightDirection.value = lights.hemi.positions; + chunks.push( name ); + chunks.push( parameters[ name ] ); - }; + } - function refreshUniformsShadow ( uniforms, lights ) { + var code = chunks.join(); - if ( uniforms.shadowMatrix ) { + var program; - var j = 0; + // Check if code has been already compiled - for ( var i = 0, il = lights.length; i < il; i ++ ) { + for ( var p = 0, pl = _programs.length; p < pl; p ++ ) { - var light = lights[ i ]; + var programInfo = _programs[ p ]; - if ( ! light.castShadow ) continue; + if ( programInfo.code === code ) { - if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { + program = programInfo; + program.usedTimes ++; - uniforms.shadowMap.value[ j ] = light.shadowMap; - uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + break; - uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + } - uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; - uniforms.shadowBias.value[ j ] = light.shadowBias; + } - j ++; + if ( program === undefined ) { - } + program = new THREE.WebGLProgram( _this, code, material, parameters ); + _programs.push( program ); - } + _this.info.memory.programs = _programs.length; } - }; - - // Uniforms (load to GPU) + material.program = program; - function loadUniformsMatrices ( uniforms, object ) { + var attributes = program.attributes; - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); + if ( material.morphTargets ) { - if ( uniforms.normalMatrix ) { + material.numSupportedMorphTargets = 0; - _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); + var id, base = 'morphTarget'; - } + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - }; + id = base + i; - function getTextureUnit() { + if ( attributes[ id ] >= 0 ) { - var textureUnit = _usedTextureUnits; + material.numSupportedMorphTargets ++; - if ( textureUnit >= _maxTextures ) { + } - console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + } } - _usedTextureUnits += 1; + if ( material.morphNormals ) { - return textureUnit; + material.numSupportedMorphNormals = 0; - }; + var id, base = 'morphNormal'; + + for ( i = 0; i < _this.maxMorphNormals; i ++ ) { + + id = base + i; - function loadUniformsGeneric ( program, uniforms ) { + if ( attributes[ id ] >= 0 ) { - var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; + material.numSupportedMorphNormals ++; - for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { + } - location = program.uniforms[ uniforms[ j ][ 1 ] ]; - if ( !location ) continue; + } - uniform = uniforms[ j ][ 0 ]; + } - type = uniform.type; - value = uniform.value; + material.uniformsList = []; - if ( type === "i" ) { // single integer + for ( var u in material.__webglShader.uniforms ) { - _gl.uniform1i( location, value ); + var location = material.program.uniforms[ u ]; - } else if ( type === "f" ) { // single float + if ( location ) { + material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] ); + } - _gl.uniform1f( location, value ); + } - } else if ( type === "v2" ) { // single THREE.Vector2 + } - _gl.uniform2f( location, value.x, value.y ); + function setMaterial( material ) { - } else if ( type === "v3" ) { // single THREE.Vector3 + if ( material.transparent === true ) { - _gl.uniform3f( location, value.x, value.y, value.z ); + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - } else if ( type === "v4" ) { // single THREE.Vector4 + } else { - _gl.uniform4f( location, value.x, value.y, value.z, value.w ); + state.setBlending( THREE.NoBlending ); - } else if ( type === "c" ) { // single THREE.Color + } - _gl.uniform3f( location, value.r, value.g, value.b ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) + } - _gl.uniform1iv( location, value ); + function setProgram( camera, lights, fog, material, object ) { - } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) + _usedTextureUnits = 0; - _gl.uniform3iv( location, value ); + if ( material.needsUpdate ) { - } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) + if ( material.program ) deallocateMaterial( material ); - _gl.uniform1fv( location, value ); + initMaterial( material, lights, fog, object ); + material.needsUpdate = false; - } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) + } - _gl.uniform3fv( location, value ); + if ( material.morphTargets ) { - } else if ( type === "v2v" ) { // array of THREE.Vector2 + if ( ! object.__webglMorphTargetInfluences ) { - if ( uniform._array === undefined ) { + object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); - uniform._array = new Float32Array( 2 * value.length ); + } - } + } - for ( i = 0, il = value.length; i < il; i ++ ) { + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; - offset = i * 2; + var program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.__webglShader.uniforms; - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; + if ( program.id !== _currentProgram ) { - } + _gl.useProgram( program.program ); + _currentProgram = program.id; - _gl.uniform2fv( location, uniform._array ); + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - } else if ( type === "v3v" ) { // array of THREE.Vector3 + } - if ( uniform._array === undefined ) { + if ( material.id !== _currentMaterialId ) { - uniform._array = new Float32Array( 3 * value.length ); + if ( _currentMaterialId === -1 ) refreshLights = true; + _currentMaterialId = material.id; - } + refreshMaterial = true; - for ( i = 0, il = value.length; i < il; i ++ ) { + } - offset = i * 3; + if ( refreshProgram || camera !== _currentCamera ) { - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - } + if ( _logarithmicDepthBuffer ) { - _gl.uniform3fv( location, uniform._array ); + _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - } else if ( type === "v4v" ) { // array of THREE.Vector4 + } - if ( uniform._array === undefined ) { - uniform._array = new Float32Array( 4 * value.length ); + if ( camera !== _currentCamera ) _currentCamera = camera; - } + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - for ( i = 0, il = value.length; i < il; i ++ ) { + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material.envMap ) { - offset = i * 4; + if ( p_uniforms.cameraPosition !== null ) { - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - uniform._array[ offset + 3 ] = value[ i ].w; + _vector3.setFromMatrixPosition( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); } - _gl.uniform4fv( location, uniform._array ); + } - } else if ( type === "m4") { // single THREE.Matrix4 + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { - if ( uniform._array === undefined ) { + if ( p_uniforms.viewMatrix !== null ) { - uniform._array = new Float32Array( 16 ); + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); } - value.flattenToArray( uniform._array ); - _gl.uniformMatrix4fv( location, false, uniform._array ); + } + + } - } else if ( type === "m4v" ) { // array of THREE.Matrix4 + // skinning uniforms must be set even if material didn't change + // auto-setting of texture unit for bone texture must go before other textures + // not sure why, but otherwise weird things happen - if ( uniform._array === undefined ) { + if ( material.skinning ) { - uniform._array = new Float32Array( 16 * value.length ); + if ( object.bindMatrix && p_uniforms.bindMatrix !== null ) { - } + _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); - for ( i = 0, il = value.length; i < il; i ++ ) { + } - value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); + if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null ) { - } + _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); - _gl.uniformMatrix4fv( location, false, uniform._array ); + } - } else if ( type === "t" ) { // single THREE.Texture (2d or cube) + if ( _supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture ) { - texture = value; - textureUnit = getTextureUnit(); + if ( p_uniforms.boneTexture !== null ) { - _gl.uniform1i( location, textureUnit ); + var textureUnit = getTextureUnit(); - if ( !texture ) continue; + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.skeleton.boneTexture, textureUnit ); - if ( texture.image instanceof Array && texture.image.length === 6 ) { + } - setCubeTexture( texture, textureUnit ); + if ( p_uniforms.boneTextureWidth !== null ) { - } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { + _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); - setCubeTextureDynamic( texture, textureUnit ); + } - } else { + if ( p_uniforms.boneTextureHeight !== null ) { - _this.setTexture( texture, textureUnit ); + _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); } - } else if ( type === "tv" ) { // array of THREE.Texture (2d) + } else if ( object.skeleton && object.skeleton.boneMatrices ) { - if ( uniform._array === undefined ) { + if ( p_uniforms.boneGlobalMatrices !== null ) { - uniform._array = []; + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices ); } - for( i = 0, il = uniform.value.length; i < il; i ++ ) { + } + + } - uniform._array[ i ] = getTextureUnit(); + if ( refreshMaterial ) { - } + // refresh uniforms common to several materials - _gl.uniform1iv( location, uniform._array ); + if ( fog && material.fog ) { - for( i = 0, il = uniform.value.length; i < il; i ++ ) { + refreshUniformsFog( m_uniforms, fog ); - texture = uniform.value[ i ]; - textureUnit = uniform._array[ i ]; + } - if ( !texture ) continue; + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material.lights ) { - _this.setTexture( texture, textureUnit ); + if ( _lightsNeedUpdate ) { + refreshLights = true; + setupLights( lights ); + _lightsNeedUpdate = false; } - } else { - - console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + if ( refreshLights ) { + refreshUniformsLights( m_uniforms, _lights ); + markUniformsLightsNeedsUpdate( m_uniforms, true ); + } else { + markUniformsLightsNeedsUpdate( m_uniforms, false ); + } } - } + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhongMaterial ) { - }; + refreshUniformsCommon( m_uniforms, material ); - function setupMatrices ( object, camera ) { + } - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); + // refresh single material specific uniforms - }; + if ( material instanceof THREE.LineBasicMaterial ) { - // + refreshUniformsLine( m_uniforms, material ); - function setColorGamma( array, offset, color, intensitySq ) { + } else if ( material instanceof THREE.LineDashedMaterial ) { - array[ offset ] = color.r * color.r * intensitySq; - array[ offset + 1 ] = color.g * color.g * intensitySq; - array[ offset + 2 ] = color.b * color.b * intensitySq; + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); - }; + } else if ( material instanceof THREE.PointCloudMaterial ) { - function setColorLinear( array, offset, color, intensity ) { + refreshUniformsParticle( m_uniforms, material ); - array[ offset ] = color.r * intensity; - array[ offset + 1 ] = color.g * intensity; - array[ offset + 2 ] = color.b * intensity; + } else if ( material instanceof THREE.MeshPhongMaterial ) { - }; + refreshUniformsPhong( m_uniforms, material ); - function setupLights ( program, lights ) { + } else if ( material instanceof THREE.MeshLambertMaterial ) { - var l, ll, light, n, - r = 0, g = 0, b = 0, - color, skyColor, groundColor, - intensity, intensitySq, - position, - distance, + refreshUniformsLambert( m_uniforms, material ); - zlights = _lights, + } else if ( material instanceof THREE.MeshDepthMaterial ) { - dirColors = zlights.directional.colors, - dirPositions = zlights.directional.positions, + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; - pointColors = zlights.point.colors, - pointPositions = zlights.point.positions, - pointDistances = zlights.point.distances, + } else if ( material instanceof THREE.MeshNormalMaterial ) { - spotColors = zlights.spot.colors, - spotPositions = zlights.spot.positions, - spotDistances = zlights.spot.distances, - spotDirections = zlights.spot.directions, - spotAnglesCos = zlights.spot.anglesCos, - spotExponents = zlights.spot.exponents, + m_uniforms.opacity.value = material.opacity; + + } - hemiSkyColors = zlights.hemi.skyColors, - hemiGroundColors = zlights.hemi.groundColors, - hemiPositions = zlights.hemi.positions, + if ( object.receiveShadow && ! material._shadowPass ) { - dirLength = 0, - pointLength = 0, - spotLength = 0, - hemiLength = 0, + refreshUniformsShadow( m_uniforms, lights ); - dirCount = 0, - pointCount = 0, - spotCount = 0, - hemiCount = 0, + } - dirOffset = 0, - pointOffset = 0, - spotOffset = 0, - hemiOffset = 0; + // load common uniforms - for ( l = 0, ll = lights.length; l < ll; l ++ ) { + loadUniformsGeneric( material.uniformsList ); - light = lights[ l ]; + } - if ( light.onlyShadow ) continue; + loadUniformsMatrices( p_uniforms, object ); - color = light.color; - intensity = light.intensity; - distance = light.distance; + if ( p_uniforms.modelMatrix !== null ) { - if ( light instanceof THREE.AmbientLight ) { + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); - if ( ! light.visible ) continue; + } - if ( _this.gammaInput ) { + return program; - r += color.r * color.r; - g += color.g * color.g; - b += color.b * color.b; + } - } else { + // Uniforms (refresh uniforms objects) - r += color.r; - g += color.g; - b += color.b; + function refreshUniformsCommon ( uniforms, material ) { - } + uniforms.opacity.value = material.opacity; - } else if ( light instanceof THREE.DirectionalLight ) { + uniforms.diffuse.value = material.color; - dirCount += 1; + uniforms.map.value = material.map; + uniforms.lightMap.value = material.lightMap; + uniforms.specularMap.value = material.specularMap; + uniforms.alphaMap.value = material.alphaMap; - if ( ! light.visible ) continue; + if ( material.bumpMap ) { - _direction.getPositionFromMatrix( light.matrixWorld ); - _vector3.getPositionFromMatrix( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) + } - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + if ( material.normalMap ) { - dirOffset = dirLength * 3; + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); - dirPositions[ dirOffset ] = _direction.x; - dirPositions[ dirOffset + 1 ] = _direction.y; - dirPositions[ dirOffset + 2 ] = _direction.z; + } - if ( _this.gammaInput ) { + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map - setColorGamma( dirColors, dirOffset, color, intensity * intensity ); + var uvScaleMap; - } else { + if ( material.map ) { - setColorLinear( dirColors, dirOffset, color, intensity ); + uvScaleMap = material.map; - } + } else if ( material.specularMap ) { - dirLength += 1; + uvScaleMap = material.specularMap; - } else if ( light instanceof THREE.PointLight ) { + } else if ( material.normalMap ) { - pointCount += 1; + uvScaleMap = material.normalMap; - if ( ! light.visible ) continue; + } else if ( material.bumpMap ) { - pointOffset = pointLength * 3; + uvScaleMap = material.bumpMap; - if ( _this.gammaInput ) { + } else if ( material.alphaMap ) { - setColorGamma( pointColors, pointOffset, color, intensity * intensity ); + uvScaleMap = material.alphaMap; - } else { + } - setColorLinear( pointColors, pointOffset, color, intensity ); + if ( uvScaleMap !== undefined ) { - } + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; - _vector3.getPositionFromMatrix( light.matrixWorld ); + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - pointPositions[ pointOffset ] = _vector3.x; - pointPositions[ pointOffset + 1 ] = _vector3.y; - pointPositions[ pointOffset + 2 ] = _vector3.z; + } - pointDistances[ pointLength ] = distance; + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - pointLength += 1; + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; - } else if ( light instanceof THREE.SpotLight ) { + } - spotCount += 1; + function refreshUniformsLine ( uniforms, material ) { - if ( ! light.visible ) continue; + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; - spotOffset = spotLength * 3; + } - if ( _this.gammaInput ) { + function refreshUniformsDash ( uniforms, material ) { - setColorGamma( spotColors, spotOffset, color, intensity * intensity ); + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; - } else { + } - setColorLinear( spotColors, spotOffset, color, intensity ); + function refreshUniformsParticle ( uniforms, material ) { - } + uniforms.psColor.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size; + uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. - _vector3.getPositionFromMatrix( light.matrixWorld ); + uniforms.map.value = material.map; - spotPositions[ spotOffset ] = _vector3.x; - spotPositions[ spotOffset + 1 ] = _vector3.y; - spotPositions[ spotOffset + 2 ] = _vector3.z; + if ( material.map !== null ) { - spotDistances[ spotLength ] = distance; + var offset = material.map.offset; + var repeat = material.map.repeat; - _direction.copy( _vector3 ); - _vector3.getPositionFromMatrix( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - spotDirections[ spotOffset ] = _direction.x; - spotDirections[ spotOffset + 1 ] = _direction.y; - spotDirections[ spotOffset + 2 ] = _direction.z; + } - spotAnglesCos[ spotLength ] = Math.cos( light.angle ); - spotExponents[ spotLength ] = light.exponent; + } - spotLength += 1; + function refreshUniformsFog ( uniforms, fog ) { - } else if ( light instanceof THREE.HemisphereLight ) { + uniforms.fogColor.value = fog.color; - hemiCount += 1; + if ( fog instanceof THREE.Fog ) { - if ( ! light.visible ) continue; + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - _direction.getPositionFromMatrix( light.matrixWorld ); - _direction.normalize(); + } else if ( fog instanceof THREE.FogExp2 ) { - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) + uniforms.fogDensity.value = fog.density; - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + } - hemiOffset = hemiLength * 3; + } - hemiPositions[ hemiOffset ] = _direction.x; - hemiPositions[ hemiOffset + 1 ] = _direction.y; - hemiPositions[ hemiOffset + 2 ] = _direction.z; + function refreshUniformsPhong ( uniforms, material ) { - skyColor = light.color; - groundColor = light.groundColor; + uniforms.shininess.value = material.shininess; + + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; - if ( _this.gammaInput ) { + if ( material.wrapAround ) { - intensitySq = intensity * intensity; + uniforms.wrapRGB.value.copy( material.wrapRGB ); - setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); - setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); + } - } else { + } - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + function refreshUniformsLambert ( uniforms, material ) { - } + uniforms.emissive.value = material.emissive; - hemiLength += 1; + if ( material.wrapAround ) { - } + uniforms.wrapRGB.value.copy( material.wrapRGB ); } - // null eventual remains from removed lights - // (this is to avoid if in shader) + } - for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; - for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; - for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + function refreshUniformsLights ( uniforms, lights ) { - zlights.directional.length = dirLength; - zlights.point.length = pointLength; - zlights.spot.length = spotLength; - zlights.hemi.length = hemiLength; + uniforms.ambientLightColor.value = lights.ambient; - zlights.ambient[ 0 ] = r; - zlights.ambient[ 1 ] = g; - zlights.ambient[ 2 ] = b; + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; - }; + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecay.value = lights.point.decays; - // GL state setting + uniforms.spotLightColor.value = lights.spot.colors; + uniforms.spotLightPosition.value = lights.spot.positions; + uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDirection.value = lights.spot.directions; + uniforms.spotLightAngleCos.value = lights.spot.anglesCos; + uniforms.spotLightExponent.value = lights.spot.exponents; + uniforms.spotLightDecay.value = lights.spot.decays; - this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; - if ( cullFace === THREE.CullFaceNone ) { + } - _gl.disable( _gl.CULL_FACE ); + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - } else { + function markUniformsLightsNeedsUpdate ( uniforms, value ) { - if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { + uniforms.ambientLightColor.needsUpdate = value; - _gl.frontFace( _gl.CW ); + uniforms.directionalLightColor.needsUpdate = value; + uniforms.directionalLightDirection.needsUpdate = value; - } else { + uniforms.pointLightColor.needsUpdate = value; + uniforms.pointLightPosition.needsUpdate = value; + uniforms.pointLightDistance.needsUpdate = value; + uniforms.pointLightDecay.needsUpdate = value; - _gl.frontFace( _gl.CCW ); + uniforms.spotLightColor.needsUpdate = value; + uniforms.spotLightPosition.needsUpdate = value; + uniforms.spotLightDistance.needsUpdate = value; + uniforms.spotLightDirection.needsUpdate = value; + uniforms.spotLightAngleCos.needsUpdate = value; + uniforms.spotLightExponent.needsUpdate = value; + uniforms.spotLightDecay.needsUpdate = value; - } + uniforms.hemisphereLightSkyColor.needsUpdate = value; + uniforms.hemisphereLightGroundColor.needsUpdate = value; + uniforms.hemisphereLightDirection.needsUpdate = value; - if ( cullFace === THREE.CullFaceBack ) { + } - _gl.cullFace( _gl.BACK ); + function refreshUniformsShadow ( uniforms, lights ) { - } else if ( cullFace === THREE.CullFaceFront ) { + if ( uniforms.shadowMatrix ) { - _gl.cullFace( _gl.FRONT ); + var j = 0; - } else { + for ( var i = 0, il = lights.length; i < il; i ++ ) { - _gl.cullFace( _gl.FRONT_AND_BACK ); + var light = lights[ i ]; - } + if ( ! light.castShadow ) continue; - _gl.enable( _gl.CULL_FACE ); + if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { - } + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; - }; + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; - this.setMaterialFaces = function ( material ) { + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; + uniforms.shadowBias.value[ j ] = light.shadowBias; - var doubleSided = material.side === THREE.DoubleSide; - var flipSided = material.side === THREE.BackSide; + j ++; - if ( _oldDoubleSided !== doubleSided ) { + } - if ( doubleSided ) { + } - _gl.disable( _gl.CULL_FACE ); + } - } else { + } - _gl.enable( _gl.CULL_FACE ); + // Uniforms (load to GPU) - } + function loadUniformsMatrices ( uniforms, object ) { - _oldDoubleSided = doubleSided; + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); - } + if ( uniforms.normalMatrix ) { - if ( _oldFlipSided !== flipSided ) { + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); - if ( flipSided ) { + } - _gl.frontFace( _gl.CW ); + } - } else { + function getTextureUnit() { - _gl.frontFace( _gl.CCW ); + var textureUnit = _usedTextureUnits; - } + if ( textureUnit >= _maxTextures ) { - _oldFlipSided = flipSided; + THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); } - }; + _usedTextureUnits += 1; + + return textureUnit; + + } - this.setDepthTest = function ( depthTest ) { + function loadUniformsGeneric ( uniforms ) { - if ( _oldDepthTest !== depthTest ) { + var texture, textureUnit, offset; - if ( depthTest ) { + for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { - _gl.enable( _gl.DEPTH_TEST ); + var uniform = uniforms[ j ][ 0 ]; - } else { + // needsUpdate property is not added to all uniforms. + if ( uniform.needsUpdate === false ) continue; - _gl.disable( _gl.DEPTH_TEST ); + var type = uniform.type; + var value = uniform.value; + var location = uniforms[ j ][ 1 ]; - } + switch ( type ) { - _oldDepthTest = depthTest; + case '1i': + _gl.uniform1i( location, value ); + break; - } + case '1f': + _gl.uniform1f( location, value ); + break; - }; + case '2f': + _gl.uniform2f( location, value[ 0 ], value[ 1 ] ); + break; - this.setDepthWrite = function ( depthWrite ) { + case '3f': + _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); + break; - if ( _oldDepthWrite !== depthWrite ) { + case '4f': + _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); + break; - _gl.depthMask( depthWrite ); - _oldDepthWrite = depthWrite; + case '1iv': + _gl.uniform1iv( location, value ); + break; - } + case '3iv': + _gl.uniform3iv( location, value ); + break; - }; + case '1fv': + _gl.uniform1fv( location, value ); + break; - function setLineWidth ( width ) { + case '2fv': + _gl.uniform2fv( location, value ); + break; - if ( width !== _oldLineWidth ) { + case '3fv': + _gl.uniform3fv( location, value ); + break; - _gl.lineWidth( width ); + case '4fv': + _gl.uniform4fv( location, value ); + break; - _oldLineWidth = width; + case 'Matrix3fv': + _gl.uniformMatrix3fv( location, false, value ); + break; - } + case 'Matrix4fv': + _gl.uniformMatrix4fv( location, false, value ); + break; - }; + // - function setPolygonOffset ( polygonoffset, factor, units ) { + case 'i': - if ( _oldPolygonOffset !== polygonoffset ) { + // single integer + _gl.uniform1i( location, value ); - if ( polygonoffset ) { + break; - _gl.enable( _gl.POLYGON_OFFSET_FILL ); + case 'f': - } else { + // single float + _gl.uniform1f( location, value ); - _gl.disable( _gl.POLYGON_OFFSET_FILL ); + break; - } + case 'v2': - _oldPolygonOffset = polygonoffset; + // single THREE.Vector2 + _gl.uniform2f( location, value.x, value.y ); - } + break; - if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { + case 'v3': - _gl.polygonOffset( factor, units ); + // single THREE.Vector3 + _gl.uniform3f( location, value.x, value.y, value.z ); - _oldPolygonOffsetFactor = factor; - _oldPolygonOffsetUnits = units; + break; - } + case 'v4': - }; + // single THREE.Vector4 + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); - this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { + break; - if ( blending !== _oldBlending ) { + case 'c': - if ( blending === THREE.NoBlending ) { + // single THREE.Color + _gl.uniform3f( location, value.r, value.g, value.b ); - _gl.disable( _gl.BLEND ); + break; - } else if ( blending === THREE.AdditiveBlending ) { + case 'iv1': - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); + // flat array of integers (JS or typed array) + _gl.uniform1iv( location, value ); - } else if ( blending === THREE.SubtractiveBlending ) { + break; - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); + case 'iv': - } else if ( blending === THREE.MultiplyBlending ) { + // flat array of integers with 3 x N size (JS or typed array) + _gl.uniform3iv( location, value ); - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); + break; - } else if ( blending === THREE.CustomBlending ) { + case 'fv1': - _gl.enable( _gl.BLEND ); + // flat array of floats (JS or typed array) + _gl.uniform1fv( location, value ); - } else { + break; - _gl.enable( _gl.BLEND ); - _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD ); - _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); + case 'fv': - } + // flat array of floats with 3 x N size (JS or typed array) + _gl.uniform3fv( location, value ); - _oldBlending = blending; + break; - } + case 'v2v': - if ( blending === THREE.CustomBlending ) { + // array of THREE.Vector2 - if ( blendEquation !== _oldBlendEquation ) { + if ( uniform._array === undefined ) { - _gl.blendEquation( paramThreeToGL( blendEquation ) ); + uniform._array = new Float32Array( 2 * value.length ); - _oldBlendEquation = blendEquation; + } - } + for ( var i = 0, il = value.length; i < il; i ++ ) { - if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { + offset = i * 2; - _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; - _oldBlendSrc = blendSrc; - _oldBlendDst = blendDst; + } - } + _gl.uniform2fv( location, uniform._array ); - } else { + break; - _oldBlendEquation = null; - _oldBlendSrc = null; - _oldBlendDst = null; + case 'v3v': - } + // array of THREE.Vector3 - }; + if ( uniform._array === undefined ) { - // Defines + uniform._array = new Float32Array( 3 * value.length ); - function generateDefines ( defines ) { + } - var value, chunk, chunks = []; + for ( var i = 0, il = value.length; i < il; i ++ ) { - for ( var d in defines ) { + offset = i * 3; - value = defines[ d ]; - if ( value === false ) continue; + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; - chunk = "#define " + d + " " + value; - chunks.push( chunk ); + } - } + _gl.uniform3fv( location, uniform._array ); - return chunks.join( "\n" ); + break; - }; + case 'v4v': - // Shaders + // array of THREE.Vector4 - function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) { + if ( uniform._array === undefined ) { - var p, pl, d, program, code; - var chunks = []; + uniform._array = new Float32Array( 4 * value.length ); - // Generate code + } - if ( shaderID ) { + for ( var i = 0, il = value.length; i < il; i ++ ) { - chunks.push( shaderID ); + offset = i * 4; - } else { + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + uniform._array[ offset + 3 ] = value[ i ].w; - chunks.push( fragmentShader ); - chunks.push( vertexShader ); + } - } + _gl.uniform4fv( location, uniform._array ); - for ( d in defines ) { + break; - chunks.push( d ); - chunks.push( defines[ d ] ); + case 'm3': - } + // single THREE.Matrix3 + _gl.uniformMatrix3fv( location, false, value.elements ); - for ( p in parameters ) { + break; - chunks.push( p ); - chunks.push( parameters[ p ] ); + case 'm3v': - } + // array of THREE.Matrix3 - code = chunks.join(); + if ( uniform._array === undefined ) { - // Check if code has been already compiled + uniform._array = new Float32Array( 9 * value.length ); - for ( p = 0, pl = _programs.length; p < pl; p ++ ) { + } - var programInfo = _programs[ p ]; + for ( var i = 0, il = value.length; i < il; i ++ ) { - if ( programInfo.code === code ) { + value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); - // console.log( "Code already compiled." /*: \n\n" + code*/ ); + } - programInfo.usedTimes ++; + _gl.uniformMatrix3fv( location, false, uniform._array ); - return programInfo.program; + break; - } + case 'm4': - } + // single THREE.Matrix4 + _gl.uniformMatrix4fv( location, false, value.elements ); - var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; + break; - if ( parameters.shadowMapType === THREE.PCFShadowMap ) { + case 'm4v': - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; + // array of THREE.Matrix4 - } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { + if ( uniform._array === undefined ) { - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; + uniform._array = new Float32Array( 16 * value.length ); - } + } - // console.log( "building new program " ); + for ( var i = 0, il = value.length; i < il; i ++ ) { - // + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); - var customDefines = generateDefines( defines ); + } - // + _gl.uniformMatrix4fv( location, false, uniform._array ); - program = _gl.createProgram(); + break; - var prefix_vertex = [ + case 't': - "precision " + _precision + " float;", - "precision " + _precision + " int;", + // single THREE.Texture (2d or cube) - customDefines, + texture = value; + textureUnit = getTextureUnit(); - _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", + _gl.uniform1i( location, textureUnit ); - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", - _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "", + if ( ! texture ) continue; - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + if ( texture instanceof THREE.CubeTexture || + ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ - "#define MAX_SHADOWS " + parameters.maxShadows, + setCubeTexture( texture, textureUnit ); - "#define MAX_BONES " + parameters.maxBones, + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - parameters.map ? "#define USE_MAP" : "", - parameters.envMap ? "#define USE_ENVMAP" : "", - parameters.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", + setCubeTextureDynamic( texture, textureUnit ); - parameters.skinning ? "#define USE_SKINNING" : "", - parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", + } else { - parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", - parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", - parameters.perPixel ? "#define PHONG_PER_PIXEL" : "", - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", + _this.setTexture( texture, textureUnit ); - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + } - parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", + break; - "uniform mat4 modelMatrix;", - "uniform mat4 modelViewMatrix;", - "uniform mat4 projectionMatrix;", - "uniform mat4 viewMatrix;", - "uniform mat3 normalMatrix;", - "uniform vec3 cameraPosition;", + case 'tv': - "attribute vec3 position;", - "attribute vec3 normal;", - "attribute vec2 uv;", - "attribute vec2 uv2;", + // array of THREE.Texture (2d) - "#ifdef USE_COLOR", + if ( uniform._array === undefined ) { - "attribute vec3 color;", + uniform._array = []; - "#endif", + } - "#ifdef USE_MORPHTARGETS", + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - "attribute vec3 morphTarget0;", - "attribute vec3 morphTarget1;", - "attribute vec3 morphTarget2;", - "attribute vec3 morphTarget3;", + uniform._array[ i ] = getTextureUnit(); - "#ifdef USE_MORPHNORMALS", + } - "attribute vec3 morphNormal0;", - "attribute vec3 morphNormal1;", - "attribute vec3 morphNormal2;", - "attribute vec3 morphNormal3;", + _gl.uniform1iv( location, uniform._array ); - "#else", + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - "attribute vec3 morphTarget4;", - "attribute vec3 morphTarget5;", - "attribute vec3 morphTarget6;", - "attribute vec3 morphTarget7;", + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; - "#endif", + if ( ! texture ) continue; - "#endif", + _this.setTexture( texture, textureUnit ); - "#ifdef USE_SKINNING", + } - "attribute vec4 skinIndex;", - "attribute vec4 skinWeight;", + break; - "#endif", + default: - "" + THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); - ].join("\n"); + } - var prefix_fragment = [ + } - "precision " + _precision + " float;", - "precision " + _precision + " int;", + } - ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", + function setupMatrices ( object, camera ) { - customDefines, + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + } - "#define MAX_SHADOWS " + parameters.maxShadows, + function setColorLinear( array, offset, color, intensity ) { - parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", + array[ offset ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", - _this.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "", + } - ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "", - ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", + function setupLights ( lights ) { - parameters.map ? "#define USE_MAP" : "", - parameters.envMap ? "#define USE_ENVMAP" : "", - parameters.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", + var l, ll, light, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, + distance, - parameters.metal ? "#define METAL" : "", - parameters.perPixel ? "#define PHONG_PER_PIXEL" : "", - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", + zlights = _lights, - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, - "uniform mat4 viewMatrix;", - "uniform vec3 cameraPosition;", - "" + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + pointDecays = zlights.point.decays, - ].join("\n"); + spotColors = zlights.spot.colors, + spotPositions = zlights.spot.positions, + spotDistances = zlights.spot.distances, + spotDirections = zlights.spot.directions, + spotAnglesCos = zlights.spot.anglesCos, + spotExponents = zlights.spot.exponents, + spotDecays = zlights.spot.decays, - var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader ); - var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader ); + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, - _gl.attachShader( program, glVertexShader ); - _gl.attachShader( program, glFragmentShader ); + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, - //Force a particular attribute to index 0. - // because potentially expensive emulation is done by browser if attribute 0 is disabled. - //And, color, for example is often automatically bound to index 0 so disabling it - if ( index0AttributeName ) { - _gl.bindAttribLocation( program, 0, index0AttributeName ); - } + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, - _gl.linkProgram( program ); + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0; - if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) { + for ( l = 0, ll = lights.length; l < ll; l ++ ) { - console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" ); - console.error( "Program Info Log: " + _gl.getProgramInfoLog( program ) ); - } + light = lights[ l ]; - // clean up + if ( light.onlyShadow ) continue; - _gl.deleteShader( glFragmentShader ); - _gl.deleteShader( glVertexShader ); + color = light.color; + intensity = light.intensity; + distance = light.distance; - // console.log( prefix_fragment + fragmentShader ); - // console.log( prefix_vertex + vertexShader ); + if ( light instanceof THREE.AmbientLight ) { - program.uniforms = {}; - program.attributes = {}; + if ( ! light.visible ) continue; - var identifiers, u, a, i; + r += color.r; + g += color.g; + b += color.b; - // cache uniform locations + } else if ( light instanceof THREE.DirectionalLight ) { - identifiers = [ + dirCount += 1; - 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', - 'morphTargetInfluences' + if ( ! light.visible ) continue; - ]; + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); - if ( parameters.useVertexTexture ) { + dirOffset = dirLength * 3; - identifiers.push( 'boneTexture' ); - identifiers.push( 'boneTextureWidth' ); - identifiers.push( 'boneTextureHeight' ); + dirPositions[ dirOffset ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; - } else { + setColorLinear( dirColors, dirOffset, color, intensity ); - identifiers.push( 'boneGlobalMatrices' ); + dirLength += 1; - } + } else if ( light instanceof THREE.PointLight ) { - for ( u in uniforms ) { + pointCount += 1; - identifiers.push( u ); + if ( ! light.visible ) continue; - } + pointOffset = pointLength * 3; - cacheUniformLocations( program, identifiers ); + setColorLinear( pointColors, pointOffset, color, intensity ); - // cache attributes locations + _vector3.setFromMatrixPosition( light.matrixWorld ); - identifiers = [ + pointPositions[ pointOffset ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; - "position", "normal", "uv", "uv2", "tangent", "color", - "skinIndex", "skinWeight", "lineDistance" + // distance is 0 if decay is 0, because there is no attenuation at all. + pointDistances[ pointLength ] = distance; + pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - ]; + pointLength += 1; - for ( i = 0; i < parameters.maxMorphTargets; i ++ ) { + } else if ( light instanceof THREE.SpotLight ) { - identifiers.push( "morphTarget" + i ); + spotCount += 1; - } + if ( ! light.visible ) continue; - for ( i = 0; i < parameters.maxMorphNormals; i ++ ) { + spotOffset = spotLength * 3; - identifiers.push( "morphNormal" + i ); + setColorLinear( spotColors, spotOffset, color, intensity ); - } + _direction.setFromMatrixPosition( light.matrixWorld ); - for ( a in attributes ) { + spotPositions[ spotOffset ] = _direction.x; + spotPositions[ spotOffset + 1 ] = _direction.y; + spotPositions[ spotOffset + 2 ] = _direction.z; - identifiers.push( a ); + spotDistances[ spotLength ] = distance; - } + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); - cacheAttributeLocations( program, identifiers ); + spotDirections[ spotOffset ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; - program.id = _programs_counter ++; + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - _programs.push( { program: program, code: code, usedTimes: 1 } ); + spotLength += 1; - _this.info.memory.programs = _programs.length; + } else if ( light instanceof THREE.HemisphereLight ) { - return program; + hemiCount += 1; - }; + if ( ! light.visible ) continue; - // Shader parameters cache + _direction.setFromMatrixPosition( light.matrixWorld ); + _direction.normalize(); - function cacheUniformLocations ( program, identifiers ) { + hemiOffset = hemiLength * 3; - var i, l, id; + hemiPositions[ hemiOffset ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; - for( i = 0, l = identifiers.length; i < l; i ++ ) { + skyColor = light.color; + groundColor = light.groundColor; - id = identifiers[ i ]; - program.uniforms[ id ] = _gl.getUniformLocation( program, id ); + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - } + hemiLength += 1; - }; + } - function cacheAttributeLocations ( program, identifiers ) { + } - var i, l, id; + // null eventual remains from removed lights + // (this is to avoid if in shader) - for( i = 0, l = identifiers.length; i < l; i ++ ) { + for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; + for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; + for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; - id = identifiers[ i ]; - program.attributes[ id ] = _gl.getAttribLocation( program, id ); + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; - } + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; - }; + } - function addLineNumbers ( string ) { + // GL state setting - var chunks = string.split( "\n" ); + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - for ( var i = 0, il = chunks.length; i < il; i ++ ) { + if ( cullFace === THREE.CullFaceNone ) { - // Chrome reports shader errors on lines - // starting counting from 1 + _gl.disable( _gl.CULL_FACE ); - chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ]; + } else { - } + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { - return chunks.join( "\n" ); + _gl.frontFace( _gl.CW ); - }; + } else { - function getShader ( type, string ) { + _gl.frontFace( _gl.CCW ); - var shader; + } - if ( type === "fragment" ) { + if ( cullFace === THREE.CullFaceBack ) { - shader = _gl.createShader( _gl.FRAGMENT_SHADER ); + _gl.cullFace( _gl.BACK ); - } else if ( type === "vertex" ) { + } else if ( cullFace === THREE.CullFaceFront ) { - shader = _gl.createShader( _gl.VERTEX_SHADER ); + _gl.cullFace( _gl.FRONT ); - } + } else { - _gl.shaderSource( shader, string ); - _gl.compileShader( shader ); + _gl.cullFace( _gl.FRONT_AND_BACK ); - if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { + } - console.error( _gl.getShaderInfoLog( shader ) ); - console.error( addLineNumbers( string ) ); - return null; + _gl.enable( _gl.CULL_FACE ); } - return shader; - }; - // Textures - - - function isPowerOfTwo ( value ) { + this.setMaterialFaces = function ( material ) { - return ( value & ( value - 1 ) ) === 0; + state.setDoubleSided( material.side === THREE.DoubleSide ); + state.setFlipSided( material.side === THREE.BackSide ); }; + // Textures + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { + var extension; + if ( isImagePowerOfTwo ) { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); @@ -25434,126 +23266,161 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { + + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); + + } + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { + + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); + + } + } - if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { + extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + + if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) { - if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) { - _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); - texture.__oldAnisotropy = texture.anisotropy; + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); + texture.__currentAnisotropy = texture.anisotropy; } } - }; + } - this.setTexture = function ( texture, slot ) { + this.uploadTexture = function ( texture ) { - if ( texture.needsUpdate ) { + if ( texture.__webglInit === undefined ) { - if ( ! texture.__webglInit ) { + texture.__webglInit = true; - texture.__webglInit = true; + texture.addEventListener( 'dispose', onTextureDispose ); - texture.addEventListener( 'dispose', onTextureDispose ); + texture.__webglTexture = _gl.createTexture(); - texture.__webglTexture = _gl.createTexture(); + _this.info.memory.textures ++; - _this.info.memory.textures ++; + } - } + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + texture.image = clampToMaxSize( texture.image, _maxTextureSize ); - var image = texture.image, - isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); + var image = texture.image, + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); - setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); - var mipmap, mipmaps = texture.mipmaps; + var mipmap, mipmaps = texture.mipmaps; - if ( texture instanceof THREE.DataTexture ) { + if ( texture instanceof THREE.DataTexture ) { - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } + } - texture.generateMipmaps = false; + texture.generateMipmaps = false; - } else { + } else { - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - } + } - } else if ( texture instanceof THREE.CompressedTexture ) { + } else if ( texture instanceof THREE.CompressedTexture ) { - for( var i = 0, il = mipmaps.length; i < il; i ++ ) { + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { + + if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { - mipmap = mipmaps[ i ]; - if ( texture.format!==THREE.RGBAFormat ) { _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + } else { - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); + } + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + } - } else { // regular Texture (image, video, canvas) + } - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels + } else { // regular Texture (image, video, canvas) - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - texture.generateMipmaps = false; + } - } else { + texture.generateMipmaps = false; - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + } else { - } + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); } - if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + }; + + this.setTexture = function ( texture, slot ) { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); - texture.needsUpdate = false; + if ( texture.needsUpdate ) { - if ( texture.onUpdate ) texture.onUpdate(); + _this.uploadTexture( texture ); } else { - _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); } @@ -25562,27 +23429,27 @@ THREE.WebGLRenderer = function ( parameters ) { function clampToMaxSize ( image, maxSize ) { - if ( image.width <= maxSize && image.height <= maxSize ) { + if ( image.width > maxSize || image.height > maxSize ) { - return image; + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. - } + var scale = maxSize / Math.max( image.width, image.height ); - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. + var canvas = document.createElement( 'canvas' ); + canvas.width = Math.floor( image.width * scale ); + canvas.height = Math.floor( image.height * scale ); - var maxDimension = Math.max( image.width, image.height ); - var newWidth = Math.floor( image.width * maxSize / maxDimension ); - var newHeight = Math.floor( image.height * maxSize / maxDimension ); + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - var canvas = document.createElement( 'canvas' ); - canvas.width = newWidth; - canvas.height = newHeight; + THREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); - var ctx = canvas.getContext( "2d" ); - ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); + return canvas; - return canvas; + } + + return image; } @@ -25608,25 +23475,26 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); var isCompressed = texture instanceof THREE.CompressedTexture; + var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; var cubeImage = []; for ( var i = 0; i < 6; i ++ ) { - if ( _this.autoScaleCubemaps && ! isCompressed ) { + if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); } else { - cubeImage[ i ] = texture.image[ i ]; + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; } } var image = cubeImage[ 0 ], - isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ), + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), glFormat = paramThreeToGL( texture.format ), glType = paramThreeToGL( texture.type ); @@ -25634,27 +23502,48 @@ THREE.WebGLRenderer = function ( parameters ) { for ( var i = 0; i < 6; i ++ ) { - if( !isCompressed ) { + if ( ! isCompressed ) { + + if ( isDataTexture ) { + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + + } else { + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + } } else { var mipmap, mipmaps = cubeImage[ i ].mipmaps; - for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { mipmap = mipmaps[ j ]; - if ( texture.format!==THREE.RGBAFormat ) { - _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { + + if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) { + + _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + + } else { + + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); + + } } else { + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + } } + } + } if ( texture.generateMipmaps && isImagePowerOfTwo ) { @@ -25676,14 +23565,14 @@ THREE.WebGLRenderer = function ( parameters ) { } - }; + } function setCubeTextureDynamic ( texture, slot ) { _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); - }; + } // Render targets @@ -25692,7 +23581,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); - }; + } function setupRenderBuffer ( renderbuffer, renderTarget ) { @@ -25704,7 +23593,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); /* For some reason this is not working. Defaulting to RGBA4. - } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); @@ -25720,13 +23609,13 @@ THREE.WebGLRenderer = function ( parameters ) { } - }; + } this.setRenderTarget = function ( renderTarget ) { var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - if ( renderTarget && ! renderTarget.__webglFramebuffer ) { + if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) { if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; @@ -25739,7 +23628,7 @@ THREE.WebGLRenderer = function ( parameters ) { // Setup texture, create render and frame buffers - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ), + var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), glFormat = paramThreeToGL( renderTarget.format ), glType = paramThreeToGL( renderTarget.type ); @@ -25871,6 +23760,54 @@ THREE.WebGLRenderer = function ( parameters ) { }; + this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { + + if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; + + } + + if ( renderTarget.__webglFramebuffer ) { + + if ( renderTarget.format !== THREE.RGBAFormat ) { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); + return; + + } + + var restore = false; + + if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); + + restore = true; + + } + + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { + + _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); + + } else { + + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + + } + + if ( restore ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); + + } + + } + + }; + function updateRenderTargetMipmap ( renderTarget ) { if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { @@ -25887,7 +23824,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - }; + } // Fallback filters for non-power-of-2 textures @@ -25901,12 +23838,14 @@ THREE.WebGLRenderer = function ( parameters ) { return _gl.LINEAR; - }; + } // Map three.js constants to WebGL constants function paramThreeToGL ( p ) { + var extension; + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; @@ -25931,6 +23870,14 @@ THREE.WebGLRenderer = function ( parameters ) { if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; + extension = extensions.get( 'OES_texture_half_float' ); + + if ( extension !== null ) { + + if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; + + } + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; if ( p === THREE.RGBAFormat ) return _gl.RGBA; @@ -25954,24 +23901,46 @@ THREE.WebGLRenderer = function ( parameters ) { if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; - if ( _glExtensionCompressedTextureS3TC !== undefined ) { + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + + if ( extension !== null ) { + + if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } + + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + + if ( extension !== null ) { + + if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + + } + + extension = extensions.get( 'EXT_blend_minmax' ); + + if ( extension !== null ) { - if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; + if ( p === THREE.MinEquation ) return extension.MIN_EXT; + if ( p === THREE.MaxEquation ) return extension.MAX_EXT; } return 0; - }; + } // Allocations function allocateBones ( object ) { - if ( _supportsBoneTextures && object && object.useVertexTexture ) { + if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { return 1024; @@ -25981,7 +23950,7 @@ THREE.WebGLRenderer = function ( parameters ) { // ( for example when prebuilding shader // to be used with multiple objects ) // - // - leave some extra space for other uniforms + // - leave some extra space for other uniforms // - limit here is ANGLE's 254 max uniform vectors // (up to 54 should be safe) @@ -25992,11 +23961,11 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { - maxBones = Math.min( object.bones.length, maxBones ); + maxBones = Math.min( object.skeleton.bones.length, maxBones ); - if ( maxBones < object.bones.length ) { + if ( maxBones < object.skeleton.bones.length ) { - console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); } @@ -26006,7 +23975,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - }; + } function allocateLights( lights ) { @@ -26019,7 +23988,7 @@ THREE.WebGLRenderer = function ( parameters ) { var light = lights[ l ]; - if ( light.onlyShadow ) continue; + if ( light.onlyShadow || light.visible === false ) continue; if ( light instanceof THREE.DirectionalLight ) dirLights ++; if ( light instanceof THREE.PointLight ) pointLights ++; @@ -26028,15 +23997,15 @@ THREE.WebGLRenderer = function ( parameters ) { } - return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; + return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights }; - }; + } function allocateShadows( lights ) { var maxShadows = 0; - for ( var l = 0, ll = lights.length; l < ll; l++ ) { + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { var light = lights[ l ]; @@ -26049,116 +24018,38 @@ THREE.WebGLRenderer = function ( parameters ) { return maxShadows; - }; - - // Initialization - - function initGL() { - - try { - - var attributes = { - alpha: _alpha, - premultipliedAlpha: _premultipliedAlpha, - antialias: _antialias, - stencil: _stencil, - preserveDrawingBuffer: _preserveDrawingBuffer - }; - - _gl = _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); - - if ( _gl === null ) { - - throw 'Error creating WebGL context.'; - - } - - } catch ( error ) { - - console.error( error ); - - } - - _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); - _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); - _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); - - _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - - _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - - if ( ! _glExtensionTextureFloat ) { - - console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); - - } - - if ( ! _glExtensionStandardDerivatives ) { - - console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); - - } - - if ( ! _glExtensionTextureFilterAnisotropic ) { - - console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); - - } - - if ( ! _glExtensionCompressedTextureS3TC ) { - - console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); - - } - - if ( _gl.getShaderPrecisionFormat === undefined ) { + } - _gl.getShaderPrecisionFormat = function() { + // DEPRECATED - return { - "rangeMin" : 1, - "rangeMax" : 1, - "precision" : 1 - }; + this.initMaterial = function () { - } - } + THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); }; - function setDefaultGLState () { - - _gl.clearColor( 0, 0, 0, 1 ); - _gl.clearDepth( 1 ); - _gl.clearStencil( 0 ); - - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthFunc( _gl.LEQUAL ); + this.addPrePlugin = function () { - _gl.frontFace( _gl.CCW ); - _gl.cullFace( _gl.BACK ); - _gl.enable( _gl.CULL_FACE ); + THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + }; - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + this.addPostPlugin = function () { - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); }; - // default plugins (order is important) + this.updateShadowMap = function () { - this.shadowMapPlugin = new THREE.ShadowMapPlugin(); - this.addPrePlugin( this.shadowMapPlugin ); + THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - this.addPostPlugin( new THREE.SpritePlugin() ); - this.addPostPlugin( new THREE.LensFlarePlugin() ); + }; }; +// File:src/renderers/WebGLRenderTarget.js + /** * @author szimek / https://github.com/szimek/ * @author alteredq / http://alteredqualia.com/ @@ -26190,7 +24081,7 @@ THREE.WebGLRenderTarget = function ( width, height, options ) { this.generateMipmaps = true; - this.shareDepthFrom = null; + this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; }; @@ -26198,6 +24089,13 @@ THREE.WebGLRenderTarget.prototype = { constructor: THREE.WebGLRenderTarget, + setSize: function ( width, height ) { + + this.width = width; + this.height = height; + + }, + clone: function () { var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); @@ -26237,6 +24135,8 @@ THREE.WebGLRenderTarget.prototype = { THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); +// File:src/renderers/WebGLRenderTargetCube.js + /** * @author alteredq / http://alteredqualia.com */ @@ -26245,6705 +24145,6772 @@ THREE.WebGLRenderTargetCube = function ( width, height, options ) { THREE.WebGLRenderTarget.call( this, width, height, options ); - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - -}; - -THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableVertex = function () { - - this.positionWorld = new THREE.Vector3(); - this.positionScreen = new THREE.Vector4(); - - this.visible = true; - -}; - -THREE.RenderableVertex.prototype.copy = function ( vertex ) { - - this.positionWorld.copy( vertex.positionWorld ); - this.positionScreen.copy( vertex.positionScreen ); + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 }; -/** - * @author mrdoob / http://mrdoob.com/ - */ +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); +THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; -THREE.RenderableFace3 = function () { +// File:src/renderers/webgl/WebGLExtensions.js - this.id = 0; +/** +* @author mrdoob / http://mrdoob.com/ +*/ - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - this.v3 = new THREE.RenderableVertex(); +THREE.WebGLExtensions = function ( gl ) { - this.centroidModel = new THREE.Vector3(); + var extensions = {}; - this.normalModel = new THREE.Vector3(); - this.normalModelView = new THREE.Vector3(); + this.get = function ( name ) { - this.vertexNormalsLength = 0; - this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; - this.vertexNormalsModelView = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + if ( extensions[ name ] !== undefined ) { - this.color = null; - this.material = null; - this.uvs = [[]]; + return extensions[ name ]; - this.z = 0; + } -}; + var extension; -/** - * @author mrdoob / http://mrdoob.com/ - */ + switch ( name ) { -THREE.RenderableObject = function () { + case 'EXT_texture_filter_anisotropic': + extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + break; - this.id = 0; + case 'WEBGL_compressed_texture_s3tc': + extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + break; - this.object = null; - this.z = 0; + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; -}; + default: + extension = gl.getExtension( name ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -THREE.RenderableSprite = function () { + if ( extension === null ) { - this.id = 0; + THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - this.object = null; + } - this.x = 0; - this.y = 0; - this.z = 0; + extensions[ name ] = extension; - this.rotation = 0; - this.scale = new THREE.Vector2(); + return extension; - this.material = null; + }; }; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableLine = function () { +// File:src/renderers/webgl/WebGLProgram.js - this.id = 0; +THREE.WebGLProgram = ( function () { - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); + var programIdCount = 0; - this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; - this.material = null; + var generateDefines = function ( defines ) { - this.z = 0; - -}; + var value, chunk, chunks = []; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( var d in defines ) { -THREE.GeometryUtils = { + value = defines[ d ]; + if ( value === false ) continue; - // Merge two geometries or geometry and geometry from object (using object's transform) + chunk = '#define ' + d + ' ' + value; + chunks.push( chunk ); - merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { + } - var matrix, normalMatrix, - vertexOffset = geometry1.vertices.length, - uvPosition = geometry1.faceVertexUvs[ 0 ].length, - geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, - vertices1 = geometry1.vertices, - vertices2 = geometry2.vertices, - faces1 = geometry1.faces, - faces2 = geometry2.faces, - uvs1 = geometry1.faceVertexUvs[ 0 ], - uvs2 = geometry2.faceVertexUvs[ 0 ]; + return chunks.join( '\n' ); - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + }; - if ( object2 instanceof THREE.Mesh ) { + var cacheUniformLocations = function ( gl, program, identifiers ) { - object2.matrixAutoUpdate && object2.updateMatrix(); + var uniforms = {}; - matrix = object2.matrix; + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + var id = identifiers[ i ]; + uniforms[ id ] = gl.getUniformLocation( program, id ); } - // vertices + return uniforms; - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + }; - var vertex = vertices2[ i ]; + var cacheAttributeLocations = function ( gl, program, identifiers ) { - var vertexCopy = vertex.clone(); + var attributes = {}; - if ( matrix ) vertexCopy.applyMatrix4( matrix ); + for ( var i = 0, l = identifiers.length; i < l; i ++ ) { - vertices1.push( vertexCopy ); + var id = identifiers[ i ]; + attributes[ id ] = gl.getAttribLocation( program, id ); } - // faces + return attributes; - for ( i = 0, il = faces2.length; i < il; i ++ ) { + }; - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + return function ( renderer, code, material, parameters ) { - faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); + var _this = renderer; + var _gl = _this.context; - if ( normalMatrix ) { + var defines = material.defines; + var uniforms = material.__webglShader.uniforms; + var attributes = material.attributes; - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + var vertexShader = material.__webglShader.vertexShader; + var fragmentShader = material.__webglShader.fragmentShader; - } + var index0AttributeName = material.index0AttributeName; - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + if ( index0AttributeName === undefined && parameters.morphTargets === true ) { - normal = faceVertexNormals[ j ].clone(); + // programs with morphTargets displace position out of attribute 0 - if ( normalMatrix ) { + index0AttributeName = 'position'; - normal.applyMatrix3( normalMatrix ).normalize(); + } - } + var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - faceCopy.vertexNormals.push( normal ); + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { - } + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - faceCopy.color.copy( face.color ); + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); + } - } + var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; + var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + if ( parameters.envMap ) { - faceCopy.centroid.copy( face.centroid ); + switch ( material.envMap.mapping ) { - if ( matrix ) { + case THREE.CubeReflectionMapping: + case THREE.CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; + + case THREE.EquirectangularReflectionMapping: + case THREE.EquirectangularRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; + break; - faceCopy.centroid.applyMatrix4( matrix ); + case THREE.SphericalReflectionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; + break; } - faces1.push( faceCopy ); + switch ( material.envMap.mapping ) { - } + case THREE.CubeRefractionMapping: + case THREE.EquirectangularRefractionMapping: + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; - // uvs + } - for ( i = 0, il = uvs2.length; i < il; i ++ ) { + switch ( material.combine ) { - var uv = uvs2[ i ], uvCopy = []; + case THREE.MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + case THREE.MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + case THREE.AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; } - uvs1.push( uvCopy ); - } - }, - - // Get random point in triangle (via barycentric coordinates) - // (uniform distribution) - // http://www.cgafaq.info/wiki/Random_Point_In_Triangle - - randomPointInTriangle: function () { + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - var vector = new THREE.Vector3(); - - return function ( vectorA, vectorB, vectorC ) { + // console.log( 'building new program ' ); - var point = new THREE.Vector3(); - - var a = THREE.Math.random16(); - var b = THREE.Math.random16(); + // - if ( ( a + b ) > 1 ) { + var customDefines = generateDefines( defines ); - a = 1 - a; - b = 1 - b; + // - } + var program = _gl.createProgram(); - var c = 1 - a - b; + var prefix_vertex, prefix_fragment; - point.copy( vectorA ); - point.multiplyScalar( a ); + if ( material instanceof THREE.RawShaderMaterial ) { - vector.copy( vectorB ); - vector.multiplyScalar( b ); + prefix_vertex = ''; + prefix_fragment = ''; - point.add( vector ); + } else { - vector.copy( vectorC ); - vector.multiplyScalar( c ); + prefix_vertex = [ - point.add( vector ); + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - return point; + customDefines, - }; + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - }(), + _this.gammaInput ? '#define GAMMA_INPUT' : '', + _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, - // Get random point in face (triangle / quad) - // (uniform distribution) + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - randomPointInFace: function ( face, geometry, useCachedAreas ) { + '#define MAX_SHADOWS ' + parameters.maxShadows, - var vA, vB, vC, vD; + '#define MAX_BONES ' + parameters.maxBones, - vA = geometry.vertices[ face.a ]; - vB = geometry.vertices[ face.b ]; - vC = geometry.vertices[ face.c ]; + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', - return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); + parameters.flatShading ? '#define FLAT_SHADED': '', - }, + parameters.skinning ? '#define USE_SKINNING' : '', + parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', - // Get uniformly distributed random points in mesh - // - create array with cumulative sums of face areas - // - pick random number from 0 to total area - // - find corresponding place in area array by binary search - // - get random point in face + parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', + parameters.morphNormals ? '#define USE_MORPHNORMALS' : '', + parameters.wrapAround ? '#define WRAP_AROUND' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - randomPointsInGeometry: function ( geometry, n ) { + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', - var face, i, - faces = geometry.faces, - vertices = geometry.vertices, - il = faces.length, - totalArea = 0, - cumulativeAreas = [], - vA, vB, vC, vD; + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - // precompute face areas + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + //_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', - for ( i = 0; i < il; i ++ ) { - face = faces[ i ]; + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', - vA = vertices[ face.a ]; - vB = vertices[ face.b ]; - vC = vertices[ face.c ]; + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', + 'attribute vec2 uv2;', - face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); + '#ifdef USE_COLOR', - totalArea += face._area; + ' attribute vec3 color;', - cumulativeAreas[ i ] = totalArea; + '#endif', - } + '#ifdef USE_MORPHTARGETS', - // binary search cumulative areas array + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', - function binarySearchIndices( value ) { + ' #ifdef USE_MORPHNORMALS', - function binarySearch( start, end ) { + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', - // return closest larger index - // if exact number is not found + ' #else', - if ( end < start ) - return start; + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', - var mid = start + Math.floor( ( end - start ) / 2 ); + ' #endif', - if ( cumulativeAreas[ mid ] > value ) { + '#endif', - return binarySearch( start, mid - 1 ); + '#ifdef USE_SKINNING', - } else if ( cumulativeAreas[ mid ] < value ) { + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', - return binarySearch( mid + 1, end ); + '#endif', - } else { + '' - return mid; + ].join( '\n' ); - } + prefix_fragment = [ - } + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - var result = binarySearch( 0, cumulativeAreas.length - 1 ) - return result; + ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', - } + customDefines, - // pick random face weighted by face area + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - var r, index, - result = []; + '#define MAX_SHADOWS ' + parameters.maxShadows, - var stats = {}; + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', - for ( i = 0; i < n; i ++ ) { + _this.gammaInput ? '#define GAMMA_INPUT' : '', + _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, - r = THREE.Math.random16() * totalArea; + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - index = binarySearchIndices( r ); + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapTypeDefine : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.envMap ? '#define ' + envMapBlendingDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', - result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); + parameters.flatShading ? '#define FLAT_SHADED': '', - if ( ! stats[ index ] ) { + parameters.metal ? '#define METAL' : '', + parameters.wrapAround ? '#define WRAP_AROUND' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - stats[ index ] = 1; + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', - } else { + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + //_this._glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', - stats[ index ] += 1; + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', + '' - } + ].join( '\n' ); } - return result; + var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader ); + var glFragmentShader = new THREE.WebGLShader( _gl, _gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader ); - }, + _gl.attachShader( program, glVertexShader ); + _gl.attachShader( program, glFragmentShader ); - // Get triangle area (half of parallelogram) - // http://mathworld.wolfram.com/TriangleArea.html + if ( index0AttributeName !== undefined ) { - triangleArea: function () { + // Force a particular attribute to index 0. + // because potentially expensive emulation is done by browser if attribute 0 is disabled. + // And, color, for example is often automatically bound to index 0 so disabling it - var vector1 = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); + _gl.bindAttribLocation( program, 0, index0AttributeName ); - return function ( vectorA, vectorB, vectorC ) { + } - vector1.subVectors( vectorB, vectorA ); - vector2.subVectors( vectorC, vectorA ); - vector1.cross( vector2 ); + _gl.linkProgram( program ); - return 0.5 * vector1.length(); + var programLogInfo = _gl.getProgramInfoLog( program ); - }; + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - }(), + THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo ); - // Center geometry so that 0,0,0 is in center of bounding box + } - center: function ( geometry ) { + if ( programLogInfo !== '' ) { - geometry.computeBoundingBox(); + THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); - var bb = geometry.boundingBox; + } - var offset = new THREE.Vector3(); + // clean up - offset.addVectors( bb.min, bb.max ); - offset.multiplyScalar( -0.5 ); + _gl.deleteShader( glVertexShader ); + _gl.deleteShader( glFragmentShader ); - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); - geometry.computeBoundingBox(); + // cache uniform locations - return offset; + var identifiers = [ - }, + 'viewMatrix', + 'modelViewMatrix', + 'projectionMatrix', + 'normalMatrix', + 'modelMatrix', + 'cameraPosition', + 'morphTargetInfluences', + 'bindMatrix', + 'bindMatrixInverse' - triangulateQuads: function ( geometry ) { + ]; - var i, il, j, jl; + if ( parameters.useVertexTexture ) { - var faces = []; - var faceVertexUvs = []; + identifiers.push( 'boneTexture' ); + identifiers.push( 'boneTextureWidth' ); + identifiers.push( 'boneTextureHeight' ); - for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) { + } else { - faceVertexUvs[ i ] = []; + identifiers.push( 'boneGlobalMatrices' ); } - for ( i = 0, il = geometry.faces.length; i < il; i ++ ) { + if ( parameters.logarithmicDepthBuffer ) { - var face = geometry.faces[ i ]; + identifiers.push('logDepthBufFC'); - faces.push( face ); + } - for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { - faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] ); + for ( var u in uniforms ) { - } + identifiers.push( u ); } - geometry.faces = faces; - geometry.faceVertexUvs = faceVertexUvs; - - geometry.computeCentroids(); - geometry.computeFaceNormals(); - geometry.computeVertexNormals(); + this.uniforms = cacheUniformLocations( _gl, program, identifiers ); - if ( geometry.hasTangents ) geometry.computeTangents(); + // cache attributes locations - } + identifiers = [ -}; + 'position', + 'normal', + 'uv', + 'uv2', + 'tangent', + 'color', + 'skinIndex', + 'skinWeight', + 'lineDistance' -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + ]; -THREE.ImageUtils = { + for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) { - crossOrigin: 'anonymous', + identifiers.push( 'morphTarget' + i ); - loadTexture: function ( url, mapping, onLoad, onError ) { + } - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; + for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) { - var texture = new THREE.Texture( undefined, mapping ); + identifiers.push( 'morphNormal' + i ); - var image = loader.load( url, function () { + } - texture.needsUpdate = true; + for ( var a in attributes ) { - if ( onLoad ) onLoad( texture ); + identifiers.push( a ); - } ); + } - texture.image = image; - texture.sourceFile = url; + this.attributes = cacheAttributeLocations( _gl, program, identifiers ); + this.attributesKeys = Object.keys( this.attributes ); - return texture; + // - }, + this.id = programIdCount ++; + this.code = code; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; - loadCompressedTexture: function ( url, mapping, onLoad, onError ) { + return this; - var texture = new THREE.CompressedTexture(); - texture.mapping = mapping; + }; - var request = new XMLHttpRequest(); +} )(); - request.onload = function () { +// File:src/renderers/webgl/WebGLShader.js - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); +THREE.WebGLShader = ( function () { - texture.format = dds.format; + var addLineNumbers = function ( string ) { - texture.mipmaps = dds.mipmaps; - texture.image.width = dds.width; - texture.image.height = dds.height; + var lines = string.split( '\n' ); - // gl.generateMipmap fails for compressed textures - // mipmaps must be embedded in the DDS file - // or texture filters must not use mipmapping + for ( var i = 0; i < lines.length; i ++ ) { - texture.generateMipmaps = false; + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - texture.needsUpdate = true; + } - if ( onLoad ) onLoad( texture ); + return lines.join( '\n' ); - } + }; - request.onerror = onError; + return function ( gl, type, string ) { - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + var shader = gl.createShader( type ); - return texture; + gl.shaderSource( shader, string ); + gl.compileShader( shader ); - }, + if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - loadTextureCube: function ( array, mapping, onLoad, onError ) { + THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); - var images = []; - images.loadCount = 0; + } - var texture = new THREE.Texture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + if ( gl.getShaderInfoLog( shader ) !== '' ) { - // no flipping needed for cube textures + THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); - texture.flipY = false; + } - for ( var i = 0, il = array.length; i < il; ++ i ) { + // --enable-privileged-webgl-extension + // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - var cubeImage = new Image(); - images[ i ] = cubeImage; + return shader; - cubeImage.onload = function () { + }; - images.loadCount += 1; +} )(); - if ( images.loadCount === 6 ) { +// File:src/renderers/webgl/WebGLState.js - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } +THREE.WebGLState = function ( gl, paramThreeToGL ) { - }; + var newAttributes = new Uint8Array( 16 ); + var enabledAttributes = new Uint8Array( 16 ); - cubeImage.onerror = onError; + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; - cubeImage.crossOrigin = this.crossOrigin; - cubeImage.src = array[ i ]; + var currentDepthTest = null; + var currentDepthWrite = null; - } + var currentColorWrite = null; - return texture; + var currentDoubleSided = null; + var currentFlipSided = null; - }, + var currentLineWidth = null; - loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { + var currentPolygonOffset = null; + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; - var images = []; - images.loadCount = 0; + this.initAttributes = function () { - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + newAttributes[ i ] = 0; - texture.flipY = false; + } - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + }; - texture.generateMipmaps = false; + this.enableAttribute = function ( attribute ) { - var generateCubeFaceCallback = function ( rq, img ) { + newAttributes[ attribute ] = 1; - return function () { + if ( enabledAttributes[ attribute ] === 0 ) { - var buffer = rq.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - img.format = dds.format; + } - img.mipmaps = dds.mipmaps; - img.width = dds.width; - img.height = dds.height; + }; - images.loadCount += 1; + this.disableUnusedAttributes = function () { - if ( images.loadCount === 6 ) { + for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - } + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; } } - // compressed cubemap textures as 6 separate DDS files - - if ( array instanceof Array ) { + }; - for ( var i = 0, il = array.length; i < il; ++ i ) { + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - var cubeImage = {}; - images[ i ] = cubeImage; + if ( blending !== currentBlending ) { - var request = new XMLHttpRequest(); + if ( blending === THREE.NoBlending ) { - request.onload = generateCubeFaceCallback( request, cubeImage ); - request.onerror = onError; + gl.disable( gl.BLEND ); - var url = array[ i ]; + } else if ( blending === THREE.AdditiveBlending ) { - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - } + } else if ( blending === THREE.SubtractiveBlending ) { - // compressed cubemap texture stored in a single DDS file + // TODO: Find blendFuncSeparate() combination + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); - } else { + } else if ( blending === THREE.MultiplyBlending ) { - var url = array; - var request = new XMLHttpRequest(); + // TODO: Find blendFuncSeparate() combination + gl.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - request.onload = function( ) { + } else if ( blending === THREE.CustomBlending ) { - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + gl.enable( gl.BLEND ); - if ( dds.isCubemap ) { + } else { - var faces = dds.mipmaps.length / dds.mipmapCount; + gl.enable( gl.BLEND ); + gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); - for ( var f = 0; f < faces; f ++ ) { + } - images[ f ] = { mipmaps : [] }; + currentBlending = blending; - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + } - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; + if ( blending === THREE.CustomBlending ) { - } + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - } + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - } + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; } - request.onerror = onError; - - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); - - } - - return texture; + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - }, + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - loadDDSTexture: function ( url, mapping, onLoad, onError ) { + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; - var images = []; - images.loadCount = 0; + } - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; + } else { - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - texture.flipY = false; + } - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + }; - texture.generateMipmaps = false; + this.setDepthTest = function ( depthTest ) { - { - var request = new XMLHttpRequest(); + if ( currentDepthTest !== depthTest ) { - request.onload = function( ) { + if ( depthTest ) { - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); + gl.enable( gl.DEPTH_TEST ); - if ( dds.isCubemap ) { + } else { - var faces = dds.mipmaps.length / dds.mipmapCount; + gl.disable( gl.DEPTH_TEST ); - for ( var f = 0; f < faces; f ++ ) { + } - images[ f ] = { mipmaps : [] }; + currentDepthTest = depthTest; - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + } - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; + }; - } + this.setDepthWrite = function ( depthWrite ) { - } + if ( currentDepthWrite !== depthWrite ) { + gl.depthMask( depthWrite ); + currentDepthWrite = depthWrite; - } else { - texture.image.width = dds.width; - texture.image.height = dds.height; - texture.mipmaps = dds.mipmaps; - } + } - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); + }; - } + this.setColorWrite = function ( colorWrite ) { - request.onerror = onError; + if ( currentColorWrite !== colorWrite ) { - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); + gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); + currentColorWrite = colorWrite; } - return texture; + }; - }, + this.setDoubleSided = function ( doubleSided ) { - parseDDS: function ( buffer, loadMipmaps ) { + if ( currentDoubleSided !== doubleSided ) { - var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + if ( doubleSided ) { - // Adapted from @toji's DDS utils - // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + gl.disable( gl.CULL_FACE ); - // All values and structures referenced from: - // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + } else { - var DDS_MAGIC = 0x20534444; + gl.enable( gl.CULL_FACE ); - var DDSD_CAPS = 0x1, - DDSD_HEIGHT = 0x2, - DDSD_WIDTH = 0x4, - DDSD_PITCH = 0x8, - DDSD_PIXELFORMAT = 0x1000, - DDSD_MIPMAPCOUNT = 0x20000, - DDSD_LINEARSIZE = 0x80000, - DDSD_DEPTH = 0x800000; + } - var DDSCAPS_COMPLEX = 0x8, - DDSCAPS_MIPMAP = 0x400000, - DDSCAPS_TEXTURE = 0x1000; + currentDoubleSided = doubleSided; - var DDSCAPS2_CUBEMAP = 0x200, - DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, - DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, - DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, - DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, - DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, - DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, - DDSCAPS2_VOLUME = 0x200000; + } - var DDPF_ALPHAPIXELS = 0x1, - DDPF_ALPHA = 0x2, - DDPF_FOURCC = 0x4, - DDPF_RGB = 0x40, - DDPF_YUV = 0x200, - DDPF_LUMINANCE = 0x20000; + }; - function fourCCToInt32( value ) { + this.setFlipSided = function ( flipSided ) { - return value.charCodeAt(0) + - (value.charCodeAt(1) << 8) + - (value.charCodeAt(2) << 16) + - (value.charCodeAt(3) << 24); + if ( currentFlipSided !== flipSided ) { - } + if ( flipSided ) { - function int32ToFourCC( value ) { + gl.frontFace( gl.CW ); - return String.fromCharCode( - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); - } + } else { + + gl.frontFace( gl.CCW ); - function loadARGBMip( buffer, dataOffset, width, height ) { - var dataLength = width*height*4; - var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); - var byteArray = new Uint8Array( dataLength ); - var dst = 0; - var src = 0; - for ( var y = 0; y < height; y++ ) { - for ( var x = 0; x < width; x++ ) { - var b = srcBuffer[src]; src++; - var g = srcBuffer[src]; src++; - var r = srcBuffer[src]; src++; - var a = srcBuffer[src]; src++; - byteArray[dst] = r; dst++; //r - byteArray[dst] = g; dst++; //g - byteArray[dst] = b; dst++; //b - byteArray[dst] = a; dst++; //a - } } - return byteArray; + + currentFlipSided = flipSided; + } - var FOURCC_DXT1 = fourCCToInt32("DXT1"); - var FOURCC_DXT3 = fourCCToInt32("DXT3"); - var FOURCC_DXT5 = fourCCToInt32("DXT5"); + }; - var headerLengthInt = 31; // The header length in 32 bit ints + this.setLineWidth = function ( width ) { - // Offsets into the header array + if ( width !== currentLineWidth ) { - var off_magic = 0; + gl.lineWidth( width ); - var off_size = 1; - var off_flags = 2; - var off_height = 3; - var off_width = 4; + currentLineWidth = width; - var off_mipmapCount = 7; + } - var off_pfFlags = 20; - var off_pfFourCC = 21; - var off_RGBBitCount = 22; - var off_RBitMask = 23; - var off_GBitMask = 24; - var off_BBitMask = 25; - var off_ABitMask = 26; + }; - var off_caps = 27; - var off_caps2 = 28; - var off_caps3 = 29; - var off_caps4 = 30; + this.setPolygonOffset = function ( polygonoffset, factor, units ) { - // Parse header + if ( currentPolygonOffset !== polygonoffset ) { - var header = new Int32Array( buffer, 0, headerLengthInt ); + if ( polygonoffset ) { - if ( header[ off_magic ] !== DDS_MAGIC ) { + gl.enable( gl.POLYGON_OFFSET_FILL ); - console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); - return dds; + } else { - } + gl.disable( gl.POLYGON_OFFSET_FILL ); - if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { + } - console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); - return dds; + currentPolygonOffset = polygonoffset; } - var blockBytes; + if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { - var fourCC = header[ off_pfFourCC ]; + gl.polygonOffset( factor, units ); - var isRGBAUncompressed = false; + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; - switch ( fourCC ) { + } - case FOURCC_DXT1: + }; - blockBytes = 8; - dds.format = THREE.RGB_S3TC_DXT1_Format; - break; + this.reset = function () { - case FOURCC_DXT3: + for ( var i = 0; i < enabledAttributes.length; i ++ ) { - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT3_Format; - break; + enabledAttributes[ i ] = 0; - case FOURCC_DXT5: + } - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT5_Format; - break; + currentBlending = null; + currentDepthTest = null; + currentDepthWrite = null; + currentColorWrite = null; + currentDoubleSided = null; + currentFlipSided = null; - default: + }; - if( header[off_RGBBitCount] ==32 - && header[off_RBitMask]&0xff0000 - && header[off_GBitMask]&0xff00 - && header[off_BBitMask]&0xff - && header[off_ABitMask]&0xff000000 ) { - isRGBAUncompressed = true; - blockBytes = 64; - dds.format = THREE.RGBAFormat; - } else { - console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); - return dds; - } - } +}; - dds.mipmapCount = 1; +// File:src/renderers/webgl/plugins/LensFlarePlugin.js - if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ - dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); +THREE.LensFlarePlugin = function ( renderer, flares ) { - } + var gl = renderer.context; - //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; + var hasVertexTexture; - dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; + var tempTexture, occlusionTexture; - dds.width = header[ off_width ]; - dds.height = header[ off_height ]; + var init = function () { - var dataOffset = header[ off_size ] + 4; + var vertices = new Float32Array( [ + -1, -1, 0, 0, + 1, -1, 1, 0, + 1, 1, 1, 1, + -1, 1, 0, 1 + ] ); - // Extract mipmaps buffers + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - var width = dds.width; - var height = dds.height; + // buffers - var faces = dds.isCubemap ? 6 : 1; + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - for ( var face = 0; face < faces; face ++ ) { + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - for ( var i = 0; i < dds.mipmapCount; i ++ ) { + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - if( isRGBAUncompressed ) { - var byteArray = loadARGBMip( buffer, dataOffset, width, height ); - var dataLength = byteArray.length; - } else { - var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; - var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); - } + // textures - var mipmap = { "data": byteArray, "width": width, "height": height }; - dds.mipmaps.push( mipmap ); + tempTexture = gl.createTexture(); + occlusionTexture = gl.createTexture(); - dataOffset += dataLength; + gl.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - width = Math.max( width * 0.5, 1 ); - height = Math.max( height * 0.5, 1 ); + gl.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - } + hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0; - width = dds.width; - height = dds.height; + var shader; - } + if ( hasVertexTexture ) { - return dds; + shader = { - }, + vertexShader: [ - getNormalMap: function ( image, depth ) { + "uniform lowp int renderType;", - // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - var cross = function ( a, b ) { + "uniform sampler2D occlusionMap;", - return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; + "attribute vec2 position;", + "attribute vec2 uv;", - } + "varying vec2 vUV;", + "varying float vVisibility;", - var subtract = function ( a, b ) { + "void main() {", - return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; + "vUV = uv;", - } + "vec2 pos = position;", - var normalize = function ( a ) { + "if( renderType == 2 ) {", - var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); - return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; + "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", - } + "vVisibility = visibility.r / 9.0;", + "vVisibility *= 1.0 - visibility.g / 9.0;", + "vVisibility *= visibility.b / 9.0;", + "vVisibility *= 1.0 - visibility.a / 9.0;", - depth = depth | 1; + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - var width = image.width; - var height = image.height; + "}", - var canvas = document.createElement( 'canvas' ); - canvas.width = width; - canvas.height = height; + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0 ); + "}" - var data = context.getImageData( 0, 0, width, height ).data; - var imageData = context.createImageData( width, height ); - var output = imageData.data; + ].join( "\n" ), - for ( var x = 0; x < width; x ++ ) { + fragmentShader: [ - for ( var y = 0; y < height; y ++ ) { + "uniform lowp int renderType;", - var ly = y - 1 < 0 ? 0 : y - 1; - var uy = y + 1 > height - 1 ? height - 1 : y + 1; - var lx = x - 1 < 0 ? 0 : x - 1; - var ux = x + 1 > width - 1 ? width - 1 : x + 1; + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", - var points = []; - var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; - points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + "varying vec2 vUV;", + "varying float vVisibility;", - var normals = []; - var num_points = points.length; + "void main() {", - for ( var i = 0; i < num_points; i ++ ) { + // pink square - var v1 = points[ i ]; - var v2 = points[ ( i + 1 ) % num_points ]; - v1 = subtract( v1, origin ); - v2 = subtract( v2, origin ); - normals.push( normalize( cross( v1, v2 ) ) ); + "if( renderType == 0 ) {", - } + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", - var normal = [ 0, 0, 0 ]; + // restore - for ( var i = 0; i < normals.length; i ++ ) { + "} else if( renderType == 1 ) {", - normal[ 0 ] += normals[ i ][ 0 ]; - normal[ 1 ] += normals[ i ][ 1 ]; - normal[ 2 ] += normals[ i ][ 2 ]; + "gl_FragColor = texture2D( map, vUV );", - } + // flare - normal[ 0 ] /= normals.length; - normal[ 1 ] /= normals.length; - normal[ 2 ] /= normals.length; + "} else {", - var idx = ( y * width + x ) * 4; + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - output[ idx ] = ( ( normal[ 0 ] + 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; + "}", - } + "}" - } + ].join( "\n" ) - context.putImageData( imageData, 0, 0 ); + }; - return canvas; + } else { - }, + shader = { - generateDataTexture: function ( width, height, color ) { + vertexShader: [ - var size = width * height; - var data = new Uint8Array( 3 * size ); + "uniform lowp int renderType;", - var r = Math.floor( color.r * 255 ); - var g = Math.floor( color.g * 255 ); - var b = Math.floor( color.b * 255 ); + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - for ( var i = 0; i < size; i ++ ) { + "attribute vec2 position;", + "attribute vec2 uv;", - data[ i * 3 ] = r; - data[ i * 3 + 1 ] = g; - data[ i * 3 + 2 ] = b; + "varying vec2 vUV;", - } + "void main() {", - var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); - texture.needsUpdate = true; + "vUV = uv;", - return texture; + "vec2 pos = position;", - } + "if( renderType == 2 ) {", -}; + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", -/** - * @author alteredq / http://alteredqualia.com/ - */ + "}", -THREE.SceneUtils = { + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - createMultiMaterialObject: function ( geometry, materials ) { + "}" - var group = new THREE.Object3D(); + ].join( "\n" ), - for ( var i = 0, l = materials.length; i < l; i ++ ) { + fragmentShader: [ - group.add( new THREE.Mesh( geometry, materials[ i ] ) ); + "precision mediump float;", - } + "uniform lowp int renderType;", - return group; + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", - }, + "varying vec2 vUV;", - detach : function ( child, parent, scene ) { + "void main() {", - child.applyMatrix( parent.matrixWorld ); - parent.remove( child ); - scene.add( child ); + // pink square - }, + "if( renderType == 0 ) {", - attach: function ( child, scene, parent ) { + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", - var matrixWorldInverse = new THREE.Matrix4(); - matrixWorldInverse.getInverse( parent.matrixWorld ); - child.applyMatrix( matrixWorldInverse ); + // restore - scene.remove( child ); - parent.add( child ); + "} else if( renderType == 1 ) {", - } + "gl_FragColor = texture2D( map, vUV );", -}; + // flare -/** - * @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/ - * - */ + "} else {", -THREE.FontUtils = { + "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", + "visibility = ( 1.0 - visibility / 4.0 );", - faces : {}, + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - // Just for now. face[weight][style] + "}", - face : "helvetiker", - weight: "normal", - style : "normal", - size : 150, - divisions : 10, + "}" - getFace : function() { + ].join( "\n" ) - return this.faces[ this.face ][ this.weight ][ this.style ]; + }; - }, + } - loadFace : function( data ) { + program = createProgram( shader ); - var family = data.familyName.toLowerCase(); + attributes = { + vertex: gl.getAttribLocation ( program, "position" ), + uv: gl.getAttribLocation ( program, "uv" ) + } - var ThreeFont = this; + uniforms = { + renderType: gl.getUniformLocation( program, "renderType" ), + map: gl.getUniformLocation( program, "map" ), + occlusionMap: gl.getUniformLocation( program, "occlusionMap" ), + opacity: gl.getUniformLocation( program, "opacity" ), + color: gl.getUniformLocation( program, "color" ), + scale: gl.getUniformLocation( program, "scale" ), + rotation: gl.getUniformLocation( program, "rotation" ), + screenPosition: gl.getUniformLocation( program, "screenPosition" ) + }; - ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; + }; - ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; - ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + */ - var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { - return data; + if ( flares.length === 0 ) return; - }, + var tempPosition = new THREE.Vector3(); - drawText : function( text ) { + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; - var characterPts = [], allPts = []; + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); - // RenderText + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); - var i, p, - face = this.getFace(), - scale = this.size / face.resolution, - offset = 0, - chars = String( text ).split( '' ), - length = chars.length; + if ( program === undefined ) { - var fontPaths = []; + init(); - for ( i = 0; i < length; i ++ ) { + } - var path = new THREE.Path(); + gl.useProgram( program ); - var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); - offset += ret.offset; + gl.enableVertexAttribArray( attributes.vertex ); + gl.enableVertexAttribArray( attributes.uv ); - fontPaths.push( ret.path ); + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/unforms - } + gl.uniform1i( uniforms.occlusionMap, 0 ); + gl.uniform1i( uniforms.map, 1 ); - // get the width + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); + gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); - var width = offset / 2; - // - // for ( p = 0; p < allPts.length; p++ ) { - // - // allPts[ p ].x -= width; - // - // } + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - //var extract = this.extractPoints( allPts, characterPts ); - //extract.contour = allPts; + gl.disable( gl.CULL_FACE ); + gl.depthMask( false ); - //extract.paths = fontPaths; - //extract.offset = width; + for ( var i = 0, l = flares.length; i < l; i ++ ) { - return { paths : fontPaths, offset : width }; + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); - }, + // calc object screen position + var flare = flares[ i ]; + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); - extractGlyphPoints : function( c, face, scale, offset, path ) { + // setup arrays for gl programs - var pts = []; + screenPosition.copy( tempPosition ) - 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[ '?' ]; + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; - if ( !glyph ) return; + // screen cull - if ( glyph.o ) { + if ( hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { - outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - length = outline.length; + // save current RGB to temp texture - scaleX = scale; - scaleY = scale; + gl.activeTexture( gl.TEXTURE1 ); + gl.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - for ( i = 0; i < length; ) { - action = outline[ i ++ ]; + // render pink quad - //console.log( action ); + gl.uniform1i( uniforms.renderType, 0 ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - switch( action ) { + gl.disable( gl.BLEND ); + gl.enable( gl.DEPTH_TEST ); - case 'm': + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - // Move To - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; + // copy result to occlusionMap - path.moveTo( x, y ); - break; + gl.activeTexture( gl.TEXTURE0 ); + gl.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - case 'l': - // Line To + // restore graphics - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; - path.lineTo(x,y); - break; + gl.uniform1i( uniforms.renderType, 1 ); + gl.disable( gl.DEPTH_TEST ); - case 'q': + gl.activeTexture( gl.TEXTURE1 ); + gl.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - // QuadraticCurveTo - cpx = outline[ i++ ] * scaleX + offset; - cpy = outline[ i++ ] * scaleY; - cpx1 = outline[ i++ ] * scaleX + offset; - cpy1 = outline[ i++ ] * scaleY; + // update object positions - path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + flare.positionScreen.copy( screenPosition ) - laste = pts[ pts.length - 1 ]; + if ( flare.customUpdateCallback ) { - if ( laste ) { + flare.customUpdateCallback( flare ); - cpx0 = laste.x; - cpy0 = laste.y; + } else { - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + flare.updateLensFlares(); - var t = i2 / divisions; - var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - } + } - } + // render flares - break; + gl.uniform1i( uniforms.renderType, 2 ); + gl.enable( gl.BLEND ); - case 'b': + for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - // Cubic Bezier Curve + var sprite = flare.lensFlares[ j ]; - 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; + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; - laste = pts[ pts.length - 1 ]; + size = sprite.size * sprite.scale / viewportHeight; - if ( laste ) { + scale.x = size * invAspect; + scale.y = size; - cpx0 = laste.x; - cpy0 = laste.y; + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform1f( uniforms.rotation, sprite.rotation ); - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + gl.uniform1f( uniforms.opacity, sprite.opacity ); + gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); - 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 ); + renderer.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + renderer.setTexture( sprite.texture, 1 ); - } + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); } - break; - } } - } - - - - return { offset: glyph.ha*scale, path:path}; - } -}; + } + // restore gl -THREE.FontUtils.generateShapes = function( text, parameters ) { + gl.enable( gl.CULL_FACE ); + gl.enable( gl.DEPTH_TEST ); + gl.depthMask( true ); - // Parameters + renderer.resetGLState(); - parameters = parameters || {}; + }; - var size = parameters.size !== undefined ? parameters.size : 100; - var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; + function createProgram ( shader ) { - var font = parameters.font !== undefined ? parameters.font : "helvetiker"; - var weight = parameters.weight !== undefined ? parameters.weight : "normal"; - var style = parameters.style !== undefined ? parameters.style : "normal"; + var program = gl.createProgram(); - THREE.FontUtils.size = size; - THREE.FontUtils.divisions = curveSegments; + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - THREE.FontUtils.face = font; - THREE.FontUtils.weight = weight; - THREE.FontUtils.style = style; + var prefix = "precision " + renderer.getPrecision() + " float;\n"; - // Get a Font data json object + gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - var data = THREE.FontUtils.drawText( text ); + gl.compileShader( fragmentShader ); + gl.compileShader( vertexShader ); - var paths = data.paths; - var shapes = []; + gl.attachShader( program, fragmentShader ); + gl.attachShader( program, vertexShader ); - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + gl.linkProgram( program ); - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + return program; } - return shapes; - }; +// File:src/renderers/webgl/plugins/ShadowMapPlugin.js /** - * 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 - * + * @author alteredq / http://alteredqualia.com/ */ +THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) { -( function( namespace ) { + var _gl = _renderer.context; - var EPSILON = 0.0000000001; + var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, - // takes in an contour array and returns + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), - var process = function( contour, indices ) { + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), - var n = contour.length; + _matrixPosition = new THREE.Vector3(), - if ( n < 3 ) return null; + _renderList = []; - var result = [], - verts = [], - vertIndices = []; + // init - /* we want a counter-clockwise polygon in verts */ + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); - var u, v, w; + _depthMaterial = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader + } ); - if ( area( contour ) > 0.0 ) { + _depthMaterialMorph = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + morphTargets: true + } ); - for ( v = 0; v < n; v++ ) verts[ v ] = v; + _depthMaterialSkin = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + skinning: true + } ); - } else { + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + morphTargets: true, + skinning: true + } ); - for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; - } + this.render = function ( scene, camera ) { - var nv = n; + if ( _renderer.shadowMapEnabled === false ) return; - /* remove nv - 2 vertices, creating 1 triangle every time */ + var i, il, j, jl, n, - var count = 2 * nv; /* error detection */ + shadowMap, shadowMatrix, shadowCamera, + buffer, material, + webglObject, object, light, - for( v = nv - 1; nv > 2; ) { + lights = [], + k = 0, - /* if we loop, it is probably a non-simple polygon */ + fog = null; - if ( ( count-- ) <= 0 ) { + // set GL state for depth map - //** Triangulate: ERROR - probable bad polygon! + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); - //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!" ); + _gl.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); - if ( indices ) return vertIndices; - return result; + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - } + _gl.cullFace( _gl.FRONT ); - /* three consecutive vertices in current polygon, <u,v,w> */ + } else { - 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 */ + _gl.cullFace( _gl.BACK ); - if ( snip( contour, u, v, w, nv, verts ) ) { + } - var a, b, c, s, t; + _renderer.state.setDepthTest( true ); - /* true names of the vertices */ + // preprocess lights + // - skip lights that are not casting shadows + // - create virtual lights for cascaded shadow maps - a = verts[ u ]; - b = verts[ v ]; - c = verts[ w ]; + for ( i = 0, il = _lights.length; i < il; i ++ ) { - /* output Triangle */ + light = _lights[ i ]; - result.push( [ contour[ a ], - contour[ b ], - contour[ c ] ] ); + if ( ! light.castShadow ) continue; + if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { - vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); + for ( n = 0; n < light.shadowCascadeCount; n ++ ) { - /* remove v from the remaining polygon */ + var virtualLight; - for( s = v, t = v + 1; t < nv; s++, t++ ) { + if ( ! light.shadowCascadeArray[ n ] ) { - verts[ s ] = verts[ t ]; + virtualLight = createVirtualLight( light, n ); + virtualLight.originalCamera = camera; - } + var gyro = new THREE.Gyroscope(); + gyro.position.copy( light.shadowCascadeOffset ); - nv--; + gyro.add( virtualLight ); + gyro.add( virtualLight.target ); - /* reset error detection counter */ + camera.add( gyro ); - count = 2 * nv; + light.shadowCascadeArray[ n ] = virtualLight; - } + //console.log( "Created virtualLight", virtualLight ); - } + } else { - if ( indices ) return vertIndices; - return result; + virtualLight = light.shadowCascadeArray[ n ]; - }; + } - // calculate area of the contour polygon + updateVirtualLight( light, n ); - var area = function ( contour ) { + lights[ k ] = virtualLight; + k ++; - var n = contour.length; - var a = 0.0; + } - for( var p = n - 1, q = 0; q < n; p = q++ ) { + } else { - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + lights[ k ] = light; + k ++; + + } } - return a * 0.5; + // render depth map - }; + for ( i = 0, il = lights.length; i < il; i ++ ) { - var snip = function ( contour, u, v, w, n, verts ) { + light = lights[ i ]; - var p; - var ax, ay, bx, by; - var cx, cy, px, py; + if ( ! light.shadowMap ) { - ax = contour[ verts[ u ] ].x; - ay = contour[ verts[ u ] ].y; + var shadowFilter = THREE.LinearFilter; - bx = contour[ verts[ v ] ].x; - by = contour[ verts[ v ] ].y; + if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { - cx = contour[ verts[ w ] ].x; - cy = contour[ verts[ w ] ].y; + shadowFilter = THREE.NearestFilter; - if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; + } - var aX, aY, bX, bY, cX, cY; - var apx, apy, bpx, bpy, cpx, cpy; - var cCROSSap, bCROSScp, aCROSSbp; + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; - aX = cx - bx; aY = cy - by; - bX = ax - cx; bY = ay - cy; - cX = bx - ax; cY = by - ay; + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + + light.shadowMatrix = new THREE.Matrix4(); - for ( p = 0; p < n; p++ ) { + } - if( (p === u) || (p === v) || (p === w) ) continue; + if ( ! light.shadowCamera ) { - px = contour[ verts[ p ] ].x - py = contour[ verts[ p ] ].y + if ( light instanceof THREE.SpotLight ) { - apx = px - ax; apy = py - ay; - bpx = px - bx; bpy = py - by; - cpx = px - cx; cpy = py - cy; + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); - // see if p is inside triangle abc + } else if ( light instanceof THREE.DirectionalLight ) { - aCROSSbp = aX*bpy - aY*bpx; - cCROSSap = cX*apy - cY*apx; - bCROSScp = bX*cpy - bY*cpx; + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); - if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; + } else { - } + THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); + continue; - return true; + } - }; + scene.add( light.shadowCamera ); + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - namespace.Triangulate = process; - namespace.Triangulate.area = area; + } - return namespace; + if ( light.shadowCameraVisible && ! light.cameraHelper ) { -})(THREE.FontUtils); + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + scene.add( light.cameraHelper ); -// To use the typeface.js face files, hook up the API -self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; -THREE.typeface_js = self._typeface_js; + } -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of Curve methods - * .getPoint(t), getTangent(t) - * .getPointAt(u), getTagentAt(u) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following classes subclasses THREE.Curve: - * - * -- 2d classes -- - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.CubicBezierCurve - * THREE.SplineCurve - * THREE.ArcCurve - * THREE.EllipseCurve - * - * -- 3d classes -- - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * THREE.CubicBezierCurve3 - * THREE.SplineCurve3 - * THREE.ClosedSplineCurve3 - * - * A series of curves can be represented as a THREE.CurvePath - * - **/ + if ( light.isVirtual && virtualLight.originalCamera == camera ) { -/************************************************************** - * Abstract Curve base class - **************************************************************/ + updateShadowCamera( camera, light ); -THREE.Curve = function () { + } -}; + shadowMap = light.shadowMap; + shadowMatrix = light.shadowMatrix; + shadowCamera = light.shadowCamera; -// Virtual base class method to overwrite and implement in subclasses -// - t [0 .. 1] + // -THREE.Curve.prototype.getPoint = function ( t ) { + shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); + _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _matrixPosition ); + shadowCamera.updateMatrixWorld(); - console.log( "Warning, getPoint() not implemented!" ); - return null; + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); -}; + // -// Get point at relative position in curve according to arc length -// - u [0 .. 1] + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); -THREE.Curve.prototype.getPointAt = function ( u ) { + // compute shadow matrix - var t = this.getUtoTmapping( u ); - return this.getPoint( t ); + shadowMatrix.set( + 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 + ); -}; + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); -// Get sequence of points using getPoint( t ) + // update camera matrices and frustum -THREE.Curve.prototype.getPoints = function ( divisions ) { + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - if ( !divisions ) divisions = 5; + // render shadow map - var d, pts = []; + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); - for ( d = 0; d <= divisions; d ++ ) { + // set object matrices & frustum culling - pts.push( this.getPoint( d / divisions ) ); + _renderList.length = 0; - } + projectObject( scene, scene, shadowCamera ); - return pts; -}; + // render regular objects -// Get sequence of points using getPointAt( u ) + var objectMaterial, useMorphing, useSkinning; -THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { + for ( j = 0, jl = _renderList.length; j < jl; j ++ ) { - if ( !divisions ) divisions = 5; + webglObject = _renderList[ j ]; - var d, pts = []; + object = webglObject.object; + buffer = webglObject.buffer; - for ( d = 0; d <= divisions; d ++ ) { + // culling is overriden globally for all objects + // while rendering depth map - pts.push( this.getPointAt( d / divisions ) ); + // need to deal with MeshFaceMaterial somehow + // in that case just use the first of material.materials for now + // (proper solution would require to break objects by materials + // similarly to regular rendering and then set corresponding + // depth materials per each chunk instead of just once per object) - } + objectMaterial = getObjectMaterial( object ); - return pts; + useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; -}; + if ( object.customDepthMaterial ) { -// Get total curve arc length + material = object.customDepthMaterial; -THREE.Curve.prototype.getLength = function () { + } else if ( useSkinning ) { - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; -}; + } else if ( useMorphing ) { -// Get list of cumulative segment lengths + material = _depthMaterialMorph; -THREE.Curve.prototype.getLengths = function ( divisions ) { + } else { - if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + material = _depthMaterial; - if ( this.cacheArcLengths - && ( this.cacheArcLengths.length == divisions + 1 ) - && !this.needsUpdate) { + } - //console.log( "cached", this.cacheArcLengths ); - return this.cacheArcLengths; + _renderer.setMaterialFaces( objectMaterial ); - } + if ( buffer instanceof THREE.BufferGeometry ) { - this.needsUpdate = false; + _renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object ); - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; + } else { - cache.push( 0 ); + _renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object ); - for ( p = 1; p <= divisions; p ++ ) { + } - current = this.getPoint ( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + } - } + // set matrices and render immediate objects - this.cacheArcLengths = cache; + for ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) { - return cache; // { sums: cache, sum:sum }; Sum is in the last element. + webglObject = _webglObjectsImmediate[ j ]; + object = webglObject.object; -}; + if ( object.visible && object.castShadow ) { + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); -THREE.Curve.prototype.updateArcLengths = function() { - this.needsUpdate = true; - this.getLengths(); -}; + _renderer.renderImmediateObject( shadowCamera, _lights, fog, _depthMaterial, object ); -// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance + } -THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { + } - var arcLengths = this.getLengths(); + } - var i = 0, il = arcLengths.length; + // restore GL state - var targetArcLength; // The targeted u distance value to get + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); - if ( distance ) { + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); - targetArcLength = distance; + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - } else { + _gl.cullFace( _gl.BACK ); - targetArcLength = u * arcLengths[ il - 1 ]; + } - } + _renderer.resetGLState(); - //var time = Date.now(); + }; - // binary search for the index with largest value smaller than target u distance + function projectObject( scene, object, shadowCamera ) { - var low = 0, high = il - 1, comparison; + if ( object.visible ) { - while ( low <= high ) { + var webglObjects = _webglObjects[ object.id ]; - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + if ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) { - comparison = arcLengths[ i ] - targetArcLength; + for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - if ( comparison < 0 ) { + var webglObject = webglObjects[ i ]; - low = i + 1; - continue; + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + _renderList.push( webglObject ); - } else if ( comparison > 0 ) { + } - high = i - 1; - continue; + } - } else { + for ( var i = 0, l = object.children.length; i < l; i ++ ) { - high = i; - break; + projectObject( scene, object.children[ i ], shadowCamera ); - // DONE + } } } - i = high; + function createVirtualLight( light, cascade ) { - //console.log('b' , i, low, high, Date.now()- time); + var virtualLight = new THREE.DirectionalLight(); - if ( arcLengths[ i ] == targetArcLength ) { + virtualLight.isVirtual = true; - var t = i / ( il - 1 ); - return t; + virtualLight.onlyShadow = true; + virtualLight.castShadow = true; - } + virtualLight.shadowCameraNear = light.shadowCameraNear; + virtualLight.shadowCameraFar = light.shadowCameraFar; - // we could get finer grain at lengths, or use simple interpolatation between two points + virtualLight.shadowCameraLeft = light.shadowCameraLeft; + virtualLight.shadowCameraRight = light.shadowCameraRight; + virtualLight.shadowCameraBottom = light.shadowCameraBottom; + virtualLight.shadowCameraTop = light.shadowCameraTop; - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + virtualLight.shadowCameraVisible = light.shadowCameraVisible; - var segmentLength = lengthAfter - lengthBefore; + virtualLight.shadowDarkness = light.shadowDarkness; - // determine where we are between the 'before' and 'after' points + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; + virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + virtualLight.pointsWorld = []; + virtualLight.pointsFrustum = []; - // add that fractional amount to t + var pointsWorld = virtualLight.pointsWorld, + pointsFrustum = virtualLight.pointsFrustum; - var t = ( i + segmentFraction ) / ( il -1 ); + for ( var i = 0; i < 8; i ++ ) { - return t; + pointsWorld[ i ] = new THREE.Vector3(); + pointsFrustum[ i ] = new THREE.Vector3(); -}; + } -// Returns a unit vector tangent at t -// In case any sub curve does not implement its tangent derivation, -// 2 points a small delta apart will be used to find its gradient -// which seems to give a reasonable approximation + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; -THREE.Curve.prototype.getTangent = function( t ) { + pointsFrustum[ 0 ].set( - 1, - 1, nearZ ); + pointsFrustum[ 1 ].set( 1, - 1, nearZ ); + pointsFrustum[ 2 ].set( - 1, 1, nearZ ); + pointsFrustum[ 3 ].set( 1, 1, nearZ ); - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + pointsFrustum[ 4 ].set( - 1, - 1, farZ ); + pointsFrustum[ 5 ].set( 1, - 1, farZ ); + pointsFrustum[ 6 ].set( - 1, 1, farZ ); + pointsFrustum[ 7 ].set( 1, 1, farZ ); - // Capping in case of danger + return virtualLight; - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + } - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + // Synchronize virtual light with the original light - var vec = pt2.clone().sub(pt1); - return vec.normalize(); + function updateVirtualLight( light, cascade ) { + + var virtualLight = light.shadowCascadeArray[ cascade ]; -}; + virtualLight.position.copy( light.position ); + virtualLight.target.position.copy( light.target.position ); + virtualLight.lookAt( virtualLight.target ); + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + virtualLight.shadowDarkness = light.shadowDarkness; -THREE.Curve.prototype.getTangentAt = function ( u ) { + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; -}; + var pointsFrustum = virtualLight.pointsFrustum; + pointsFrustum[ 0 ].z = nearZ; + pointsFrustum[ 1 ].z = nearZ; + pointsFrustum[ 2 ].z = nearZ; + pointsFrustum[ 3 ].z = nearZ; + pointsFrustum[ 4 ].z = farZ; + pointsFrustum[ 5 ].z = farZ; + pointsFrustum[ 6 ].z = farZ; + pointsFrustum[ 7 ].z = farZ; + } + // Fit shadow camera's ortho frustum to camera frustum -/************************************************************** - * Utils - **************************************************************/ + function updateShadowCamera( camera, light ) { -THREE.Curve.Utils = { + var shadowCamera = light.shadowCamera, + pointsFrustum = light.pointsFrustum, + pointsWorld = light.pointsWorld; - tangentQuadraticBezier: function ( t, p0, p1, p2 ) { + _min.set( Infinity, Infinity, Infinity ); + _max.set( - Infinity, - Infinity, - Infinity ); - return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + for ( var i = 0; i < 8; i ++ ) { - }, + var p = pointsWorld[ i ]; - // Puay Bing, thanks for helping with this derivative! + p.copy( pointsFrustum[ i ] ); + p.unproject( camera ); - tangentCubicBezier: function (t, p0, p1, p2, p3 ) { + p.applyMatrix4( shadowCamera.matrixWorldInverse ); - return -3 * p0 * (1 - t) * (1 - t) + - 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + - 6 * t * p2 * (1-t) - 3 * t * t * p2 + - 3 * t * t * p3; - }, + if ( p.x < _min.x ) _min.x = p.x; + if ( p.x > _max.x ) _max.x = p.x; + if ( p.y < _min.y ) _min.y = p.y; + if ( p.y > _max.y ) _max.y = p.y; - tangentSpline: function ( t, p0, p1, p2, p3 ) { + if ( p.z < _min.z ) _min.z = p.z; + if ( p.z > _max.z ) _max.z = p.z; - // To check if my formulas are correct + } - var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 - var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t - var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 - var h11 = 3 * t * t - 2 * t; // t3 − t2 + shadowCamera.left = _min.x; + shadowCamera.right = _max.x; + shadowCamera.top = _max.y; + shadowCamera.bottom = _min.y; - return h00 + h10 + h01 + h11; + // can't really fit near/far + //shadowCamera.near = _min.z; + //shadowCamera.far = _max.z; - }, + shadowCamera.updateProjectionMatrix(); - // Catmull-Rom + } - interpolate: function( p0, p1, p2, p3, t ) { + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use for shadow maps - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + function getObjectMaterial( object ) { - } + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; }; +// File:src/renderers/webgl/plugins/SpritePlugin.js -// TODO: Transformation for Curves? +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ -/************************************************************** - * 3D Curves - **************************************************************/ +THREE.SpritePlugin = function ( renderer, sprites ) { -// A Factory method for creating new curve subclasses + var gl = renderer.context; -THREE.Curve.create = function ( constructor, getPointFunc ) { + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; - constructor.prototype = Object.create( THREE.Curve.prototype ); - constructor.prototype.getPoint = getPointFunc; + var texture; - return constructor; + // decompose matrixWorld -}; + var spritePosition = new THREE.Vector3(); + var spriteRotation = new THREE.Quaternion(); + var spriteScale = new THREE.Vector3(); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ + var init = function () { -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ + var vertices = new Float32Array( [ + - 0.5, - 0.5, 0, 0, + 0.5, - 0.5, 1, 0, + 0.5, 0.5, 1, 1, + - 0.5, 0.5, 0, 1 + ] ); -THREE.CurvePath = function () { + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - this.curves = []; - this.bends = []; + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - this.autoClose = false; // Automatically closes the path -}; + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); -THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); -THREE.CurvePath.prototype.add = function ( curve ) { + program = createProgram(); - this.curves.push( curve ); + attributes = { + position: gl.getAttribLocation ( program, 'position' ), + uv: gl.getAttribLocation ( program, 'uv' ) + }; -}; + uniforms = { + uvOffset: gl.getUniformLocation( program, 'uvOffset' ), + uvScale: gl.getUniformLocation( program, 'uvScale' ), -THREE.CurvePath.prototype.checkConnection = function() { - // TODO - // If the ending of curve is not connected to the starting - // or the next curve, then, this is not a real path -}; + rotation: gl.getUniformLocation( program, 'rotation' ), + scale: gl.getUniformLocation( program, 'scale' ), -THREE.CurvePath.prototype.closePath = function() { - // TODO Test - // and verify for vector3 (needs to implement equals) - // Add a line curve if start and end of lines are not connected - var startPoint = this.curves[0].getPoint(0); - var endPoint = this.curves[this.curves.length-1].getPoint(1); + color: gl.getUniformLocation( program, 'color' ), + map: gl.getUniformLocation( program, 'map' ), + opacity: gl.getUniformLocation( program, 'opacity' ), - if (!startPoint.equals(endPoint)) { - this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); - } + modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), + projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), -}; + fogType: gl.getUniformLocation( program, 'fogType' ), + fogDensity: gl.getUniformLocation( program, 'fogDensity' ), + fogNear: gl.getUniformLocation( program, 'fogNear' ), + fogFar: gl.getUniformLocation( program, 'fogFar' ), + fogColor: gl.getUniformLocation( program, 'fogColor' ), -// To get accurate point with reference to -// entire path distance at time t, -// following has to be done: + alphaTest: gl.getUniformLocation( program, 'alphaTest' ) + }; -// 1. Length of each sub path have to be known -// 2. Locate and identify type of curve -// 3. Get t for the curve -// 4. Return curve.getPointAt(t') + var canvas = document.createElement( 'canvas' ); + canvas.width = 8; + canvas.height = 8; -THREE.CurvePath.prototype.getPoint = function( t ) { + var context = canvas.getContext( '2d' ); + context.fillStyle = 'white'; + context.fillRect( 0, 0, 8, 8 ); - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0, diff, curve; + texture = new THREE.Texture( canvas ); + texture.needsUpdate = true; - // To think about boundaries points. + }; - while ( i < curveLengths.length ) { + this.render = function ( scene, camera ) { - if ( curveLengths[ i ] >= d ) { + if ( sprites.length === 0 ) return; - diff = curveLengths[ i ] - d; - curve = this.curves[ i ]; + // setup gl - var u = 1 - diff / curve.getLength(); + if ( program === undefined ) { - return curve.getPointAt( u ); + init(); - break; } - i ++; - - } + gl.useProgram( program ); - return null; + gl.enableVertexAttribArray( attributes.position ); + gl.enableVertexAttribArray( attributes.uv ); - // loop where sum != 0, sum > d , sum+1 <d + gl.disable( gl.CULL_FACE ); + gl.enable( gl.BLEND ); -}; + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); + gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); -/* -THREE.CurvePath.prototype.getTangent = function( t ) { -};*/ + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); -// We cannot use the default THREE.Curve getPoint() with getLength() because in -// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath -// getPoint() depends on getLength + gl.activeTexture( gl.TEXTURE0 ); + gl.uniform1i( uniforms.map, 0 ); -THREE.CurvePath.prototype.getLength = function() { + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; - var lens = this.getCurveLengths(); - return lens[ lens.length - 1 ]; + if ( fog ) { -}; + gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); -// Compute lengths and cache them -// We cannot overwrite getLengths() because UtoT mapping uses it. + if ( fog instanceof THREE.Fog ) { -THREE.CurvePath.prototype.getCurveLengths = function() { + gl.uniform1f( uniforms.fogNear, fog.near ); + gl.uniform1f( uniforms.fogFar, fog.far ); - // We use cache values if curves and cache array are same length + gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; - if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) { + } else if ( fog instanceof THREE.FogExp2 ) { - return this.cacheLengths; + gl.uniform1f( uniforms.fogDensity, fog.density ); - }; + gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; - // Get length of subsurve - // Push sums into cached array + } - var lengths = [], sums = 0; - var i, il = this.curves.length; + } else { - for ( i = 0; i < il; i ++ ) { + gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; - sums += this.curves[ i ].getLength(); - lengths.push( sums ); + } - } - this.cacheLengths = lengths; + // update positions and sort - return lengths; + for ( var i = 0, l = sprites.length; i < l; i ++ ) { -}; + var sprite = sprites[ i ]; + sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + } -// Returns min and max coordinates, as well as centroid + sprites.sort( painterSortStable ); -THREE.CurvePath.prototype.getBoundingBox = function () { + // render all sprites - var points = this.getPoints(); + var scale = []; - var maxX, maxY, maxZ; - var minX, minY, minZ; + for ( var i = 0, l = sprites.length; i < l; i ++ ) { - maxX = maxY = Number.NEGATIVE_INFINITY; - minX = minY = Number.POSITIVE_INFINITY; + var sprite = sprites[ i ]; + var material = sprite.material; - var p, i, il, sum; + gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); - var v3 = points[0] instanceof THREE.Vector3; + sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); - sum = v3 ? new THREE.Vector3() : new THREE.Vector2(); + scale[ 0 ] = spriteScale.x; + scale[ 1 ] = spriteScale.y; - for ( i = 0, il = points.length; i < il; i ++ ) { + var fogType = 0; - p = points[ i ]; + if ( scene.fog && material.fog ) { - if ( p.x > maxX ) maxX = p.x; - else if ( p.x < minX ) minX = p.x; + fogType = sceneFogType; - if ( p.y > maxY ) maxY = p.y; - else if ( p.y < minY ) minY = p.y; + } - if ( v3 ) { + if ( oldFogType !== fogType ) { - if ( p.z > maxZ ) maxZ = p.z; - else if ( p.z < minZ ) minZ = p.z; + gl.uniform1i( uniforms.fogType, fogType ); + oldFogType = fogType; - } + } - sum.add( p ); + if ( material.map !== null ) { - } + gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); + gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); - var ret = { + } else { - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY, - centroid: sum.divideScalar( il ) + gl.uniform2f( uniforms.uvOffset, 0, 0 ); + gl.uniform2f( uniforms.uvScale, 1, 1 ); - }; + } - if ( v3 ) { + gl.uniform1f( uniforms.opacity, material.opacity ); + gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); - ret.maxZ = maxZ; - ret.minZ = minZ; + gl.uniform1f( uniforms.rotation, material.rotation ); + gl.uniform2fv( uniforms.scale, scale ); - } + renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + renderer.state.setDepthTest( material.depthTest ); + renderer.state.setDepthWrite( material.depthWrite ); - return ret; + if ( material.map && material.map.image && material.map.image.width ) { -}; + renderer.setTexture( material.map, 0 ); -/************************************************************** - * Create Geometries Helpers - **************************************************************/ + } else { -/// Generate geometry from path points (for Line or ParticleSystem objects) + renderer.setTexture( texture, 0 ); -THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + } - var pts = this.getPoints( divisions, true ); - return this.createGeometry( pts ); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); -}; + } -// Generate geometry from equidistance sampling along the path + // restore gl -THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { + gl.enable( gl.CULL_FACE ); - var pts = this.getSpacedPoints( divisions, true ); - return this.createGeometry( pts ); + renderer.resetGLState(); -}; + }; -THREE.CurvePath.prototype.createGeometry = function( points ) { + function createProgram () { - var geometry = new THREE.Geometry(); + var program = gl.createProgram(); - for ( var i = 0; i < points.length; i ++ ) { + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); - geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); + gl.shaderSource( vertexShader, [ - } + 'precision ' + renderer.getPrecision() + ' float;', - return geometry; + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform float rotation;', + 'uniform vec2 scale;', + 'uniform vec2 uvOffset;', + 'uniform vec2 uvScale;', -}; + 'attribute vec2 position;', + 'attribute vec2 uv;', + 'varying vec2 vUV;', -/************************************************************** - * Bend / Wrap Helper Methods - **************************************************************/ + 'void main() {', -// Wrap path / Bend modifiers? + 'vUV = uvOffset + uv * uvScale;', -THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + 'vec2 alignedPosition = position * scale;', - this.bends.push( bendpath ); + 'vec2 rotatedPosition;', + 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', + 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', -}; + 'vec4 finalPosition;', -THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { + 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', + 'finalPosition.xy += rotatedPosition;', + 'finalPosition = projectionMatrix * finalPosition;', - var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints - var i, il; + 'gl_Position = finalPosition;', - if ( !bends ) { + '}' - bends = this.bends; + ].join( '\n' ) ); - } + gl.shaderSource( fragmentShader, [ - for ( i = 0, il = bends.length; i < il; i ++ ) { + 'precision ' + renderer.getPrecision() + ' float;', - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + 'uniform vec3 color;', + 'uniform sampler2D map;', + 'uniform float opacity;', - } + 'uniform int fogType;', + 'uniform vec3 fogColor;', + 'uniform float fogDensity;', + 'uniform float fogNear;', + 'uniform float fogFar;', + 'uniform float alphaTest;', - return oldPts; + 'varying vec2 vUV;', -}; + 'void main() {', -THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { + 'vec4 texture = texture2D( map, vUV );', - var oldPts = this.getSpacedPoints( segments ); + 'if ( texture.a < alphaTest ) discard;', - var i, il; + 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', - if ( !bends ) { + 'if ( fogType > 0 ) {', - bends = this.bends; + 'float depth = gl_FragCoord.z / gl_FragCoord.w;', + 'float fogFactor = 0.0;', - } + 'if ( fogType == 1 ) {', - for ( i = 0, il = bends.length; i < il; i ++ ) { + 'fogFactor = smoothstep( fogNear, fogFar, depth );', - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + '} else {', - } + 'const float LOG2 = 1.442695;', + 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', + 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', - return oldPts; + '}', -}; + 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', -// This returns getPoints() bend/wrapped around the contour of a path. -// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html + '}', -THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { + '}' - var bounds = this.getBoundingBox(); + ].join( '\n' ) ); - var i, il, p, oldX, oldY, xNorm; + gl.compileShader( vertexShader ); + gl.compileShader( fragmentShader ); - for ( i = 0, il = oldPts.length; i < il; i ++ ) { + gl.attachShader( program, vertexShader ); + gl.attachShader( program, fragmentShader ); - p = oldPts[ i ]; + gl.linkProgram( program ); - oldX = p.x; - oldY = p.y; + return program; - xNorm = oldX / bounds.maxX; + }; - // If using actual distance, for length > path, requires line extrusions - //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance + function painterSortStable ( a, b ) { - xNorm = path.getUtoTmapping( xNorm, oldX ); + if ( a.z !== b.z ) { - // check for out of bounds? + return b.z - a.z; - var pathPt = path.getPoint( xNorm ); - var normal = path.getNormalVector( xNorm ).multiplyScalar( oldY ); + } else { - p.x = pathPt.x + normal.x; - p.y = pathPt.y + normal.y; + return b.id - a.id; - } + } - return oldPts; + }; }; +// File:src/extras/GeometryUtils.js /** - * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ */ -THREE.Gyroscope = function () { +THREE.GeometryUtils = { - THREE.Object3D.call( this ); + merge: function ( geometry1, geometry2, materialIndexOffset ) { -}; + THREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); -THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); + var matrix; -THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { + if ( geometry2 instanceof THREE.Mesh ) { - this.matrixAutoUpdate && this.updateMatrix(); + geometry2.matrixAutoUpdate && geometry2.updateMatrix(); - // update matrixWorld + matrix = geometry2.matrix; + geometry2 = geometry2.geometry; - if ( this.matrixWorldNeedsUpdate || force ) { + } - if ( this.parent ) { + geometry1.merge( geometry2, matrix, materialIndexOffset ); - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + }, - this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); - this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); + center: function ( geometry ) { - this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); + THREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + return geometry.center(); + } - } else { +}; - this.matrixWorld.copy( this.matrix ); +// File:src/extras/ImageUtils.js - } +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author Daosheng Mu / https://github.com/DaoshengMu/ + */ +THREE.ImageUtils = { - this.matrixWorldNeedsUpdate = false; + crossOrigin: undefined, - force = true; + loadTexture: function ( url, mapping, onLoad, onError ) { - } + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; - // update children + var texture = new THREE.Texture( undefined, mapping ); - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + loader.load( url, function ( image ) { - this.children[ i ].updateMatrixWorld( force ); + texture.image = image; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); -}; + }, undefined, function ( event ) { -THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); -THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); -THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); -THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); + if ( onError ) onError( event ); + } ); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - * - **/ + texture.sourceFile = url; -THREE.Path = function ( points ) { + return texture; - THREE.CurvePath.call(this); + }, - this.actions = []; + loadTextureCube: function ( array, mapping, onLoad, onError ) { - if ( points ) { + var images = []; - this.fromPoints( points ); + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; - } + var texture = new THREE.CubeTexture( images, mapping ); -}; + // no flipping needed for cube textures -THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); + texture.flipY = false; -THREE.PathActions = { + var loaded = 0; - MOVE_TO: 'moveTo', - LINE_TO: 'lineTo', - QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve - BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve - CSPLINE_THRU: 'splineThru', // Catmull-rom spline - ARC: 'arc', // Circle - ELLIPSE: 'ellipse' -}; + var loadTexture = function ( i ) { -// TODO Clean up PATH API + loader.load( array[ i ], function ( image ) { -// Create path using straight lines to connect all points -// - vectors: array of Vector2 + texture.images[ i ] = image; -THREE.Path.prototype.fromPoints = function ( vectors ) { + loaded += 1; - this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + if ( loaded === 6 ) { - for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { + texture.needsUpdate = true; - this.lineTo( vectors[ v ].x, vectors[ v ].y ); + if ( onLoad ) onLoad( texture ); - }; + } -}; + }, undefined, onError ); -// startPath() endPath()? + } -THREE.Path.prototype.moveTo = function ( x, y ) { + for ( var i = 0, il = array.length; i < il; ++ i ) { - var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); + loadTexture( i ); -}; + } -THREE.Path.prototype.lineTo = function ( x, y ) { + return texture; - var args = Array.prototype.slice.call( arguments ); + }, - var lastargs = this.actions[ this.actions.length - 1 ].args; + loadCompressedTexture: function () { - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) - var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); - this.curves.push( curve ); + }, - this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); + loadCompressedTextureCube: function () { -}; + THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) -THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + }, - var args = Array.prototype.slice.call( arguments ); + getNormalMap: function ( image, depth ) { - var lastargs = this.actions[ this.actions.length - 1 ].args; + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + var cross = function ( a, b ) { - var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCPx, aCPy ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); + return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; - this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); + } -}; + var subtract = function ( a, b ) { -THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY ) { + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; - var args = Array.prototype.slice.call( arguments ); + } - var lastargs = this.actions[ this.actions.length - 1 ].args; + var normalize = function ( a ) { - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); + return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; - var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCP1x, aCP1y ), - new THREE.Vector2( aCP2x, aCP2y ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); + } - this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + depth = depth | 1; -}; + var width = image.width; + var height = image.height; -THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - var args = Array.prototype.slice.call( arguments ); - var lastargs = this.actions[ this.actions.length - 1 ].args; + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0 ); - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; -//--- - var npts = [ new THREE.Vector2( x0, y0 ) ]; - Array.prototype.push.apply( npts, pts ); + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; - var curve = new THREE.SplineCurve( npts ); - this.curves.push( curve ); + for ( var x = 0; x < width; x ++ ) { - this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + for ( var y = 0; y < height; y ++ ) { -}; + var ly = y - 1 < 0 ? 0 : y - 1; + var uy = y + 1 > height - 1 ? height - 1 : y + 1; + var lx = x - 1 < 0 ? 0 : x - 1; + var ux = x + 1 > width - 1 ? width - 1 : x + 1; -// FUTURE: Change the API or follow canvas API? + var points = []; + var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; + points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); -THREE.Path.prototype.arc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { + var normals = []; + var num_points = points.length; - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + for ( var i = 0; i < num_points; i ++ ) { + + var v1 = points[ i ]; + var v2 = points[ ( i + 1 ) % num_points ]; + v1 = subtract( v1, origin ); + v2 = subtract( v2, origin ); + normals.push( normalize( cross( v1, v2 ) ) ); + + } - this.absarc(aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + var normal = [ 0, 0, 0 ]; - }; + for ( var i = 0; i < normals.length; i ++ ) { - THREE.Path.prototype.absarc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); - }; + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; -THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { + } - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; - this.absellipse(aX + x0, aY + y0, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); + 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 + 2 ] = ( normal[ 2 ] * 255 ) | 0; + output[ idx + 3 ] = 255; + } -THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { + } - var args = Array.prototype.slice.call( arguments ); - var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - this.curves.push( curve ); + context.putImageData( imageData, 0, 0 ); - var lastPoint = curve.getPoint(1); - args.push(lastPoint.x); - args.push(lastPoint.y); + return canvas; - this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); + }, - }; + generateDataTexture: function ( width, height, color ) { -THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { + var size = width * height; + var data = new Uint8Array( 3 * size ); - if ( ! divisions ) divisions = 40; + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); - var points = []; + for ( var i = 0; i < size; i ++ ) { - for ( var i = 0; i < divisions; i ++ ) { + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; - points.push( this.getPoint( i / divisions ) ); + } - //if( !this.getPoint( i / divisions ) ) throw "DIE"; + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; + + return texture; } - // if ( closedPath ) { - // - // points.push( points[ 0 ] ); - // - // } +}; - return points; +// File:src/extras/SceneUtils.js -}; +/** + * @author alteredq / http://alteredqualia.com/ + */ -/* Return an array of vectors based on contour of the path */ +THREE.SceneUtils = { -THREE.Path.prototype.getPoints = function( divisions, closedPath ) { + createMultiMaterialObject: function ( geometry, materials ) { - if (this.useSpacedPoints) { - console.log('tata'); - return this.getSpacedPoints( divisions, closedPath ); - } + var group = new THREE.Object3D(); - divisions = divisions || 12; + for ( var i = 0, l = materials.length; i < l; i ++ ) { - var points = []; + group.add( new THREE.Mesh( geometry, materials[ i ] ) ); - var i, il, item, action, args; - var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, - laste, j, - t, tx, ty; + } - for ( i = 0, il = this.actions.length; i < il; i ++ ) { + return group; - item = this.actions[ i ]; + }, - action = item.action; - args = item.args; + detach: function ( child, parent, scene ) { - switch( action ) { + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); - case THREE.PathActions.MOVE_TO: + }, - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + attach: function ( child, scene, parent ) { - break; + var matrixWorldInverse = new THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); - case THREE.PathActions.LINE_TO: + scene.remove( child ); + parent.add( child ); - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + } - break; +}; - case THREE.PathActions.QUADRATIC_CURVE_TO: +// File:src/extras/FontUtils.js - cpx = args[ 2 ]; - cpy = args[ 3 ]; +/** + * @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/ + * + */ - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; +THREE.FontUtils = { - if ( points.length > 0 ) { + faces: {}, - laste = points[ points.length - 1 ]; + // Just for now. face[weight][style] - cpx0 = laste.x; - cpy0 = laste.y; + face: 'helvetiker', + weight: 'normal', + style: 'normal', + size: 150, + divisions: 10, - } else { + getFace: function () { - laste = this.actions[ i - 1 ].args; + try { - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; + return this.faces[ this.face ][ this.weight ][ this.style ]; - } + } catch (e) { - for ( j = 1; j <= divisions; j ++ ) { + throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." - t = j / divisions; + }; - tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + }, - points.push( new THREE.Vector2( tx, ty ) ); + loadFace: function ( data ) { - } + var family = data.familyName.toLowerCase(); - break; + var ThreeFont = this; - case THREE.PathActions.BEZIER_CURVE_TO: + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; - cpx = args[ 4 ]; - cpy = args[ 5 ]; + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - cpx2 = args[ 2 ]; - cpy2 = args[ 3 ]; + return data; - if ( points.length > 0 ) { + }, - laste = points[ points.length - 1 ]; + drawText: function ( text ) { - cpx0 = laste.x; - cpy0 = laste.y; + // RenderText - } else { + var i, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; - laste = this.actions[ i - 1 ].args; + var fontPaths = []; - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; + for ( i = 0; i < length; i ++ ) { - } + var path = new THREE.Path(); + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; - for ( j = 1; j <= divisions; j ++ ) { + fontPaths.push( ret.path ); - t = j / divisions; + } - tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + // get the width - points.push( new THREE.Vector2( tx, ty ) ); + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } - } + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; - break; + //extract.paths = fontPaths; + //extract.offset = width; - case THREE.PathActions.CSPLINE_THRU: + return { paths: fontPaths, offset: width }; - laste = this.actions[ i - 1 ].args; + }, - var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); - var spts = [ last ]; - var n = divisions * args[ 0 ].length; - spts = spts.concat( args[ 0 ] ); - var spline = new THREE.SplineCurve( spts ); + extractGlyphPoints: function ( c, face, scale, offset, path ) { - for ( j = 1; j <= n; j ++ ) { + var pts = []; - points.push( spline.getPointAt( j / n ) ) ; + 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; - break; + if ( glyph.o ) { - case THREE.PathActions.ARC: + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; - var aX = args[ 0 ], aY = args[ 1 ], - aRadius = args[ 2 ], - aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], - aClockwise = !!args[ 5 ]; + scaleX = scale; + scaleY = scale; - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + for ( i = 0; i < length; ) { + + action = outline[ i ++ ]; + + //console.log( action ); - for ( j = 1; j <= tdivisions; j ++ ) { + switch ( action ) { - t = j / tdivisions; + case 'm': - if ( ! aClockwise ) { + // Move To - t = 1 - t; + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; - } + path.moveTo( x, y ); + break; - angle = aStartAngle + t * deltaAngle; + case 'l': - tx = aX + aRadius * Math.cos( angle ); - ty = aY + aRadius * Math.sin( angle ); + // Line To - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; + path.lineTo( x, y ); + break; - points.push( new THREE.Vector2( tx, ty ) ); + case 'q': - } + // QuadraticCurveTo - //console.log(points); + cpx = outline[ i ++ ] * scaleX + offset; + cpy = outline[ i ++ ] * scaleY; + cpx1 = outline[ i ++ ] * scaleX + offset; + cpy1 = outline[ i ++ ] * scaleY; - break; + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - case THREE.PathActions.ELLIPSE: + laste = pts[ pts.length - 1 ]; - var aX = args[ 0 ], aY = args[ 1 ], - xRadius = args[ 2 ], - yRadius = args[ 3 ], - aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], - aClockwise = !!args[ 6 ]; + if ( laste ) { + cpx0 = laste.x; + cpy0 = laste.y; - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - for ( j = 1; j <= tdivisions; j ++ ) { + var t = i2 / divisions; + THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } - t = j / tdivisions; + } - if ( ! aClockwise ) { + break; - t = 1 - t; + case 'b': - } + // Cubic Bezier Curve - angle = aStartAngle + t * deltaAngle; + 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; - tx = aX + xRadius * Math.cos( angle ); - ty = aY + yRadius * Math.sin( angle ); + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + laste = pts[ pts.length - 1 ]; - points.push( new THREE.Vector2( tx, ty ) ); + if ( laste ) { - } + cpx0 = laste.x; + cpy0 = laste.y; - //console.log(points); + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - break; + var t = i2 / divisions; + THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - } // end switch + } - } + } + + break; + } + } + } - // Normalize to remove the closing point by default. - var lastPoint = points[ points.length - 1]; - var EPSILON = 0.0000000001; - if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && - Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) - points.splice( points.length - 1, 1); - if ( closedPath ) { - points.push( points[ 0 ] ); + return { offset: glyph.ha * scale, path:path }; } - return points; - }; -// Breaks path into shapes -THREE.Path.prototype.toShapes = function( isCCW ) { +THREE.FontUtils.generateShapes = function ( text, parameters ) { - var i, il, item, action, args; + // Parameters - var subPaths = [], lastPath = new THREE.Path(); + parameters = parameters || {}; - for ( i = 0, il = this.actions.length; i < il; i ++ ) { + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; - item = this.actions[ i ]; + var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; + var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; + var style = parameters.style !== undefined ? parameters.style : 'normal'; - args = item.args; - action = item.action; + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; - if ( action == THREE.PathActions.MOVE_TO ) { + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; - if ( lastPath.actions.length != 0 ) { + // Get a Font data json object - subPaths.push( lastPath ); - lastPath = new THREE.Path(); + var data = THREE.FontUtils.drawText( text ); - } + var paths = data.paths; + var shapes = []; - } + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - lastPath[ action ].apply( lastPath, args ); + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); } - if ( lastPath.actions.length != 0 ) { + return shapes; + +}; - subPaths.push( lastPath ); - } +/** + * 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 + * + */ - // console.log(subPaths); - if ( subPaths.length == 0 ) return []; +( function ( namespace ) { - var solid, tmpPath, tmpShape, shapes = []; + var EPSILON = 0.0000000001; - if ( subPaths.length == 1) { + // takes in an contour array and returns - tmpPath = subPaths[0]; - tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; + var process = function ( contour, indices ) { - } + var n = contour.length; - var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? !holesFirst : holesFirst; + if ( n < 3 ) return null; - // console.log("Holes first", holesFirst); + var result = [], + verts = [], + vertIndices = []; - if ( holesFirst ) { + /* we want a counter-clockwise polygon in verts */ - tmpShape = new THREE.Shape(); + var u, v, w; - for ( i = 0, il = subPaths.length; i < il; i ++ ) { + if ( area( contour ) > 0.0 ) { - tmpPath = subPaths[ i ]; - solid = THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ); - solid = isCCW ? !solid : solid; + for ( v = 0; v < n; v ++ ) verts[ v ] = v; - if ( solid ) { + } else { - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; + for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; - shapes.push( tmpShape ); - tmpShape = new THREE.Shape(); + } - //console.log('cw', i); + var nv = n; - } else { + /* remove nv - 2 vertices, creating 1 triangle every time */ - tmpShape.holes.push( tmpPath ); + var count = 2 * nv; /* error detection */ - //console.log('ccw', i); + for ( v = nv - 1; nv > 2; ) { - } + /* if we loop, it is probably a non-simple polygon */ - } + if ( ( count -- ) <= 0 ) { - } else { + //** Triangulate: ERROR - probable bad polygon! - // Shapes first - tmpShape = undefined; + //throw ( "Warning, unable to triangulate polygon!" ); + //return null; + // Sometimes warning is fine, especially polygons are triangulated in reverse. + THREE.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); - for ( i = 0, il = subPaths.length; i < il; i ++ ) { + if ( indices ) return vertIndices; + return result; - tmpPath = subPaths[ i ]; - solid = THREE.Shape.Utils.isClockWise( tmpPath.getPoints() ); - solid = isCCW ? !solid : solid; + } - if ( solid ) { + /* three consecutive vertices in current polygon, <u,v,w> */ - if ( tmpShape ) shapes.push( tmpShape ); + 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 */ - tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; + if ( snip( contour, u, v, w, nv, verts ) ) { - } else { + var a, b, c, s, t; - tmpShape.holes.push( tmpPath ); + /* true names of the vertices */ - } + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; - } + /* output Triangle */ - shapes.push( tmpShape ); + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); - } - //console.log("shape", shapes); + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); - return shapes; + /* remove v from the remaining polygon */ -}; + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + verts[ s ] = verts[ t ]; -// STEP 1 Create a path. -// STEP 2 Turn path into shape. -// STEP 3 ExtrudeGeometry takes in Shape/Shapes -// STEP 3a - Extract points from each shape, turn to vertices -// STEP 3b - Triangulate each shape, add faces. + } -THREE.Shape = function () { + nv --; - THREE.Path.apply( this, arguments ); - this.holes = []; + /* reset error detection counter */ -}; + count = 2 * nv; -THREE.Shape.prototype = Object.create( THREE.Path.prototype ); + } -// Convenience method to return ExtrudeGeometry + } -THREE.Shape.prototype.extrude = function ( options ) { + if ( indices ) return vertIndices; + return result; - var extruded = new THREE.ExtrudeGeometry( this, options ); - return extruded; + }; -}; + // calculate area of the contour polygon -// Convenience method to return ShapeGeometry + var area = function ( contour ) { -THREE.Shape.prototype.makeGeometry = function ( options ) { + var n = contour.length; + var a = 0.0; - var geometry = new THREE.ShapeGeometry( this, options ); - return geometry; + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { -}; + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; -// Get points of holes + } -THREE.Shape.prototype.getPointsHoles = function ( divisions ) { + return a * 0.5; - var i, il = this.holes.length, holesPts = []; + }; - for ( i = 0; i < il; i ++ ) { + var snip = function ( contour, u, v, w, n, verts ) { - holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); + var p; + var ax, ay, bx, by; + var cx, cy, px, py; - } + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; - return holesPts; + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; -}; + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; -// Get points of holes (spaced by regular distance) + if ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false; -THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { + var aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; - var i, il = this.holes.length, holesPts = []; + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; - for ( i = 0; i < il; i ++ ) { + for ( p = 0; p < n; p ++ ) { + + px = contour[ verts[ p ] ].x + py = contour[ verts[ p ] ].y + + if ( ( ( px === ax ) && ( py === ay ) ) || + ( ( px === bx ) && ( py === by ) ) || + ( ( px === cx ) && ( py === cy ) ) ) continue; + + apx = px - ax; apy = py - ay; + bpx = px - bx; bpy = py - by; + cpx = px - cx; cpy = py - cy; - holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); + // see if p is inside triangle abc - } + aCROSSbp = aX * bpy - aY * bpx; + cCROSSap = cX * apy - cY * apx; + bCROSScp = bX * cpy - bY * cpx; - return holesPts; + if ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false; -}; + } + return true; -// Get points of shape and holes (keypoints based on segments parameter) + }; -THREE.Shape.prototype.extractAllPoints = function ( divisions ) { - return { + namespace.Triangulate = process; + namespace.Triangulate.area = area; - shape: this.getTransformedPoints( divisions ), - holes: this.getPointsHoles( divisions ) + 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.typeface_js = self._typeface_js; -THREE.Shape.prototype.extractPoints = function ( divisions ) { +// File:src/extras/audio/Audio.js - if (this.useSpacedPoints) { - return this.extractAllSpacedPoints(divisions); - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - return this.extractAllPoints(divisions); +THREE.Audio = function ( listener ) { -}; + THREE.Object3D.call( this ); -// -// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { -// -// return { -// -// shape: this.transform( bend, divisions ), -// holes: this.getPointsHoles( divisions, bend ) -// -// }; -// -// }; + this.type = 'Audio'; -// Get points of shape and holes (spaced by regular distance) + this.context = listener.context; + this.source = this.context.createBufferSource(); + this.source.onended = this.onEnded.bind(this); -THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - return { + this.panner = this.context.createPanner(); + this.panner.connect( this.gain ); - shape: this.getTransformedSpacedPoints( divisions ), - holes: this.getSpacedPointsHoles( divisions ) + this.autoplay = false; - }; + this.startTime = 0; + this.isPlaying = false; }; -/************************************************************** - * Utils - **************************************************************/ +THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Audio.prototype.constructor = THREE.Audio; -THREE.Shape.Utils = { +THREE.Audio.prototype.load = function ( file ) { - /* - contour - array of vector2 for contour - holes - array of array of vector2 - */ + var scope = this; + + var request = new XMLHttpRequest(); + request.open( 'GET', file, true ); + request.responseType = 'arraybuffer'; + request.onload = function ( e ) { - removeHoles: function ( contour, holes ) { + scope.context.decodeAudioData( this.response, function ( buffer ) { - var shape = contour.concat(); // work on this shape - var allpoints = shape.concat(); + scope.source.buffer = buffer; - /* For each isolated shape, find the closest points and break to the hole to allow triangulation */ + if( scope.autoplay ) scope.play(); + } ); - var prevShapeVert, nextShapeVert, - prevHoleVert, nextHoleVert, - holeIndex, shapeIndex, - shapeId, shapeGroup, - h, h2, - hole, shortest, d, - p, pts1, pts2, - tmpShape1, tmpShape2, - tmpHole1, tmpHole2, - verts = []; + }; + request.send(); - for ( h = 0; h < holes.length; h ++ ) { + return this; - hole = holes[ h ]; +}; - /* - shapeholes[ h ].concat(); // preserves original - holes.push( hole ); - */ +THREE.Audio.prototype.play = function () { - Array.prototype.push.apply( allpoints, hole ); + if ( this.isPlaying === true ) { - shortest = Number.POSITIVE_INFINITY; + THREE.warn( 'THREE.Audio: Audio is already playing.' ); + return; + } - // Find the shortest pair of pts between shape and hole + var source = this.context.createBufferSource(); - // Note: Actually, I'm not sure now if we could optimize this to be faster than O(m*n) - // Using distanceToSquared() intead of distanceTo() should speed a little - // since running square roots operations are reduced. + source.buffer = this.source.buffer; + source.loop = this.source.loop; + source.onended = this.source.onended; + source.connect( this.panner ); + source.start( 0, this.startTime ); - for ( h2 = 0; h2 < hole.length; h2 ++ ) { + this.isPlaying = true; - pts1 = hole[ h2 ]; - var dist = []; + this.source = source; - for ( p = 0; p < shape.length; p++ ) { +}; - pts2 = shape[ p ]; - d = pts1.distanceToSquared( pts2 ); - dist.push( d ); +THREE.Audio.prototype.pause = function () { - if ( d < shortest ) { + this.source.stop(); + this.startTime = this.context.currentTime; - shortest = d; - holeIndex = h2; - shapeIndex = p; +}; - } +THREE.Audio.prototype.stop = function () { - } + this.source.stop(); + this.startTime = 0; - } +}; - //console.log("shortest", shortest, dist); +THREE.Audio.prototype.onEnded = function() { - prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; - prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; + this.isPlaying = false; - var areaapts = [ +}; - hole[ holeIndex ], - shape[ shapeIndex ], - shape[ prevShapeVert ] +THREE.Audio.prototype.setLoop = function ( value ) { - ]; + this.source.loop = value; - var areaa = THREE.FontUtils.Triangulate.area( areaapts ); +}; - var areabpts = [ +THREE.Audio.prototype.setRefDistance = function ( value ) { - hole[ holeIndex ], - hole[ prevHoleVert ], - shape[ shapeIndex ] + this.panner.refDistance = value; - ]; +}; - var areab = THREE.FontUtils.Triangulate.area( areabpts ); +THREE.Audio.prototype.setRolloffFactor = function ( value ) { - var shapeOffset = 1; - var holeOffset = -1; + this.panner.rolloffFactor = value; - var oldShapeIndex = shapeIndex, oldHoleIndex = holeIndex; - shapeIndex += shapeOffset; - holeIndex += holeOffset; +}; - if ( shapeIndex < 0 ) { shapeIndex += shape.length; } - shapeIndex %= shape.length; +THREE.Audio.prototype.setVolume = function ( value ) { - if ( holeIndex < 0 ) { holeIndex += hole.length; } - holeIndex %= hole.length; + this.gain.gain.value = value; - prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; - prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; +}; - areaapts = [ +THREE.Audio.prototype.updateMatrixWorld = ( function () { - hole[ holeIndex ], - shape[ shapeIndex ], - shape[ prevShapeVert ] + var position = new THREE.Vector3(); - ]; + return function ( force ) { - var areaa2 = THREE.FontUtils.Triangulate.area( areaapts ); + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); - areabpts = [ + position.setFromMatrixPosition( this.matrixWorld ); - hole[ holeIndex ], - hole[ prevHoleVert ], - shape[ shapeIndex ] + this.panner.setPosition( position.x, position.y, position.z ); - ]; + }; - var areab2 = THREE.FontUtils.Triangulate.area( areabpts ); - //console.log(areaa,areab ,areaa2,areab2, ( areaa + areab ), ( areaa2 + areab2 )); +} )(); - if ( ( areaa + areab ) > ( areaa2 + areab2 ) ) { +// File:src/extras/audio/AudioListener.js - // In case areas are not correct. - //console.log("USE THIS"); +/** + * @author mrdoob / http://mrdoob.com/ + */ - shapeIndex = oldShapeIndex; - holeIndex = oldHoleIndex ; +THREE.AudioListener = function () { - if ( shapeIndex < 0 ) { shapeIndex += shape.length; } - shapeIndex %= shape.length; + THREE.Object3D.call( this ); - if ( holeIndex < 0 ) { holeIndex += hole.length; } - holeIndex %= hole.length; + this.type = 'AudioListener'; - prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1; - prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1; + this.context = new ( window.AudioContext || window.webkitAudioContext )(); - } else { +}; - //console.log("USE THAT ") +THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype ); +THREE.AudioListener.prototype.constructor = THREE.AudioListener; - } +THREE.AudioListener.prototype.updateMatrixWorld = ( function () { - tmpShape1 = shape.slice( 0, shapeIndex ); - tmpShape2 = shape.slice( shapeIndex ); - tmpHole1 = hole.slice( holeIndex ); - tmpHole2 = hole.slice( 0, holeIndex ); + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3(); - // Should check orders here again? + var orientation = new THREE.Vector3(); + var velocity = new THREE.Vector3(); - var trianglea = [ + var positionPrev = new THREE.Vector3(); - hole[ holeIndex ], - shape[ shapeIndex ], - shape[ prevShapeVert ] + return function ( force ) { - ]; + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); - var triangleb = [ + var listener = this.context.listener; + var up = this.up; - hole[ holeIndex ] , - hole[ prevHoleVert ], - shape[ shapeIndex ] + this.matrixWorld.decompose( position, quaternion, scale ); - ]; + orientation.set( 0, 0, -1 ).applyQuaternion( quaternion ); + velocity.subVectors( position, positionPrev ); - verts.push( trianglea ); - verts.push( triangleb ); + listener.setPosition( position.x, position.y, position.z ); + listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); + listener.setVelocity( velocity.x, velocity.y, velocity.z ); - shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); + positionPrev.copy( position ); - } + }; - return { +} )(); - shape:shape, /* shape with no holes */ - isolatedPts: verts, /* isolated faces */ - allpoints: allpoints +// File:src/extras/core/Curve.js - } +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTagentAt(u) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following classes subclasses THREE.Curve: + * + * -- 2d classes -- + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.CubicBezierCurve + * THREE.SplineCurve + * THREE.ArcCurve + * THREE.EllipseCurve + * + * -- 3d classes -- + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * THREE.CubicBezierCurve3 + * THREE.SplineCurve3 + * THREE.ClosedSplineCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ +/************************************************************** + * Abstract Curve base class + **************************************************************/ - }, +THREE.Curve = function () { - triangulateShape: function ( contour, holes ) { +}; - var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes ); +// Virtual base class method to overwrite and implement in subclasses +// - t [0 .. 1] - var shape = shapeWithoutHoles.shape, - allpoints = shapeWithoutHoles.allpoints, - isolatedPts = shapeWithoutHoles.isolatedPts; +THREE.Curve.prototype.getPoint = function ( t ) { - var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape + THREE.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); + return null; - // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. +}; - //console.log( "triangles",triangles, triangles.length ); - //console.log( "allpoints",allpoints, allpoints.length ); +// Get point at relative position in curve according to arc length +// - u [0 .. 1] - var i, il, f, face, - key, index, - allPointsMap = {}, - isolatedPointsMap = {}; +THREE.Curve.prototype.getPointAt = function ( u ) { - // prepare all points map + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); - for ( i = 0, il = allpoints.length; i < il; i ++ ) { +}; - key = allpoints[ i ].x + ":" + allpoints[ i ].y; +// Get sequence of points using getPoint( t ) - if ( allPointsMap[ key ] !== undefined ) { +THREE.Curve.prototype.getPoints = function ( divisions ) { - console.log( "Duplicate point", key ); + if ( ! divisions ) divisions = 5; - } + var d, pts = []; - allPointsMap[ key ] = i; + for ( d = 0; d <= divisions; d ++ ) { - } + pts.push( this.getPoint( d / divisions ) ); - // check all face vertices against all points map + } - for ( i = 0, il = triangles.length; i < il; i ++ ) { + return pts; - face = triangles[ i ]; +}; - for ( f = 0; f < 3; f ++ ) { +// Get sequence of points using getPointAt( u ) - key = face[ f ].x + ":" + face[ f ].y; +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { - index = allPointsMap[ key ]; + if ( ! divisions ) divisions = 5; - if ( index !== undefined ) { + var d, pts = []; - face[ f ] = index; + for ( d = 0; d <= divisions; d ++ ) { - } + pts.push( this.getPointAt( d / divisions ) ); - } + } - } + return pts; - // check isolated points vertices against all points map +}; - for ( i = 0, il = isolatedPts.length; i < il; i ++ ) { +// Get total curve arc length - face = isolatedPts[ i ]; +THREE.Curve.prototype.getLength = function () { - for ( f = 0; f < 3; f ++ ) { + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; - key = face[ f ].x + ":" + face[ f ].y; +}; - index = allPointsMap[ key ]; +// Get list of cumulative segment lengths - if ( index !== undefined ) { +THREE.Curve.prototype.getLengths = function ( divisions ) { - face[ f ] = index; + if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; - } + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length == divisions + 1 ) + && ! this.needsUpdate) { - } + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; - } + } - return triangles.concat( isolatedPts ); + this.needsUpdate = false; - }, // end triangulate shapes + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - /* - triangulate2 : function( pts, holes ) { + cache.push( 0 ); - // For use with Poly2Tri.js + for ( p = 1; p <= divisions; p ++ ) { - var allpts = pts.concat(); - var shape = []; - for (var p in pts) { - shape.push(new js.poly2tri.Point(pts[p].x, pts[p].y)); - } + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - var swctx = new js.poly2tri.SweepContext(shape); + } - for (var h in holes) { - var aHole = holes[h]; - var newHole = [] - for (i in aHole) { - newHole.push(new js.poly2tri.Point(aHole[i].x, aHole[i].y)); - allpts.push(aHole[i]); - } - swctx.AddHole(newHole); - } + this.cacheArcLengths = cache; - var find; - var findIndexForPt = function (pt) { - find = new THREE.Vector2(pt.x, pt.y); - var p; - for (p=0, pl = allpts.length; p<pl; p++) { - if (allpts[p].equals(find)) return p; - } - return -1; - }; + return cache; // { sums: cache, sum:sum }; Sum is in the last element. - // triangulate - js.poly2tri.sweep.Triangulate(swctx); +}; - var triangles = swctx.GetTriangles(); - var tr ; - var facesPts = []; - for (var t in triangles) { - tr = triangles[t]; - facesPts.push([ - findIndexForPt(tr.GetPoint(0)), - findIndexForPt(tr.GetPoint(1)), - findIndexForPt(tr.GetPoint(2)) - ]); - } +THREE.Curve.prototype.updateArcLengths = function() { + this.needsUpdate = true; + this.getLengths(); +}; - // console.log(facesPts); - // console.log("triangles", triangles.length, triangles); +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance - // Returns array of faces with 3 element each - return facesPts; - }, -*/ +THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { - isClockWise: function ( pts ) { + var arcLengths = this.getLengths(); - return THREE.FontUtils.Triangulate.area( pts ) < 0; + var i = 0, il = arcLengths.length; - }, + var targetArcLength; // The targeted u distance value to get - // Bezier Curves formulas obtained from - // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + if ( distance ) { - // Quad Bezier Functions + targetArcLength = distance; - b2p0: function ( t, p ) { + } else { - var k = 1 - t; - return k * k * p; + targetArcLength = u * arcLengths[ il - 1 ]; - }, + } - b2p1: function ( t, p ) { + //var time = Date.now(); + + // binary search for the index with largest value smaller than target u distance - return 2 * ( 1 - t ) * t * p; + var low = 0, high = il - 1, comparison; - }, + while ( low <= high ) { - b2p2: function ( t, p ) { + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - return t * t * p; + comparison = arcLengths[ i ] - targetArcLength; - }, + if ( comparison < 0 ) { - b2: function ( t, p0, p1, p2 ) { + low = i + 1; - return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); + } else if ( comparison > 0 ) { - }, + high = i - 1; - // Cubic Bezier Functions + } else { - b3p0: function ( t, p ) { + high = i; + break; - var k = 1 - t; - return k * k * k * p; + // DONE - }, + } - b3p1: function ( t, p ) { + } - var k = 1 - t; - return 3 * k * k * t * p; + i = high; - }, + //console.log('b' , i, low, high, Date.now()- time); - b3p2: function ( t, p ) { + if ( arcLengths[ i ] == targetArcLength ) { - var k = 1 - t; - return 3 * k * t * t * p; + var t = i / ( il - 1 ); + return t; - }, + } - b3p3: function ( t, p ) { + // we could get finer grain at lengths, or use simple interpolatation between two points - return t * t * t * p; + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - }, + var segmentLength = lengthAfter - lengthBefore; - b3: function ( t, p0, p1, p2, p3 ) { + // determine where we are between the 'before' and 'after' points - return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - } + // add that fractional amount to t -}; + var t = ( i + segmentFraction ) / ( il - 1 ); + return t; -/************************************************************** - * Line - **************************************************************/ +}; -THREE.LineCurve = function ( v1, v2 ) { +// Returns a unit vector tangent at t +// In case any sub curve does not implement its tangent derivation, +// 2 points a small delta apart will be used to find its gradient +// which seems to give a reasonable approximation - this.v1 = v1; - this.v2 = v2; +THREE.Curve.prototype.getTangent = function( t ) { -}; + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; -THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); + // Capping in case of danger -THREE.LineCurve.prototype.getPoint = function ( t ) { + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - var point = this.v2.clone().sub(this.v1); - point.multiplyScalar( t ).add( this.v1 ); + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - return point; + var vec = pt2.clone().sub(pt1); + return vec.normalize(); }; -// Line curve is linear, so we can overwrite default getPointAt -THREE.LineCurve.prototype.getPointAt = function ( u ) { +THREE.Curve.prototype.getTangentAt = function ( u ) { - return this.getPoint( u ); + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); }; -THREE.LineCurve.prototype.getTangent = function( t ) { - var tangent = this.v2.clone().sub(this.v1); - return tangent.normalize(); -}; + /************************************************************** - * Quadratic Bezier curve + * Utils **************************************************************/ +THREE.Curve.Utils = { -THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { -}; + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); -THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + }, + // Puay Bing, thanks for helping with this derivative! -THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { + tangentCubicBezier: function (t, p0, p1, p2, p3 ) { - var tx, ty; + return - 3 * p0 * (1 - t) * (1 - t) + + 3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) + + 6 * t * p2 * (1 - t) - 3 * t * t * p2 + + 3 * t * t * p3; - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + }, - return new THREE.Vector2( tx, ty ); + tangentSpline: function ( t, p0, p1, p2, p3 ) { -}; + // To check if my formulas are correct + var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 + var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t + var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2 + var h11 = 3 * t * t - 2 * t; // t3 − t2 -THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { + return h00 + h10 + h01 + h11; - var tx, ty; + }, - tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); + // Catmull-Rom - // returns unit vector + interpolate: function( p0, p1, p2, p3, t ) { - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - return tangent; + } }; -/************************************************************** - * Cubic Bezier curve - **************************************************************/ - -THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; -}; +// TODO: Transformation for Curves? -THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +/************************************************************** + * 3D Curves + **************************************************************/ -THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { +// A Factory method for creating new curve subclasses - var tx, ty; +THREE.Curve.create = function ( constructor, getPointFunc ) { - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.constructor = constructor; + constructor.prototype.getPoint = getPointFunc; - return new THREE.Vector2( tx, ty ); + return constructor; }; -THREE.CubicBezierCurve.prototype.getTangent = function( t ) { - - var tx, ty; - - tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); +// File:src/extras/core/CurvePath.js - return tangent; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ -}; /************************************************************** - * Spline curve + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve **************************************************************/ -THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - - this.points = (points == undefined) ? [] : points; +THREE.CurvePath = function () { + this.curves = []; + this.bends = []; + + this.autoClose = false; // Automatically closes the path }; -THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.SplineCurve.prototype.getPoint = function ( t ) { - - var v = new THREE.Vector2(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); +THREE.CurvePath.prototype.constructor = THREE.CurvePath; - intPoint = Math.floor( point ); - weight = point - intPoint; +THREE.CurvePath.prototype.add = function ( curve ) { - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; + this.curves.push( curve ); - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); +}; - return v; +THREE.CurvePath.prototype.checkConnection = function() { + // TODO + // If the ending of curve is not connected to the starting + // or the next curve, then, this is not a real path +}; +THREE.CurvePath.prototype.closePath = function() { + // TODO Test + // and verify for vector3 (needs to implement equals) + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[0].getPoint(0); + var endPoint = this.curves[this.curves.length - 1].getPoint(1); + + if (! startPoint.equals(endPoint)) { + this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); + } + }; -/************************************************************** - * Ellipse curve - **************************************************************/ -THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { +// To get accurate point with reference to +// entire path distance at time t, +// following has to be done: - this.aX = aX; - this.aY = aY; +// 1. Length of each sub path have to be known +// 2. Locate and identify type of curve +// 3. Get t for the curve +// 4. Return curve.getPointAt(t') - this.xRadius = xRadius; - this.yRadius = yRadius; +THREE.CurvePath.prototype.getPoint = function( t ) { - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; - this.aClockwise = aClockwise; + // To think about boundaries points. -}; + while ( i < curveLengths.length ) { -THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); + if ( curveLengths[ i ] >= d ) { -THREE.EllipseCurve.prototype.getPoint = function ( t ) { + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; - var angle; - var deltaAngle = this.aEndAngle - this.aStartAngle; + var u = 1 - diff / curve.getLength(); - if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; - if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; + return curve.getPointAt( u ); - if ( this.aClockwise === true ) { + } - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + i ++; - } else { + } - angle = this.aStartAngle + t * deltaAngle; + return null; - } + // loop where sum != 0, sum > d , sum+1 <d - var tx = this.aX + this.xRadius * Math.cos( angle ); - var ty = this.aY + this.yRadius * Math.sin( angle ); +}; + +/* +THREE.CurvePath.prototype.getTangent = function( t ) { +};*/ - return new THREE.Vector2( tx, ty ); -}; +// We cannot use the default THREE.Curve getPoint() with getLength() because in +// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath +// getPoint() depends on getLength -/************************************************************** - * Arc curve - **************************************************************/ +THREE.CurvePath.prototype.getLength = function() { -THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + var lens = this.getCurveLengths(); + return lens[ lens.length - 1 ]; - THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; -THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); -/************************************************************** - * Line3D - **************************************************************/ +// Compute lengths and cache them +// We cannot overwrite getLengths() because UtoT mapping uses it. -THREE.LineCurve3 = THREE.Curve.create( +THREE.CurvePath.prototype.getCurveLengths = function() { - function ( v1, v2 ) { + // We use cache values if curves and cache array are same length - this.v1 = v1; - this.v2 = v2; + if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) { - }, + return this.cacheLengths; - function ( t ) { + }; - var r = new THREE.Vector3(); + // Get length of subsurve + // Push sums into cached array + var lengths = [], sums = 0; + var i, il = this.curves.length; - r.subVectors( this.v2, this.v1 ); // diff - r.multiplyScalar( t ); - r.add( this.v1 ); + for ( i = 0; i < il; i ++ ) { - return r; + sums += this.curves[ i ].getLength(); + lengths.push( sums ); } -); - -/************************************************************** - * Quadratic Bezier 3D curve - **************************************************************/ - -THREE.QuadraticBezierCurve3 = THREE.Curve.create( - - function ( v0, v1, v2 ) { + this.cacheLengths = lengths; - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + return lengths; - }, +}; - function ( t ) { - var tx, ty, tz; - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); +// Returns min and max coordinates - return new THREE.Vector3( tx, ty, tz ); +THREE.CurvePath.prototype.getBoundingBox = function () { - } + var points = this.getPoints(); -); -/************************************************************** - * Cubic Bezier 3D curve - **************************************************************/ + var maxX, maxY, maxZ; + var minX, minY, minZ; -THREE.CubicBezierCurve3 = THREE.Curve.create( + maxX = maxY = Number.NEGATIVE_INFINITY; + minX = minY = Number.POSITIVE_INFINITY; - function ( v0, v1, v2, v3 ) { + var p, i, il, sum; - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + var v3 = points[0] instanceof THREE.Vector3; - }, + sum = v3 ? new THREE.Vector3() : new THREE.Vector2(); - function ( t ) { + for ( i = 0, il = points.length; i < il; i ++ ) { - var tx, ty, tz; + p = points[ i ]; - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); + if ( p.x > maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; - return new THREE.Vector3( tx, ty, tz ); + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; - } + if ( v3 ) { -); -/************************************************************** - * Spline 3D curve - **************************************************************/ + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; + } -THREE.SplineCurve3 = THREE.Curve.create( + sum.add( p ); - function ( points /* array of Vector3 */) { + } - this.points = (points == undefined) ? [] : points; + var ret = { - }, + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY - function ( t ) { + }; - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; + if ( v3 ) { - intPoint = Math.floor( point ); - weight = point - intPoint; + ret.maxZ = maxZ; + ret.minZ = minZ; - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + } - var pt0 = points[ c[0] ], - pt1 = points[ c[1] ], - pt2 = points[ c[2] ], - pt3 = points[ c[3] ]; + return ret; - v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); - v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); - v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); +}; - return v; +/************************************************************** + * Create Geometries Helpers + **************************************************************/ - } +/// Generate geometry from path points (for Line or Points objects) -); +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); -// THREE.SplineCurve3.prototype.getTangent = function(t) { -// var v = new THREE.Vector3(); -// var c = []; -// var points = this.points, point, intPoint, weight; -// point = ( points.length - 1 ) * t; +}; -// intPoint = Math.floor( point ); -// weight = point - intPoint; +// Generate geometry from equidistance sampling along the path -// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; -// c[ 1 ] = intPoint; -// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; -// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { -// var pt0 = points[ c[0] ], -// pt1 = points[ c[1] ], -// pt2 = points[ c[2] ], -// pt3 = points[ c[3] ]; + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); -// // t = weight; -// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); -// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); -// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); +}; -// return v; +THREE.CurvePath.prototype.createGeometry = function( points ) { -// } -/************************************************************** - * Closed Spline 3D curve - **************************************************************/ + var geometry = new THREE.Geometry(); + for ( var i = 0; i < points.length; i ++ ) { -THREE.ClosedSplineCurve3 = THREE.Curve.create( + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); - function ( points /* array of Vector3 */) { + } - this.points = (points == undefined) ? [] : points; + return geometry; - }, +}; - function ( t ) { - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 0 ) * t; - // This needs to be from 0-length +1 +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ - intPoint = Math.floor( point ); - weight = point - intPoint; +// Wrap path / Bend modifiers? - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - c[ 0 ] = ( intPoint - 1 ) % points.length; - c[ 1 ] = ( intPoint ) % points.length; - c[ 2 ] = ( intPoint + 1 ) % points.length; - c[ 3 ] = ( intPoint + 2 ) % points.length; +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); - v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); + this.bends.push( bendpath ); - return v; +}; - } +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { -); -/** - * @author mikael emtinger / http://gomo.se/ - */ + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; -THREE.AnimationHandler = (function() { + if ( ! bends ) { - var playing = []; - var library = {}; - var that = {}; + bends = this.bends; + } - //--- update --- + for ( i = 0, il = bends.length; i < il; i ++ ) { - that.update = function( deltaTimeMS ) { + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - for( var i = 0; i < playing.length; i ++ ) - playing[ i ].update( deltaTimeMS ); + } - }; + return oldPts; +}; - //--- add --- +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { - that.addToUpdate = function( animation ) { + var oldPts = this.getSpacedPoints( segments ); - if ( playing.indexOf( animation ) === -1 ) - playing.push( animation ); + var i, il; - }; + if ( ! bends ) { + bends = this.bends; - //--- remove --- + } - that.removeFromUpdate = function( animation ) { + for ( i = 0, il = bends.length; i < il; i ++ ) { - var index = playing.indexOf( animation ); + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - if( index !== -1 ) - playing.splice( index, 1 ); + } - }; + return oldPts; +}; - //--- add --- +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html - that.add = function( data ) { +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { - if ( library[ data.name ] !== undefined ) - console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); + var bounds = this.getBoundingBox(); - library[ data.name ] = data; - initData( data ); + var i, il, p, oldX, oldY, xNorm; - }; + for ( i = 0, il = oldPts.length; i < il; i ++ ) { + p = oldPts[ i ]; - //--- get --- + oldX = p.x; + oldY = p.y; - that.get = function( name ) { + xNorm = oldX / bounds.maxX; - if ( typeof name === "string" ) { + // If using actual distance, for length > path, requires line extrusions + //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance - if ( library[ name ] ) { + xNorm = path.getUtoTmapping( xNorm, oldX ); - return library[ name ]; + // check for out of bounds? - } else { + var pathPt = path.getPoint( xNorm ); + var normal = path.getTangent( xNorm ); + normal.set( - normal.y, normal.x ).multiplyScalar( oldY ); - console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name ); - return null; + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; - } + } - } else { + return oldPts; - // todo: add simple tween library +}; - } - }; +// File:src/extras/core/Gyroscope.js - //--- parse --- +/** + * @author alteredq / http://alteredqualia.com/ + */ - that.parse = function( root ) { +THREE.Gyroscope = function () { - // setup hierarchy + THREE.Object3D.call( this ); - var hierarchy = []; +}; - if ( root instanceof THREE.SkinnedMesh ) { +THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Gyroscope.prototype.constructor = THREE.Gyroscope; - for( var b = 0; b < root.bones.length; b++ ) { +THREE.Gyroscope.prototype.updateMatrixWorld = ( function () { - hierarchy.push( root.bones[ b ] ); + var translationObject = new THREE.Vector3(); + var quaternionObject = new THREE.Quaternion(); + var scaleObject = new THREE.Vector3(); - } + var translationWorld = new THREE.Vector3(); + var quaternionWorld = new THREE.Quaternion(); + var scaleWorld = new THREE.Vector3(); - } else { + return function ( force ) { - parseRecurseHierarchy( root, hierarchy ); + this.matrixAutoUpdate && this.updateMatrix(); - } + // update matrixWorld - return hierarchy; + if ( this.matrixWorldNeedsUpdate || force ) { - }; + if ( this.parent ) { - var parseRecurseHierarchy = function( root, hierarchy ) { + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - hierarchy.push( root ); + this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld ); + this.matrix.decompose( translationObject, quaternionObject, scaleObject ); - for( var c = 0; c < root.children.length; c++ ) - parseRecurseHierarchy( root.children[ c ], hierarchy ); + this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld ); - } + } else { - //--- init data --- + this.matrixWorld.copy( this.matrix ); - var initData = function( data ) { + } - if( data.initialized === true ) - return; + this.matrixWorldNeedsUpdate = false; - // loop through all keys + force = true; - for( var h = 0; h < data.hierarchy.length; h ++ ) { + } - for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + // update children - // remove minus times + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - if( data.hierarchy[ h ].keys[ k ].time < 0 ) - data.hierarchy[ h ].keys[ k ].time = 0; + this.children[ i ].updateMatrixWorld( force ); + } - // create quaternions + }; + +}() ); - if( data.hierarchy[ h ].keys[ k ].rot !== undefined && - !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { +// File:src/extras/core/Path.js - var quat = data.hierarchy[ h ].keys[ k ].rot; - data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] ); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ - } +THREE.Path = function ( points ) { - } + THREE.CurvePath.call(this); + this.actions = []; - // prepare morph target keys + if ( points ) { - if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { + this.fromPoints( points ); - // get all used + } - var usedMorphTargets = {}; +}; - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); +THREE.Path.prototype.constructor = THREE.Path; - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { +THREE.PathActions = { - var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; - usedMorphTargets[ morphTargetName ] = -1; + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve + BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve + CSPLINE_THRU: 'splineThru', // Catmull-rom spline + ARC: 'arc', // Circle + ELLIPSE: 'ellipse' +}; - } +// TODO Clean up PATH API - } +// Create path using straight lines to connect all points +// - vectors: array of Vector2 - data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; +THREE.Path.prototype.fromPoints = function ( vectors ) { + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - // set all used on all frames + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + this.lineTo( vectors[ v ].x, vectors[ v ].y ); - var influences = {}; + }; - for ( var morphTargetName in usedMorphTargets ) { +}; - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { +// startPath() endPath()? - if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { +THREE.Path.prototype.moveTo = function ( x, y ) { - influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; - break; + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); - } +}; - } +THREE.Path.prototype.lineTo = function ( x, y ) { - if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { + var args = Array.prototype.slice.call( arguments ); - influences[ morphTargetName ] = 0; + var lastargs = this.actions[ this.actions.length - 1 ].args; - } + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - } + var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); + this.curves.push( curve ); - data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); - } +}; - } +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + var args = Array.prototype.slice.call( arguments ); - // remove all keys that are on the same time + var lastargs = this.actions[ this.actions.length - 1 ].args; - for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); - data.hierarchy[ h ].keys.splice( k, 1 ); - k --; + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); - } +}; - } +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { + var args = Array.prototype.slice.call( arguments ); - // set index + var lastargs = this.actions[ this.actions.length - 1 ].args; - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - data.hierarchy[ h ].keys[ k ].index = k; + var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCP1x, aCP1y ), + new THREE.Vector2( aCP2x, aCP2y ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); - } + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); - } +}; +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { - // JIT + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; - var lengthInFrames = parseInt( data.length * data.fps, 10 ); + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; +//--- + var npts = [ new THREE.Vector2( x0, y0 ) ]; + Array.prototype.push.apply( npts, pts ); - data.JIT = {}; - data.JIT.hierarchy = []; + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); - for( var h = 0; h < data.hierarchy.length; h ++ ) - data.JIT.hierarchy.push( new Array( lengthInFrames ) ); + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); +}; - // done +// FUTURE: Change the API or follow canvas API? - data.initialized = true; +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { - }; + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + this.absarc(aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - // interpolation types + }; - that.LINEAR = 0; - that.CATMULLROM = 1; - that.CATMULLROM_FORWARD = 2; + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); + }; - return that; +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { -}()); + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + this.absellipse(aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); -THREE.Animation = function ( root, name, interpolationType ) { + }; - this.root = root; - this.data = THREE.AnimationHandler.get( name ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - this.currentTime = 0; - this.timeScale = 1; +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { - this.isPlaying = false; - this.isPaused = true; - this.loop = true; + var args = Array.prototype.slice.call( arguments ); + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + this.curves.push( curve ); - this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR; + var lastPoint = curve.getPoint(1); + args.push(lastPoint.x); + args.push(lastPoint.y); - this.points = []; - this.target = new THREE.Vector3(); + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); -}; + }; -THREE.Animation.prototype.play = function ( loop, startTimeMS ) { +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { - if ( this.isPlaying === false ) { + if ( ! divisions ) divisions = 40; - this.isPlaying = true; - this.loop = loop !== undefined ? loop : true; - this.currentTime = startTimeMS !== undefined ? startTimeMS : 0; + var points = []; - // reset key cache + for ( var i = 0; i < divisions; i ++ ) { - var h, hl = this.hierarchy.length, - object; + points.push( this.getPoint( i / divisions ) ); - for ( h = 0; h < hl; h ++ ) { + //if( !this.getPoint( i / divisions ) ) throw "DIE"; - object = this.hierarchy[ h ]; + } - object.matrixAutoUpdate = true; + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } - if ( object.animationCache === undefined ) { + return points; - object.animationCache = {}; - object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; +}; - } +/* Return an array of vectors based on contour of the path */ - var prevKey = object.animationCache.prevKey; - var nextKey = object.animationCache.nextKey; +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { - prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; + if (this.useSpacedPoints) { + console.log('tata'); + return this.getSpacedPoints( divisions, closedPath ); + } - nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); - nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); - nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); + divisions = divisions || 12; - } + var points = []; - this.update( 0 ); + var i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; - } + for ( i = 0, il = this.actions.length; i < il; i ++ ) { - this.isPaused = false; + item = this.actions[ i ]; - THREE.AnimationHandler.addToUpdate( this ); + action = item.action; + args = item.args; -}; + switch ( action ) { + case THREE.PathActions.MOVE_TO: -THREE.Animation.prototype.pause = function() { + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - if ( this.isPaused === true ) { + break; - THREE.AnimationHandler.addToUpdate( this ); + case THREE.PathActions.LINE_TO: - } else { + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - THREE.AnimationHandler.removeFromUpdate( this ); + break; - } + case THREE.PathActions.QUADRATIC_CURVE_TO: - this.isPaused = !this.isPaused; + cpx = args[ 2 ]; + cpy = args[ 3 ]; -}; + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + if ( points.length > 0 ) { -THREE.Animation.prototype.stop = function() { + laste = points[ points.length - 1 ]; - this.isPlaying = false; - this.isPaused = false; - THREE.AnimationHandler.removeFromUpdate( this ); + cpx0 = laste.x; + cpy0 = laste.y; -}; + } else { + laste = this.actions[ i - 1 ].args; -THREE.Animation.prototype.update = function ( deltaTimeMS ) { + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - // early out + } - if ( this.isPlaying === false ) return; + for ( j = 1; j <= divisions; j ++ ) { + t = j / divisions; - // vars + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - var types = [ "pos", "rot", "scl" ]; - var type; - var scale; - var vector; - var prevXYZ, nextXYZ; - var prevKey, nextKey; - var object; - var animationCache; - var frame; - var JIThierarchy = this.data.JIT.hierarchy; - var currentTime, unloopedCurrentTime; - var currentPoint, forwardPoint, angle; + points.push( new THREE.Vector2( tx, ty ) ); + } - this.currentTime += deltaTimeMS * this.timeScale; + break; - unloopedCurrentTime = this.currentTime; - currentTime = this.currentTime = this.currentTime % this.data.length; - frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 ); + case THREE.PathActions.BEZIER_CURVE_TO: + cpx = args[ 4 ]; + cpy = args[ 5 ]; - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; - object = this.hierarchy[ h ]; - animationCache = object.animationCache; + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; - // loop through pos/rot/scl + if ( points.length > 0 ) { - for ( var t = 0; t < 3; t ++ ) { + laste = points[ points.length - 1 ]; - // get keys + cpx0 = laste.x; + cpy0 = laste.y; - type = types[ t ]; - prevKey = animationCache.prevKey[ type ]; - nextKey = animationCache.nextKey[ type ]; + } else { - // switch keys? + laste = this.actions[ i - 1 ].args; - if ( nextKey.time <= unloopedCurrentTime ) { + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - // did we loop? + } - if ( currentTime < unloopedCurrentTime ) { - if ( this.loop ) { + for ( j = 1; j <= divisions; j ++ ) { - prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - nextKey = this.getNextKeyWith( type, h, 1 ); + t = j / divisions; - while( nextKey.time < currentTime ) { + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + points.push( new THREE.Vector2( tx, ty ) ); - } + } - } else { + break; - this.stop(); - return; + case THREE.PathActions.CSPLINE_THRU: - } + laste = this.actions[ i - 1 ].args; - } else { + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; - do { + var n = divisions * args[ 0 ].length; - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + spts = spts.concat( args[ 0 ] ); - } while( nextKey.time < currentTime ) + var spline = new THREE.SplineCurve( spts ); - } + for ( j = 1; j <= n; j ++ ) { - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; + points.push( spline.getPointAt( j / n ) ) ; } + break; - object.matrixAutoUpdate = true; - object.matrixWorldNeedsUpdate = true; + case THREE.PathActions.ARC: - scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - prevXYZ = prevKey[ type ]; - nextXYZ = nextKey[ type ]; + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !! args[ 5 ]; + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; - // check scale error + for ( j = 1; j <= tdivisions; j ++ ) { - if ( scale < 0 || scale > 1 ) { + t = j / tdivisions; - console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h ); - scale = scale < 0 ? 0 : 1; + if ( ! aClockwise ) { - } + t = 1 - t; - // interpolate + } - if ( type === "pos" ) { + angle = aStartAngle + t * deltaAngle; - vector = object.position; + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); - if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + points.push( new THREE.Vector2( tx, ty ) ); - } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + } - this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; - this.points[ 1 ] = prevXYZ; - this.points[ 2 ] = nextXYZ; - this.points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; + //console.log(points); - scale = scale * 0.33 + 0.33; + break; + + case THREE.PathActions.ELLIPSE: - currentPoint = this.interpolateCatmullRom( this.points, scale ); + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !! args[ 6 ]; - vector.x = currentPoint[ 0 ]; - vector.y = currentPoint[ 1 ]; - vector.z = currentPoint[ 2 ]; - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; - forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 ); + for ( j = 1; j <= tdivisions; j ++ ) { - this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); - this.target.sub( vector ); - this.target.y = 0; - this.target.normalize(); + t = j / tdivisions; - angle = Math.atan2( this.target.x, this.target.z ); - object.rotation.set( 0, angle, 0 ); + if ( ! aClockwise ) { - } + t = 1 - t; } - } else if ( type === "rot" ) { - - THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); + angle = aStartAngle + t * deltaAngle; - } else if ( type === "scl" ) { + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); - vector = object.scale; + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + points.push( new THREE.Vector2( tx, ty ) ); } - } - - } - -}; + //console.log(points); -// Catmull-Rom spline + break; -THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) { + } // end switch - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; + } - point = ( points.length - 1 ) * scale; - intPoint = Math.floor( point ); - weight = point - intPoint; - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - pa = points[ c[ 0 ] ]; - pb = points[ c[ 1 ] ]; - pc = points[ c[ 2 ] ]; - pd = points[ c[ 3 ] ]; + // Normalize to remove the closing point by default. + var lastPoint = points[ points.length - 1]; + var EPSILON = 0.0000000001; + if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && + Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) + points.splice( points.length - 1, 1); + if ( closedPath ) { - w2 = weight * weight; - w3 = weight * w2; + points.push( points[ 0 ] ); - v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); - v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); - v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); + } - return v3; + return points; }; -THREE.Animation.prototype.interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { +// +// Breaks path into shapes +// +// Assumptions (if parameter isCCW==true the opposite holds): +// - solid shapes are defined clockwise (CW) +// - holes are defined counterclockwise (CCW) +// +// If parameter noHoles==true: +// - all subPaths are regarded as solid shapes +// - definition order CW/CCW has no relevance +// - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; +THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + function extractSubpaths( inActions ) { -}; + var i, il, item, action, args; + var subPaths = [], lastPath = new THREE.Path(); + for ( i = 0, il = inActions.length; i < il; i ++ ) { -// Get next key with + item = inActions[ i ]; -THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + args = item.args; + action = item.action; - var keys = this.data.hierarchy[ h ].keys; + if ( action == THREE.PathActions.MOVE_TO ) { - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + if ( lastPath.actions.length != 0 ) { - key = key < keys.length - 1 ? key : keys.length - 1; + subPaths.push( lastPath ); + lastPath = new THREE.Path(); - } else { + } - key = key % keys.length; + } - } + lastPath[ action ].apply( lastPath, args ); - for ( ; key < keys.length; key++ ) { + } - if ( keys[ key ][ type ] !== undefined ) { + if ( lastPath.actions.length != 0 ) { - return keys[ key ]; + subPaths.push( lastPath ); } - } + // console.log(subPaths); - return this.data.hierarchy[ h ].keys[ 0 ]; + return subPaths; + } -}; + function toShapesNoHoles( inSubpaths ) { -// Get previous key with + var shapes = []; -THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) { - var keys = this.data.hierarchy[ h ].keys; + var tmpPath = inSubpaths[ i ]; - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + var tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; - key = key > 0 ? key : 0; + shapes.push( tmpShape ); + } - } else { + //console.log("shape", shapes); - key = key >= 0 ? key : key + keys.length; + return shapes; + }; - } + function isPointInsidePolygon( inPt, inPolygon ) { + var EPSILON = 0.0000000001; + var polyLen = inPolygon.length; - for ( ; key >= 0; key -- ) { + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + var inside = false; + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; - if ( keys[ key ][ type ] !== undefined ) { + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; - return keys[ key ]; + if ( Math.abs(edgeDy) > EPSILON ) { // not parallel + if ( edgeDy < 0 ) { + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + } + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + if ( inPt.y == edgeLowPt.y ) { + if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! + } else { + var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y); + if ( perpEdge == 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = ! inside; // true intersection left of inPt + } + } else { // parallel or colinear + if ( inPt.y != edgeLowPt.y ) continue; // parallel + // egde lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; + } } + return inside; } - return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; -}; + var subPaths = extractSubpaths( this.actions ); + if ( subPaths.length == 0 ) return []; -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author khang duong - * @author erik kitson - */ + if ( noHoles === true ) return toShapesNoHoles( subPaths ); -THREE.KeyFrameAnimation = function( root, data, JITCompile ) { - this.root = root; - this.data = THREE.AnimationHandler.get( data ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - this.currentTime = 0; - this.timeScale = 0.001; - this.isPlaying = false; - this.isPaused = true; - this.loop = true; - this.JITCompile = JITCompile !== undefined ? JITCompile : true; + var solid, tmpPath, tmpShape, shapes = []; - // initialize to first keyframes + if ( subPaths.length == 1) { - for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + tmpPath = subPaths[0]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - obj = this.hierarchy[h]; + } - if ( keys.length && sids ) { + var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - for ( var s = 0; s < sids.length; s++ ) { + // console.log("Holes first", holesFirst); + + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; - var sid = sids[ s ], - next = this.getNextKeyWith( sid, h, 0 ); + newShapes[mainIdx] = undefined; + newShapeHoles[mainIdx] = []; - if ( next ) { + var i, il; - next.apply( sid ); + for ( i = 0, il = subPaths.length; i < il; i ++ ) { - } + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = THREE.Shape.Utils.isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; - } + if ( solid ) { - obj.matrixAutoUpdate = false; - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; + if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx ++; - } + newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; + newShapes[mainIdx].s.actions = tmpPath.actions; + newShapes[mainIdx].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx ++; + newShapeHoles[mainIdx] = []; - } + //console.log('cw', i); -}; + } else { -// Play + newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); -THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) { + //console.log('ccw', i); - if( !this.isPlaying ) { + } - this.isPlaying = true; - this.loop = loop !== undefined ? loop : true; - this.currentTime = startTimeMS !== undefined ? startTimeMS : 0; - this.startTimeMs = startTimeMS; - this.startTime = 10000000; - this.endTime = -this.startTime; + } + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[0] ) return toShapesNoHoles( subPaths ); - // reset key cache - var h, hl = this.hierarchy.length, - object, - node; + if ( newShapes.length > 1 ) { + var ambigious = false; + var toChange = []; - for ( h = 0; h < hl; h++ ) { + for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + betterShapeHoles[sIdx] = []; + } + for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + var sho = newShapeHoles[sIdx]; + for (var hIdx = 0; hIdx < sho.length; hIdx ++ ) { + var ho = sho[hIdx]; + var hole_unassigned = true; + for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) { + if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); + if ( hole_unassigned ) { + hole_unassigned = false; + betterShapeHoles[s2Idx].push( ho ); + } else { + ambigious = true; + } + } + } + if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } + } + } + // console.log("ambigious: ", ambigious); + if ( toChange.length > 0 ) { + // console.log("to change: ", toChange); + if (! ambigious) newShapeHoles = betterShapeHoles; + } + } - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; + var tmpHoles, j, jl; + for ( i = 0, il = newShapes.length; i < il; i ++ ) { + tmpShape = newShapes[i].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[i]; + for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + tmpShape.holes.push( tmpHoles[j].h ); + } + } - if ( node.animationCache === undefined ) { + //console.log("shape", shapes); - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + return shapes; - } +}; - var keys = this.data.hierarchy[h].keys; +// File:src/extras/core/Shape.js - if (keys.length) { +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ - node.animationCache.prevKey = keys[ 0 ]; - node.animationCache.nextKey = keys[ 1 ]; +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 ExtrudeGeometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to vertices +// STEP 3b - Triangulate each shape, add faces. - this.startTime = Math.min( keys[0].time, this.startTime ); - this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); +THREE.Shape = function () { - } + THREE.Path.apply( this, arguments ); + this.holes = []; - } +}; - this.update( 0 ); +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); +THREE.Shape.prototype.constructor = THREE.Shape; - } +// Convenience method to return ExtrudeGeometry - this.isPaused = false; +THREE.Shape.prototype.extrude = function ( options ) { - THREE.AnimationHandler.addToUpdate( this ); + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; }; +// Convenience method to return ShapeGeometry +THREE.Shape.prototype.makeGeometry = function ( options ) { -// Pause + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; -THREE.KeyFrameAnimation.prototype.pause = function() { +}; - if( this.isPaused ) { +// Get points of holes - THREE.AnimationHandler.addToUpdate( this ); +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { - } else { + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { - THREE.AnimationHandler.removeFromUpdate( this ); + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); } - this.isPaused = !this.isPaused; + return holesPts; }; +// Get points of holes (spaced by regular distance) -// Stop - -THREE.KeyFrameAnimation.prototype.stop = function() { - - this.isPlaying = false; - this.isPaused = false; - THREE.AnimationHandler.removeFromUpdate( this ); - - - // reset JIT matrix and remove cache +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { - for ( var h = 0; h < this.data.hierarchy.length; h++ ) { + var i, il = this.holes.length, holesPts = []; - var obj = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; + for ( i = 0; i < il; i ++ ) { - if ( node.animationCache !== undefined ) { + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); - var original = node.animationCache.originalMatrix; + } - if( obj instanceof THREE.Bone ) { + return holesPts; - original.copy( obj.skinMatrix ); - obj.skinMatrix = original; +}; - } else { - original.copy( obj.matrix ); - obj.matrix = original; +// Get points of shape and holes (keypoints based on segments parameter) - } +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { - delete node.animationCache; + return { - } + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) - } + }; }; +THREE.Shape.prototype.extractPoints = function ( divisions ) { -// Update - -THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) { + if (this.useSpacedPoints) { + return this.extractAllSpacedPoints(divisions); + } - // early out + return this.extractAllPoints(divisions); - if( !this.isPlaying ) return; +}; +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; - // vars +// Get points of shape and holes (spaced by regular distance) - var prevKey, nextKey; - var object; - var node; - var frame; - var JIThierarchy = this.data.JIT.hierarchy; - var currentTime, unloopedCurrentTime; - var looped; +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + return { - // update + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) - this.currentTime += deltaTimeMS * this.timeScale; + }; - unloopedCurrentTime = this.currentTime; - currentTime = this.currentTime = this.currentTime % this.data.length; +}; - // if looped around, the current time should be based on the startTime - if ( currentTime < this.startTimeMs ) { +/************************************************************** + * Utils + **************************************************************/ - currentTime = this.currentTime = this.startTimeMs + currentTime; +THREE.Shape.Utils = { - } + triangulateShape: function ( contour, holes ) { - frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 ); - looped = currentTime < unloopedCurrentTime; + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { + // inOtherPt needs to be colinear to the inSegment + if ( inSegPt1.x != inSegPt2.x ) { + if ( inSegPt1.x < inSegPt2.x ) { + return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); + } else { + return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); + } + } else { + if ( inSegPt1.y < inSegPt2.y ) { + return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); + } else { + return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); + } + } + } - if ( looped && !this.loop ) { + function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { + var EPSILON = 0.0000000001; - // Set the animation to the last keyframes and stop - for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; + var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - end = keys.length-1, - obj = this.hierarchy[h]; + var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; + var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; - if ( keys.length ) { + var limit = seg1dy * seg2dx - seg1dx * seg2dy; + var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; - for ( var s = 0; s < sids.length; s++ ) { + if ( Math.abs(limit) > EPSILON ) { // not parallel - var sid = sids[ s ], - prev = this.getPrevKeyWith( sid, h, end ); + var perpSeg2; + if ( limit > 0 ) { + if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; + } else { + if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; + } - if ( prev ) { - prev.apply( sid ); + // i.e. to reduce rounding errors + // intersection at endpoint of segment#1? + if ( perpSeg2 == 0 ) { + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; + return [ inSeg1Pt1 ]; + } + if ( perpSeg2 == limit ) { + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; + return [ inSeg1Pt2 ]; + } + // intersection at endpoint of segment#2? + if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; + + // return real intersection point + var factorSeg1 = perpSeg2 / limit; + return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, + y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; + + } else { // parallel or colinear + if ( ( perpSeg1 != 0 ) || + ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; + + // they are collinear or degenerate + var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? + var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point? + // both segments are points + if ( seg1Pt && seg2Pt ) { + if ( (inSeg1Pt1.x != inSeg2Pt1.x) || + (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points + return [ inSeg1Pt1 ]; // they are the same point + } + // segment#1 is a single point + if ( seg1Pt ) { + if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 + return [ inSeg1Pt1 ]; + } + // segment#2 is a single point + if ( seg2Pt ) { + if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 + return [ inSeg2Pt1 ]; + } + // they are collinear segments, which might overlap + var seg1min, seg1max, seg1minVal, seg1maxVal; + var seg2min, seg2max, seg2minVal, seg2maxVal; + if (seg1dx != 0) { // the segments are NOT on a vertical line + if ( inSeg1Pt1.x < inSeg1Pt2.x ) { + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; + } else { + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; + } + if ( inSeg2Pt1.x < inSeg2Pt2.x ) { + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; + } else { + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; + } + } else { // the segments are on a vertical line + if ( inSeg1Pt1.y < inSeg1Pt2.y ) { + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; + } else { + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; + } + if ( inSeg2Pt1.y < inSeg2Pt2.y ) { + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; + } else { + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; } - } - - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; - + if ( seg1minVal <= seg2minVal ) { + if ( seg1maxVal < seg2minVal ) return []; + if ( seg1maxVal == seg2minVal ) { + if ( inExcludeAdjacentSegs ) return []; + return [ seg2min ]; + } + if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; + return [ seg2min, seg2max ]; + } else { + if ( seg1minVal > seg2maxVal ) return []; + if ( seg1minVal == seg2maxVal ) { + if ( inExcludeAdjacentSegs ) return []; + return [ seg1min ]; + } + if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; + return [ seg1min, seg2max ]; + } } - } - this.stop(); - return; - - } - - // check pre-infinity - if ( currentTime < this.startTime ) { + function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { + // The order of legs is important - return; + var EPSILON = 0.0000000001; - } + // translation of all points, so that Vertex is at (0,0) + var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; + var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; + var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; - // update + // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. + var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; + var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg. - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; + var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; + // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - var keys = node.keys, - animationCache = node.animationCache; + if ( from2toAngle > 0 ) { // main angle < 180 deg. + return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); + } else { // main angle > 180 deg. + return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); + } + } else { // angle == 180 deg. + // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); + return ( from2otherAngle > 0 ); + } + } - // use JIT? - if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) { + function removeHoles( contour, holes ) { - if( object instanceof THREE.Bone ) { + var shape = contour.concat(); // work on this shape + var hole; - object.skinMatrix = JIThierarchy[ h ][ frame ]; - object.matrixWorldNeedsUpdate = false; + function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { + // Check if hole point lies within angle around shape point + var lastShapeIdx = shape.length - 1; - } else { + var prevShapeIdx = inShapeIdx - 1; + if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; - object.matrix = JIThierarchy[ h ][ frame ]; - object.matrixWorldNeedsUpdate = true; + var nextShapeIdx = inShapeIdx + 1; + if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; - } + var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] ); + if (! insideAngle ) { + // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); + return false; + } - // use interpolation + // Check if shape point lies within angle around hole point + var lastHoleIdx = hole.length - 1; - } else if ( keys.length ) { + var prevHoleIdx = inHoleIdx - 1; + if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; - // make sure so original matrix and not JIT matrix is set + var nextHoleIdx = inHoleIdx + 1; + if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; - if ( this.JITCompile && animationCache ) { + insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] ); + if (! insideAngle ) { + // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); + return false; + } - if( object instanceof THREE.Bone ) { + return true; + } - object.skinMatrix = animationCache.originalMatrix; + function intersectsShapeEdge( inShapePt, inHolePt ) { + // checks for intersections with shape edges + var sIdx, nextIdx, intersection; + for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { + nextIdx = sIdx + 1; nextIdx %= shape.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); + if ( intersection.length > 0 ) return true; + } - } else { + return false; + } - object.matrix = animationCache.originalMatrix; + var indepHoles = []; + function intersectsHoleEdge( inShapePt, inHolePt ) { + // checks for intersections with hole edges + var ihIdx, chkHole, + hIdx, nextIdx, intersection; + for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { + chkHole = holes[indepHoles[ihIdx]]; + for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { + nextIdx = hIdx + 1; nextIdx %= chkHole.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); + if ( intersection.length > 0 ) return true; + } } - + return false; } - prevKey = animationCache.prevKey; - nextKey = animationCache.nextKey; + var holeIndex, shapeIndex, + shapePt, holePt, + holeIdx, cutKey, failedCuts = [], + tmpShape1, tmpShape2, + tmpHole1, tmpHole2; + + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - if ( prevKey && nextKey ) { + indepHoles.push( h ); - // switch keys? + } - if ( nextKey.time <= unloopedCurrentTime ) { + var minShapeIndex = 0; + var counter = indepHoles.length * 2; + while ( indepHoles.length > 0 ) { + counter --; + if ( counter < 0 ) { + console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); + break; + } - // did we loop? + // search for shape-vertex and hole-vertex, + // which can be connected without intersections + for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { - if ( looped && this.loop ) { + shapePt = shape[ shapeIndex ]; + holeIndex = - 1; - prevKey = keys[ 0 ]; - nextKey = keys[ 1 ]; + // search for hole which can be reached without intersections + for ( var h = 0; h < indepHoles.length; h ++ ) { + holeIdx = indepHoles[h]; - while ( nextKey.time < currentTime ) { + // prevent multiple checks + cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; + if ( failedCuts[cutKey] !== undefined ) continue; - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; + hole = holes[holeIdx]; + for ( var h2 = 0; h2 < hole.length; h2 ++ ) { + holePt = hole[ h2 ]; + if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; + if ( intersectsShapeEdge( shapePt, holePt ) ) continue; + if ( intersectsHoleEdge( shapePt, holePt ) ) continue; - } + holeIndex = h2; + indepHoles.splice(h, 1); - } else if ( !looped ) { + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); - var lastIndex = keys.length - 1; + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); - while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) { + minShapeIndex = shapeIndex; - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; + // Debug only, to show the selected cuts + // glob_CutLines.push( [ shapePt, holePt ] ); + break; } + if ( holeIndex >= 0 ) break; // hole-vertex found + failedCuts[cutKey] = true; // remember failure } - - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; - + if ( holeIndex >= 0 ) break; // hole-vertex found } - if(nextKey.time >= currentTime) - prevKey.interpolate( nextKey, currentTime ); - else - prevKey.interpolate( nextKey, nextKey.time); - } - this.data.hierarchy[h].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; - + return shape; /* shape with no holes */ } - } - - // update JIT? - - if ( this.JITCompile ) { - if ( JIThierarchy[ 0 ][ frame ] === undefined ) { - - this.hierarchy[ 0 ].updateMatrixWorld( true ); - - for ( var h = 0; h < this.hierarchy.length; h++ ) { - - if( this.hierarchy[ h ] instanceof THREE.Bone ) { - - JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone(); + var i, il, f, face, + key, index, + allPointsMap = {}; - } else { + // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. - JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone(); + var allpoints = contour.concat(); - } + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - } + Array.prototype.push.apply( allpoints, holes[h] ); } - } + //console.log( "allpoints",allpoints, allpoints.length ); -}; + // prepare all points map -// Get next key with + for ( i = 0, il = allpoints.length; i < il; i ++ ) { -THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { + key = allpoints[ i ].x + ":" + allpoints[ i ].y; - var keys = this.data.hierarchy[ h ].keys; - key = key % keys.length; + if ( allPointsMap[ key ] !== undefined ) { - for ( ; key < keys.length; key++ ) { + THREE.warn( "THREE.Shape: Duplicate point", key ); - if ( keys[ key ].hasTarget( sid ) ) { + } - return keys[ key ]; + allPointsMap[ key ] = i; } - } + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); - return keys[ 0 ]; + var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape + //console.log( "triangles",triangles, triangles.length ); -}; + // check all face vertices against all points map -// Get previous key with + for ( i = 0, il = triangles.length; i < il; i ++ ) { -THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + face = triangles[ i ]; - var keys = this.data.hierarchy[ h ].keys; - key = key >= 0 ? key : key + keys.length; + for ( f = 0; f < 3; f ++ ) { - for ( ; key >= 0; key-- ) { + key = face[ f ].x + ":" + face[ f ].y; - if ( keys[ key ].hasTarget( sid ) ) { + index = allPointsMap[ key ]; - return keys[ key ]; + if ( index !== undefined ) { - } + face[ f ] = index; - } + } - return keys[ keys.length - 1 ]; + } -}; + } -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ + return triangles.concat(); -THREE.CubeCamera = function ( near, far, cubeResolution ) { + }, - THREE.Object3D.call( this ); + isClockWise: function ( pts ) { - var fov = 90, aspect = 1; + return THREE.FontUtils.Triangulate.area( pts ) < 0; - var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPX.up.set( 0, -1, 0 ); - cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); + }, - var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, -1, 0 ); - cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); - this.add( cameraNX ); + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve - var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); + // Quad Bezier Functions - var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, -1 ); - cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); - this.add( cameraNY ); + b2p0: function ( t, p ) { - var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, -1, 0 ); - cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); + var k = 1 - t; + return k * k * p; - var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, -1, 0 ); - cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); - this.add( cameraNZ ); + }, - this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); + b2p1: function ( t, p ) { - this.updateCubeMap = function ( renderer, scene ) { + return 2 * ( 1 - t ) * t * p; - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.generateMipmaps; + }, - renderTarget.generateMipmaps = false; + b2p2: function ( t, p ) { - renderTarget.activeCubeFace = 0; - renderer.render( scene, cameraPX, renderTarget ); + return t * t * p; - renderTarget.activeCubeFace = 1; - renderer.render( scene, cameraNX, renderTarget ); + }, - renderTarget.activeCubeFace = 2; - renderer.render( scene, cameraPY, renderTarget ); + b2: function ( t, p0, p1, p2 ) { - renderTarget.activeCubeFace = 3; - renderer.render( scene, cameraNY, renderTarget ); + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); - renderTarget.activeCubeFace = 4; - renderer.render( scene, cameraPZ, renderTarget ); + }, - renderTarget.generateMipmaps = generateMipmaps; + // Cubic Bezier Functions - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); + b3p0: function ( t, p ) { - }; + var k = 1 - t; + return k * k * k * p; -}; + }, -THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); + b3p1: function ( t, p ) { -/* - * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog - * - * A general perpose camera, for setting FOV, Lens Focal Length, - * and switching between perspective and orthographic views easily. - * Use this only if you do not wish to manage - * both a Orthographic and Perspective Camera - * - */ + var k = 1 - t; + return 3 * k * k * t * p; + }, -THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { + b3p2: function ( t, p ) { - THREE.Camera.call( this ); + var k = 1 - t; + return 3 * k * t * t * p; - this.fov = fov; + }, - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; + b3p3: function ( t, p ) { - // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects + return t * t * t * p; - this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); - this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); + }, - this.zoom = 1; + b3: function ( t, p0, p1, p2, p3 ) { - this.toPerspective(); + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); - var aspect = width/height; + } }; -THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); - -THREE.CombinedCamera.prototype.toPerspective = function () { - // Switches to the Perspective Camera +// File:src/extras/curves/LineCurve.js - this.near = this.cameraP.near; - this.far = this.cameraP.far; - - this.cameraP.fov = this.fov / this.zoom ; - - this.cameraP.updateProjectionMatrix(); +/************************************************************** + * Line + **************************************************************/ - this.projectionMatrix = this.cameraP.projectionMatrix; +THREE.LineCurve = function ( v1, v2 ) { - this.inPerspectiveMode = true; - this.inOrthographicMode = false; + this.v1 = v1; + this.v2 = v2; }; -THREE.CombinedCamera.prototype.toOrthographic = function () { - - // Switches to the Orthographic camera estimating viewport from Perspective +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.LineCurve.prototype.constructor = THREE.LineCurve; - var fov = this.fov; - var aspect = this.cameraP.aspect; - var near = this.cameraP.near; - var far = this.cameraP.far; +THREE.LineCurve.prototype.getPoint = function ( t ) { - // The size that we set is the mid plane of the viewing frustum + var point = this.v2.clone().sub(this.v1); + point.multiplyScalar( t ).add( this.v1 ); - var hyperfocus = ( near + far ) / 2; + return point; - var halfHeight = Math.tan( fov / 2 ) * hyperfocus; - var planeHeight = 2 * halfHeight; - var planeWidth = planeHeight * aspect; - var halfWidth = planeWidth / 2; +}; - halfHeight /= this.zoom; - halfWidth /= this.zoom; +// Line curve is linear, so we can overwrite default getPointAt - this.cameraO.left = -halfWidth; - this.cameraO.right = halfWidth; - this.cameraO.top = halfHeight; - this.cameraO.bottom = -halfHeight; +THREE.LineCurve.prototype.getPointAt = function ( u ) { - // this.cameraO.left = -farHalfWidth; - // this.cameraO.right = farHalfWidth; - // this.cameraO.top = farHalfHeight; - // this.cameraO.bottom = -farHalfHeight; + return this.getPoint( u ); - // this.cameraO.left = this.left / this.zoom; - // this.cameraO.right = this.right / this.zoom; - // this.cameraO.top = this.top / this.zoom; - // this.cameraO.bottom = this.bottom / this.zoom; +}; - this.cameraO.updateProjectionMatrix(); +THREE.LineCurve.prototype.getTangent = function( t ) { - this.near = this.cameraO.near; - this.far = this.cameraO.far; - this.projectionMatrix = this.cameraO.projectionMatrix; + var tangent = this.v2.clone().sub(this.v1); - this.inPerspectiveMode = false; - this.inOrthographicMode = true; + return tangent.normalize(); }; +// File:src/extras/curves/QuadraticBezierCurve.js -THREE.CombinedCamera.prototype.setSize = function( width, height ) { +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ - this.cameraP.aspect = width / height; - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; -}; +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; -THREE.CombinedCamera.prototype.setFov = function( fov ) { +}; - this.fov = fov; +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; - if ( this.inPerspectiveMode ) { - this.toPerspective(); +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { - } else { + var vector = new THREE.Vector2(); - this.toOrthographic(); + vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - } + return vector; }; -// For mantaining similar API with PerspectiveCamera - -THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { - if ( this.inPerspectiveMode ) { +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { - this.toPerspective(); + var vector = new THREE.Vector2(); - } else { + vector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); - this.toPerspective(); - this.toOrthographic(); + // returns unit vector - } + return vector.normalize(); }; -/* -* Uses Focal Length (in mm) to estimate and set FOV -* 35mm (fullframe) camera is used if frame size is not specified; -* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html -*/ -THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { +// File:src/extras/curves/CubicBezierCurve.js - if ( frameHeight === undefined ) frameHeight = 24; +/************************************************************** + * Cubic Bezier curve + **************************************************************/ - var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - this.setFov( fov ); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - return fov; }; +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; -THREE.CombinedCamera.prototype.setZoom = function( zoom ) { - - this.zoom = zoom; - - if ( this.inPerspectiveMode ) { - - this.toPerspective(); +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { - } else { + var tx, ty; - this.toOrthographic(); + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - } + return new THREE.Vector2( tx, ty ); }; -THREE.CombinedCamera.prototype.toFrontView = function() { +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; - this.rotation.x = 0; - this.rotation.y = 0; - this.rotation.z = 0; + tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - // should we be modifing the matrix instead? + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); - this.rotationAutoUpdate = false; + return tangent; }; -THREE.CombinedCamera.prototype.toBackView = function() { +// File:src/extras/curves/SplineCurve.js - this.rotation.x = 0; - this.rotation.y = Math.PI; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; +/************************************************************** + * Spline curve + **************************************************************/ -THREE.CombinedCamera.prototype.toLeftView = function() { +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - this.rotation.x = 0; - this.rotation.y = - Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + this.points = ( points == undefined ) ? [] : points; }; -THREE.CombinedCamera.prototype.toRightView = function() { +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; - this.rotation.x = 0; - this.rotation.y = Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; +THREE.SplineCurve.prototype.getPoint = function ( t ) { -}; + var points = this.points; + var point = ( points.length - 1 ) * t; -THREE.CombinedCamera.prototype.toTopView = function() { + var intPoint = Math.floor( point ); + var weight = point - intPoint; - this.rotation.x = - Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ] + var point1 = points[ intPoint ] + var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ] + var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ] -}; + var vector = new THREE.Vector2(); -THREE.CombinedCamera.prototype.toBottomView = function() { + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); - this.rotation.x = Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; + return vector; }; +// File:src/extras/curves/EllipseCurve.js -/** - * @author hughes - */ +/************************************************************** + * Ellipse curve + **************************************************************/ -THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { - THREE.Geometry.call( this ); + this.aX = aX; + this.aY = aY; - this.radius = radius = radius || 50; - this.segments = segments = segments !== undefined ? Math.max( 3, segments ) : 8; + this.xRadius = xRadius; + this.yRadius = yRadius; - this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; - this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; - var i, uvs = [], - center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); + this.aClockwise = aClockwise; - this.vertices.push(center); - uvs.push( centerUV ); +}; - for ( i = 0; i <= segments; i ++ ) { +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; - var vertex = new THREE.Vector3(); - var segment = thetaStart + i / segments * thetaLength; +THREE.EllipseCurve.prototype.getPoint = function ( t ) { - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + var deltaAngle = this.aEndAngle - this.aStartAngle; - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); + if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; + if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; - } + var angle; - var n = new THREE.Vector3( 0, 0, 1 ); + if ( this.aClockwise === true ) { - for ( i = 1; i <= segments; i ++ ) { + angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); - var v1 = i; - var v2 = i + 1 ; - var v3 = 0; + } else { - this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ i ], uvs[ i + 1 ], centerUV ] ); + angle = this.aStartAngle + t * deltaAngle; } + + var vector = new THREE.Vector2(); - this.computeCentroids(); - this.computeFaceNormals(); + vector.x = this.aX + this.xRadius * Math.cos( angle ); + vector.y = this.aY + this.yRadius * Math.sin( angle ); - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + return vector; }; -THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as - */ - -THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - THREE.Geometry.call( this ); +// File:src/extras/curves/ArcCurve.js - var scope = this; +/************************************************************** + * Arc curve + **************************************************************/ - this.width = width; - this.height = height; - this.depth = depth; +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - this.widthSegments = widthSegments || 1; - this.heightSegments = heightSegments || 1; - this.depthSegments = depthSegments || 1; + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +}; - var width_half = this.width / 2; - var height_half = this.height / 2; - var depth_half = this.depth / 2; +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; - buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px - buildPlane( 'z', 'y', 1, - 1, this.depth, this.height, - width_half, 1 ); // nx - buildPlane( 'x', 'z', 1, 1, this.width, this.depth, height_half, 2 ); // py - buildPlane( 'x', 'z', 1, - 1, this.width, this.depth, - height_half, 3 ); // ny - buildPlane( 'x', 'y', 1, - 1, this.width, this.height, depth_half, 4 ); // pz - buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz +// File:src/extras/curves/LineCurve3.js - function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { +/************************************************************** + * Line3D + **************************************************************/ - var w, ix, iy, - gridX = scope.widthSegments, - gridY = scope.heightSegments, - width_half = width / 2, - height_half = height / 2, - offset = scope.vertices.length; +THREE.LineCurve3 = THREE.Curve.create( - if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + function ( v1, v2 ) { - w = 'z'; + this.v1 = v1; + this.v2 = v2; - } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { + }, - w = 'y'; - gridY = scope.depthSegments; + function ( t ) { - } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { + var vector = new THREE.Vector3(); - w = 'x'; - gridX = scope.depthSegments; + vector.subVectors( this.v2, this.v1 ); // diff + vector.multiplyScalar( t ); + vector.add( this.v1 ); - } + return vector; - var gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY, - normal = new THREE.Vector3(); + } - normal[ w ] = depth > 0 ? 1 : - 1; +); - for ( iy = 0; iy < gridY1; iy ++ ) { +// File:src/extras/curves/QuadraticBezierCurve3.js - for ( ix = 0; ix < gridX1; ix ++ ) { +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ - var vector = new THREE.Vector3(); - vector[ u ] = ( ix * segment_width - width_half ) * udir; - vector[ v ] = ( iy * segment_height - height_half ) * vdir; - vector[ w ] = depth; +THREE.QuadraticBezierCurve3 = THREE.Curve.create( - scope.vertices.push( vector ); + function ( v0, v1, v2 ) { - } + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - } + }, - for ( iy = 0; iy < gridY; iy++ ) { + function ( t ) { - for ( ix = 0; ix < gridX; ix++ ) { + var vector = new THREE.Vector3(); - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; + vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + vector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); - var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); + return vector; - var face = new THREE.Face3( a + offset, b + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; + } - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); +); - face = new THREE.Face3( b + offset, c + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; +// File:src/extras/curves/CubicBezierCurve3.js - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ - } +THREE.CubicBezierCurve3 = THREE.Curve.create( - } + function ( v0, v1, v2, v3 ) { - } + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - this.computeCentroids(); - this.mergeVertices(); + }, -}; + function ( t ) { -THREE.CubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + var vector = new THREE.Vector3(); -/** - * @author mrdoob / http://mrdoob.com/ - */ + vector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + vector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + vector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); -THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { + return vector; - THREE.Geometry.call( this ); + } - this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20; - this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; - this.height = height = height !== undefined ? height : 100; +); - this.radialSegments = radialSegments = radialSegments || 8; - this.heightSegments = heightSegments = heightSegments || 1; +// File:src/extras/curves/SplineCurve3.js - this.openEnded = openEnded = openEnded !== undefined ? openEnded : false; +/************************************************************** + * Spline 3D curve + **************************************************************/ - var heightHalf = height / 2; - var x, y, vertices = [], uvs = []; +THREE.SplineCurve3 = THREE.Curve.create( - for ( y = 0; y <= heightSegments; y ++ ) { + function ( points /* array of Vector3 */) { - var verticesRow = []; - var uvsRow = []; + this.points = ( points == undefined ) ? [] : points; - var v = y / heightSegments; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + }, - for ( x = 0; x <= radialSegments; x ++ ) { + function ( t ) { - var u = x / radialSegments; + var points = this.points; + var point = ( points.length - 1 ) * t; - var vertex = new THREE.Vector3(); - vertex.x = radius * Math.sin( u * Math.PI * 2 ); - vertex.y = - v * height + heightHalf; - vertex.z = radius * Math.cos( u * Math.PI * 2 ); + var intPoint = Math.floor( point ); + var weight = point - intPoint; - this.vertices.push( vertex ); + var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ]; + var point1 = points[ intPoint ]; + var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + var vector = new THREE.Vector3(); - } + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); + vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - vertices.push( verticesRow ); - uvs.push( uvsRow ); + return vector; } - var tanTheta = ( radiusBottom - radiusTop ) / height; - var na, nb; +); - for ( x = 0; x < radialSegments; x ++ ) { +// File:src/extras/curves/ClosedSplineCurve3.js - if ( radiusTop !== 0 ) { +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ - na = this.vertices[ vertices[ 0 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - } else { +THREE.ClosedSplineCurve3 = THREE.Curve.create( - na = this.vertices[ vertices[ 1 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); + function ( points /* array of Vector3 */) { - } + this.points = ( points == undefined ) ? [] : points; - na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); - nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); + }, - for ( y = 0; y < heightSegments; y ++ ) { + function ( t ) { - var v1 = vertices[ y ][ x ]; - var v2 = vertices[ y + 1 ][ x ]; - var v3 = vertices[ y + 1 ][ x + 1 ]; - var v4 = vertices[ y ][ x + 1 ]; + var points = this.points; + var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 - var n1 = na.clone(); - var n2 = na.clone(); - var n3 = nb.clone(); - var n4 = nb.clone(); + var intPoint = Math.floor( point ); + var weight = point - intPoint; - var uv1 = uvs[ y ][ x ].clone(); - var uv2 = uvs[ y + 1 ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); - var uv4 = uvs[ y ][ x + 1 ].clone(); + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + var point0 = points[ ( intPoint - 1 ) % points.length ]; + var point1 = points[ ( intPoint ) % points.length ]; + var point2 = points[ ( intPoint + 1 ) % points.length ]; + var point3 = points[ ( intPoint + 2 ) % points.length ]; - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2, uv3, uv4 ] ); + var vector = new THREE.Vector3(); - } + vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight ); + vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight ); + vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight ); - } + return vector; - // top cap + } - if ( openEnded === false && radiusTop > 0 ) { +); - this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); +// File:src/extras/animation/AnimationHandler.js - for ( x = 0; x < radialSegments; x ++ ) { +/** + * @author mikael emtinger / http://gomo.se/ + */ - var v1 = vertices[ 0 ][ x ]; - var v2 = vertices[ 0 ][ x + 1 ]; - var v3 = this.vertices.length - 1; +THREE.AnimationHandler = { - var n1 = new THREE.Vector3( 0, 1, 0 ); - var n2 = new THREE.Vector3( 0, 1, 0 ); - var n3 = new THREE.Vector3( 0, 1, 0 ); + LINEAR: 0, + CATMULLROM: 1, + CATMULLROM_FORWARD: 2, - var uv1 = uvs[ 0 ][ x ].clone(); - var uv2 = uvs[ 0 ][ x + 1 ].clone(); - var uv3 = new THREE.Vector2( uv2.u, 0 ); + // - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, + get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, + remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, - } + // - } + animations: [], - // bottom cap + init: function ( data ) { - if ( openEnded === false && radiusBottom > 0 ) { + if ( data.initialized === true ) return data; - this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); + // loop through all keys - for ( x = 0; x < radialSegments; x ++ ) { + for ( var h = 0; h < data.hierarchy.length; h ++ ) { - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = this.vertices.length - 1; + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - var n1 = new THREE.Vector3( 0, - 1, 0 ); - var n2 = new THREE.Vector3( 0, - 1, 0 ); - var n3 = new THREE.Vector3( 0, - 1, 0 ); + // remove minus times - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = new THREE.Vector2( uv2.u, 1 ); + if ( data.hierarchy[ h ].keys[ k ].time < 0 ) { - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + data.hierarchy[ h ].keys[ k ].time = 0; - } + } - } + // create quaternions - this.computeCentroids(); - this.computeFaceNormals(); + if ( data.hierarchy[ h ].keys[ k ].rot !== undefined && + ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { -} + var quat = data.hierarchy[ h ].keys[ k ].rot; + data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat ); -THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); + } -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: <int>, // number of points on the curves - * steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too - * amount: <int>, // Depth to extrude the shape - * - * bevelEnabled: <bool>, // turn on bevel - * bevelThickness: <float>, // how deep into the original shape bevel goes - * bevelSize: <float>, // how far from shape outline is bevel - * bevelSegments: <int>, // number of bevel layers - * - * extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) - * frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals - * - * material: <int> // material index for front and back faces - * extrudeMaterial: <int> // material index for extrusion and beveled faces - * uvGenerator: <Object> // object that provides UV generator functions - * - * } - **/ + } -THREE.ExtrudeGeometry = function ( shapes, options ) { + // prepare morph target keys - if ( typeof( shapes ) === "undefined" ) { - shapes = []; - return; - } + if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { - THREE.Geometry.call( this ); + // get all used - shapes = shapes instanceof Array ? shapes : [ shapes ]; + var usedMorphTargets = {}; - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - this.addShapeList( shapes, options ); + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - this.computeCentroids(); - this.computeFaceNormals(); + var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; + usedMorphTargets[ morphTargetName ] = - 1; - // can't really use automatic vertex normals - // as then front and back sides get smoothed too - // should do separate smoothing just for sides + } - //this.computeVertexNormals(); + } - //console.log( "took", ( Date.now() - startTime ) ); + data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; -}; -THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + // set all used on all frames -THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { - var sl = shapes.length; + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - for ( var s = 0; s < sl; s ++ ) { - var shape = shapes[ s ]; - this.addShape( shape, options ); - } -}; + var influences = {}; -THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + for ( var morphTargetName in usedMorphTargets ) { - var amount = options.amount !== undefined ? options.amount : 100; + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 - var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 - var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; + break; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + } - var steps = options.steps !== undefined ? options.steps : 1; + } - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; + if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { - var material = options.material; - var extrudeMaterial = options.extrudeMaterial; + influences[ morphTargetName ] = 0; - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + } - var shapebb = this.shapebb; - //shapebb = shape.getBoundingBox(); + } + data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + } - var splineTube, binormal, normal, position2; - if ( extrudePath ) { + } - extrudePts = extrudePath.getSpacedPoints( steps ); - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + // remove all keys that are on the same time - // SETUP TNB variables + for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { - // Reuse TNB from TubeGeomtry for now. - // TODO1 - have a .isClosed in spline? + if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { - splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + data.hierarchy[ h ].keys.splice( k, 1 ); + k --; - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + } - binormal = new THREE.Vector3(); - normal = new THREE.Vector3(); - position2 = new THREE.Vector3(); + } - } - // Safeguards if bevels are not enabled + // set index - if ( ! bevelEnabled ) { + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; + data.hierarchy[ h ].keys[ k ].index = k; - } + } - // Variables initalization + } - var ahole, h, hl; // looping of holes - var scope = this; - var bevelPoints = []; + data.initialized = true; - var shapesOffset = this.vertices.length; + return data; - var shapePoints = shape.extractPoints( curveSegments ); + }, - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + parse: function ( root ) { - var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; + var parseRecurseHierarchy = function ( root, hierarchy ) { - if ( reverse ) { + hierarchy.push( root ); - vertices = vertices.reverse(); + for ( var c = 0; c < root.children.length; c ++ ) + parseRecurseHierarchy( root.children[ c ], hierarchy ); - // Maybe we should also check if holes are in the opposite direction, just to be safe ... + }; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + // setup hierarchy - ahole = holes[ h ]; + var hierarchy = []; - if ( THREE.Shape.Utils.isClockWise( ahole ) ) { + if ( root instanceof THREE.SkinnedMesh ) { - holes[ h ] = ahole.reverse(); + for ( var b = 0; b < root.skeleton.bones.length; b ++ ) { + + hierarchy.push( root.skeleton.bones[ b ] ); } + } else { + + parseRecurseHierarchy( root, hierarchy ); + } - reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + return hierarchy; - } + }, + play: function ( animation ) { - var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); + if ( this.animations.indexOf( animation ) === - 1 ) { - /* Vertices */ + this.animations.push( animation ); - var contour = vertices; // vertices has all points but contour has only points of circumference + } - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + }, - ahole = holes[ h ]; + stop: function ( animation ) { - vertices = vertices.concat( ahole ); + var index = this.animations.indexOf( animation ); - } + if ( index !== - 1 ) { + this.animations.splice( index, 1 ); - function scalePt2 ( pt, vec, size ) { + } - if ( !vec ) console.log( "die" ); + }, - return vec.clone().multiplyScalar( size ).add( pt ); + update: function ( deltaTimeMS ) { - } + for ( var i = 0; i < this.animations.length; i ++ ) { - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length, - cont, clen = contour.length; + this.animations[ i ].resetBlendWeights( ); + } - // Find directions for point movement + for ( var i = 0; i < this.animations.length; i ++ ) { - var RAD_TO_DEGREES = 180 / Math.PI; + this.animations[ i ].update( deltaTimeMS ); + } - function getBevelVec( pt_i, pt_j, pt_k ) { + } - // Algorithm 2 +}; - return getBevelVec2( pt_i, pt_j, pt_k ); +// File:src/extras/animation/Animation.js - } +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - function getBevelVec1( pt_i, pt_j, pt_k ) { +THREE.Animation = function ( root, data ) { - var anglea = Math.atan2( pt_j.y - pt_i.y, pt_j.x - pt_i.x ); - var angleb = Math.atan2( pt_k.y - pt_i.y, pt_k.x - pt_i.x ); + this.root = root; + this.data = THREE.AnimationHandler.init( data ); + this.hierarchy = THREE.AnimationHandler.parse( root ); - if ( anglea > angleb ) { + this.currentTime = 0; + this.timeScale = 1; - angleb += Math.PI * 2; + this.isPlaying = false; + this.loop = true; + this.weight = 0; - } + this.interpolationType = THREE.AnimationHandler.LINEAR; - var anglec = ( anglea + angleb ) / 2; +}; +THREE.Animation.prototype = { - //console.log('angle1', anglea * RAD_TO_DEGREES,'angle2', angleb * RAD_TO_DEGREES, 'anglec', anglec *RAD_TO_DEGREES); + constructor: THREE.Animation, - var x = - Math.cos( anglec ); - var y = - Math.sin( anglec ); + keyTypes: [ "pos", "rot", "scl" ], - var vec = new THREE.Vector2( x, y ); //.normalize(); + play: function ( startTime, weight ) { - return vec; + this.currentTime = startTime !== undefined ? startTime : 0; + this.weight = weight !== undefined ? weight : 1; - } + this.isPlaying = true; - function getBevelVec2( pt_i, pt_j, pt_k ) { + this.reset(); - var a = THREE.ExtrudeGeometry.__v1, - b = THREE.ExtrudeGeometry.__v2, - v_hat = THREE.ExtrudeGeometry.__v3, - w_hat = THREE.ExtrudeGeometry.__v4, - p = THREE.ExtrudeGeometry.__v5, - q = THREE.ExtrudeGeometry.__v6, - v, w, - v_dot_w_hat, q_sub_p_dot_w_hat, - s, intersection; + THREE.AnimationHandler.play( this ); - // good reading for line-line intersection - // http://sputsoft.com/blog/2010/03/line-line-intersection.html + }, - // define a as vector j->i - // define b as vectot k->i + stop: function() { - a.set( pt_i.x - pt_j.x, pt_i.y - pt_j.y ); - b.set( pt_i.x - pt_k.x, pt_i.y - pt_k.y ); + this.isPlaying = false; - // get unit vectors + THREE.AnimationHandler.stop( this ); - v = a.normalize(); - w = b.normalize(); + }, - // normals from pt i + reset: function () { - v_hat.set( -v.y, v.x ); - w_hat.set( w.y, -w.x ); + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - // pts from i + var object = this.hierarchy[ h ]; - p.copy( pt_i ).add( v_hat ); - q.copy( pt_i ).add( w_hat ); + if ( object.animationCache === undefined ) { - if ( p.equals( q ) ) { + object.animationCache = { + animations: {}, + blending: { + positionWeight: 0.0, + quaternionWeight: 0.0, + scaleWeight: 0.0 + } + }; + } - //console.log("Warning: lines are straight"); - return w_hat.clone(); + var name = this.data.name; + var animations = object.animationCache.animations; + var animationCache = animations[ name ]; - } + if ( animationCache === undefined ) { - // Points from j, k. helps prevents points cross overover most of the time + animationCache = { + prevKey: { pos: 0, rot: 0, scl: 0 }, + nextKey: { pos: 0, rot: 0, scl: 0 }, + originalMatrix: object.matrix + }; + + animations[ name ] = animationCache; - p.copy( pt_j ).add( v_hat ); - q.copy( pt_k ).add( w_hat ); + } - v_dot_w_hat = v.dot( w_hat ); - q_sub_p_dot_w_hat = q.sub( p ).dot( w_hat ); + // Get keys to match our current time - // We should not reach these conditions + for ( var t = 0; t < 3; t ++ ) { - if ( v_dot_w_hat === 0 ) { + var type = this.keyTypes[ t ]; - console.log( "Either infinite or no solutions!" ); + var prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + var nextKey = this.getNextKeyWith( type, h, 1 ); - if ( q_sub_p_dot_w_hat === 0 ) { + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - console.log( "Its finite solutions." ); + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - } else { + } - console.log( "Too bad, no solutions." ); + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; } } - s = q_sub_p_dot_w_hat / v_dot_w_hat; - - if ( s < 0 ) { - - // in case of emergecy, revert to algorithm 1. + }, - return getBevelVec1( pt_i, pt_j, pt_k ); + resetBlendWeights: function () { - } + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - intersection = v.multiplyScalar( s ).add( p ); + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache; - return intersection.sub( pt_i ).clone(); // Don't normalize!, otherwise sharp corners become ugly + if ( animationCache !== undefined ) { - } + var blending = animationCache.blending; - var contourMovements = []; + blending.positionWeight = 0.0; + blending.quaternionWeight = 0.0; + blending.scaleWeight = 0.0; - for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + } - if ( j === il ) j = 0; - if ( k === il ) k = 0; + } - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) + }, - var pt_i = contour[ i ]; - var pt_j = contour[ j ]; - var pt_k = contour[ k ]; + update: ( function() { - contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + var points = []; + var target = new THREE.Vector3(); + var newVector = new THREE.Vector3(); + var newQuat = new THREE.Quaternion(); - } + // Catmull-Rom spline - var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + var interpolateCatmullRom = function ( points, scale ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; - ahole = holes[ h ]; + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; - oneHoleMovements = []; + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + pa = points[ c[ 0 ] ]; + pb = points[ c[ 1 ] ]; + pc = points[ c[ 2 ] ]; + pd = points[ c[ 3 ] ]; - if ( j === il ) j = 0; - if ( k === il ) k = 0; + w2 = weight * weight; + w3 = weight * w2; - // (j)---(i)---(k) - oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); + v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); + v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); - } + return v3; - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); + }; - } + var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; - // Loop bevelSegments, 1 for the front, 1 for the back + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - for ( b = 0; b < bevelSegments; b ++ ) { - //for ( b = bevelSegments; b > 0; b -- ) { + }; - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); + return function ( delta ) { - //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved - //bs = bevelSize * t ; // linear + if ( this.isPlaying === false ) return; - // contract shape + this.currentTime += delta * this.timeScale; - for ( i = 0, il = contour.length; i < il; i ++ ) { + if ( this.weight === 0 ) + return; - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - //vert = scalePt( contour[ i ], contourCentroid, bs, false ); - v( vert.x, vert.y, - z ); + // - } + var duration = this.data.length; - // expand holes + if ( this.currentTime > duration || this.currentTime < 0 ) { - for ( h = 0, hl = holes.length; h < hl; h++ ) { + if ( this.loop ) { - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + this.currentTime %= duration; - for ( i = 0, il = ahole.length; i < il; i++ ) { + if ( this.currentTime < 0 ) + this.currentTime += duration; - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true ); + this.reset(); - v( vert.x, vert.y, -z ); + } else { - } + this.stop(); - } + } - } + } - bs = bevelSize; + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - // Back facing vertices + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache.animations[this.data.name]; + var blending = object.animationCache.blending; - for ( i = 0; i < vlen; i ++ ) { + // loop through pos/rot/scl - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + for ( var t = 0; t < 3; t ++ ) { - if ( !extrudeByPath ) { + // get keys - v( vert.x, vert.y, 0 ); + var type = this.keyTypes[ t ]; + var prevKey = animationCache.prevKey[ type ]; + var nextKey = animationCache.nextKey[ type ]; - } else { + if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) || + ( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) { - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); - normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); - binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - position2.copy( extrudePts[0] ).add(normal).add(binormal); + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - v( position2.x, position2.y, position2.z ); + } - } + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; - } + } - // Add stepped vertices... - // Including front facing vertices + var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - var s; + var prevXYZ = prevKey[ type ]; + var nextXYZ = nextKey[ type ]; - for ( s = 1; s <= steps; s ++ ) { + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; - for ( i = 0; i < vlen; i ++ ) { + // interpolate - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + if ( type === "pos" ) { - if ( !extrudeByPath ) { + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - v( vert.x, vert.y, amount / steps * s ); + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - } else { + // blend + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + object.position.lerp( newVector, proportionalWeight ); + blending.positionWeight += this.weight; - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); + points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; + points[ 1 ] = prevXYZ; + points[ 2 ] = nextXYZ; + points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; - position2.copy( extrudePts[s] ).add( normal ).add( binormal ); + scale = scale * 0.33 + 0.33; - v( position2.x, position2.y, position2.z ); + var currentPoint = interpolateCatmullRom( points, scale ); + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + blending.positionWeight += this.weight; - } + // blend - } + var vector = object.position; - } + vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight; + vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight; + vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight; + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - // Add bevel segments planes + var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { + target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + target.sub( vector ); + target.y = 0; + target.normalize(); - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); - //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); - bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; + var angle = Math.atan2( target.x, target.z ); + object.rotation.set( 0, angle, 0 ); - // contract shape + } - for ( i = 0, il = contour.length; i < il; i ++ ) { + } - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); + } else if ( type === "rot" ) { - } + THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale ); - // expand holes + // Avoid paying the cost of an additional slerp if we don't have to + if ( blending.quaternionWeight === 0 ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + object.quaternion.copy(newQuat); + blending.quaternionWeight = this.weight; - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + } else { - for ( i = 0, il = ahole.length; i < il; i ++ ) { + var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); + THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight ); + blending.quaternionWeight += this.weight; - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + } - if ( !extrudeByPath ) { + } else if ( type === "scl" ) { - v( vert.x, vert.y, amount + z ); + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - } else { + var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); + object.scale.lerp( newVector, proportionalWeight ); + blending.scaleWeight += this.weight; - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + } } } - } + return true; - } + }; - /* Faces */ + } )(), - // Top and bottom faces + getNextKeyWith: function ( type, h, key ) { - buildLidFaces(); + var keys = this.data.hierarchy[ h ].keys; - // Sides faces + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - buildSideFaces(); + key = key < keys.length - 1 ? key : keys.length - 1; + } else { - ///// Internal functions + key = key % keys.length; - function buildLidFaces() { + } - if ( bevelEnabled ) { + for ( ; key < keys.length; key ++ ) { - var layer = 0 ; // steps + 1 - var offset = vlen * layer; + if ( keys[ key ][ type ] !== undefined ) { - // Bottom faces + return keys[ key ]; - for ( i = 0; i < flen; i ++ ) { + } - face = faces[ i ]; - f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); + } - } + return this.data.hierarchy[ h ].keys[ 0 ]; - layer = steps + bevelSegments * 2; - offset = vlen * layer; + }, - // Top faces + getPrevKeyWith: function ( type, h, key ) { - for ( i = 0; i < flen; i ++ ) { + var keys = this.data.hierarchy[ h ].keys; - face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - } + key = key > 0 ? key : 0; } else { - // Bottom faces - - for ( i = 0; i < flen; i++ ) { + key = key >= 0 ? key : key + keys.length; - face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); + } - } - // Top faces + for ( ; key >= 0; key -- ) { - for ( i = 0; i < flen; i ++ ) { + if ( keys[ key ][ type ] !== undefined ) { - face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); + return keys[ key ]; } - } - } + } - // Create faces for the z-sides of the shape + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; - function buildSideFaces() { + } - var layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; +}; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { +// File:src/extras/animation/KeyFrameAnimation.js - ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author khang duong + * @author erik kitson + */ - //, true - layeroffset += ahole.length; +THREE.KeyFrameAnimation = function ( data ) { - } + this.root = data.node; + this.data = THREE.AnimationHandler.init( data ); + this.hierarchy = THREE.AnimationHandler.parse( this.root ); + this.currentTime = 0; + this.timeScale = 0.001; + this.isPlaying = false; + this.isPaused = true; + this.loop = true; - } + // initialize to first keyframes - function sidewalls( contour, layeroffset ) { + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - var j, k; - i = contour.length; + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + obj = this.hierarchy[h]; - while ( --i >= 0 ) { + if ( keys.length && sids ) { - j = i; - k = i - 1; - if ( k < 0 ) k = contour.length - 1; + for ( var s = 0; s < sids.length; s ++ ) { - //console.log('b', i,j, i-1, k,vertices.length); + var sid = sids[ s ], + next = this.getNextKeyWith( sid, h, 0 ); - var s = 0, sl = steps + bevelSegments * 2; + if ( next ) { - for ( s = 0; s < sl; s ++ ) { + next.apply( sid ); - var slen1 = vlen * s; - var slen2 = vlen * ( s + 1 ); + } - var a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; + } - f4( a, b, c, d, contour, s, sl, j, k ); + obj.matrixAutoUpdate = false; + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; - } } } +}; - function v( x, y, z ) { - - scope.vertices.push( new THREE.Vector3( x, y, z ) ); +THREE.KeyFrameAnimation.prototype = { - } + constructor: THREE.KeyFrameAnimation, - function f3( a, b, c, isBottom ) { + play: function ( startTime ) { - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; + this.currentTime = startTime !== undefined ? startTime : 0; - // normal, color, material - scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + if ( this.isPlaying === false ) { - var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); + this.isPlaying = true; - scope.faceVertexUvs[ 0 ].push( uvs ); + // reset key cache - } + var h, hl = this.hierarchy.length, + object, + node; - function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + for ( h = 0; h < hl; h ++ ) { - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - d += shapesOffset; + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; - scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); - scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); + if ( node.animationCache === undefined ) { - var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, - stepIndex, stepsLength, contourIndex1, contourIndex2 ); + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object.matrix; - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + } - } + var keys = this.data.hierarchy[h].keys; -}; + if (keys.length) { -THREE.ExtrudeGeometry.WorldUVGenerator = { + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; - generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, + this.startTime = Math.min( keys[0].time, this.startTime ); + this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, + } - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y; + } - return [ - new THREE.Vector2( ax, ay ), - new THREE.Vector2( bx, by ), - new THREE.Vector2( cx, cy ) - ]; + this.update( 0 ); - }, + } - generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + this.isPaused = false; - return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); + THREE.AnimationHandler.play( this ); }, - generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, - indexA, indexB, indexC, indexD, stepIndex, stepsLength, - contourIndex1, contourIndex2 ) { + stop: function () { - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, - az = geometry.vertices[ indexA ].z, + this.isPlaying = false; + this.isPaused = false; - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, - bz = geometry.vertices[ indexB ].z, + THREE.AnimationHandler.stop( this ); - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y, - cz = geometry.vertices[ indexC ].z, + // reset JIT matrix and remove cache - dx = geometry.vertices[ indexD ].x, - dy = geometry.vertices[ indexD ].y, - dz = geometry.vertices[ indexD ].z; + for ( var h = 0; h < this.data.hierarchy.length; h ++ ) { - if ( Math.abs( ay - by ) < 0.01 ) { - return [ - new THREE.Vector2( ax, 1 - az ), - new THREE.Vector2( bx, 1 - bz ), - new THREE.Vector2( cx, 1 - cz ), - new THREE.Vector2( dx, 1 - dz ) - ]; - } else { - return [ - new THREE.Vector2( ay, 1 - az ), - new THREE.Vector2( by, 1 - bz ), - new THREE.Vector2( cy, 1 - cz ), - new THREE.Vector2( dy, 1 - dz ) - ]; - } - } -}; + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; -THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); + if ( node.animationCache !== undefined ) { -/** - * @author jonobr1 / http://jonobr1.com - * - * Creates a one-sided polygonal geometry from a path shape. Similar to - * ExtrudeGeometry. - * - * parameters = { - * - * curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT. - * - * material: <int> // material index for front and back faces - * uvGenerator: <Object> // object that provides UV generator functions - * - * } - **/ + var original = node.animationCache.originalMatrix; -THREE.ShapeGeometry = function ( shapes, options ) { + original.copy( obj.matrix ); + obj.matrix = original; - THREE.Geometry.call( this ); + delete node.animationCache; - if ( shapes instanceof Array === false ) shapes = [ shapes ]; + } - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + } - this.addShapeList( shapes, options ); + }, - this.computeCentroids(); - this.computeFaceNormals(); + update: function ( delta ) { + + if ( this.isPlaying === false ) return; + + this.currentTime += delta * this.timeScale; -}; + // -THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + var duration = this.data.length; -/** - * Add an array of shapes to THREE.ShapeGeometry. - */ -THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { + if ( this.loop === true && this.currentTime > duration ) { - for ( var i = 0, l = shapes.length; i < l; i++ ) { + this.currentTime %= duration; - this.addShape( shapes[ i ], options ); + } - } + this.currentTime = Math.min( this.currentTime, duration ); - return this; + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { -}; + var object = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; -/** - * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. - */ -THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { + var keys = node.keys, + animationCache = node.animationCache; - if ( options === undefined ) options = {}; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - var material = options.material; - var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; + if ( keys.length ) { - var shapebb = this.shapebb; + var prevKey = animationCache.prevKey; + var nextKey = animationCache.nextKey; - // + if ( nextKey.time <= this.currentTime ) { - var i, l, hole, s; + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints( curveSegments ); + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + } - var reverse = !THREE.Shape.Utils.isClockWise( vertices ); + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; - if ( reverse ) { + } - vertices = vertices.reverse(); + if ( nextKey.time >= this.currentTime ) { - // Maybe we should also check if holes are in the opposite direction, just to be safe... + prevKey.interpolate( nextKey, this.currentTime ); - for ( i = 0, l = holes.length; i < l; i++ ) { + } else { - hole = holes[ i ]; + prevKey.interpolate( nextKey, nextKey.time ); - if ( THREE.Shape.Utils.isClockWise( hole ) ) { + } - holes[ i ] = hole.reverse(); + this.data.hierarchy[ h ].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; } } - reverse = false; + }, - } + getNextKeyWith: function ( sid, h, key ) { - var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; - // Vertices + for ( ; key < keys.length; key ++ ) { - var contour = vertices; + if ( keys[ key ].hasTarget( sid ) ) { - for ( i = 0, l = holes.length; i < l; i++ ) { + return keys[ key ]; - hole = holes[ i ]; - vertices = vertices.concat( hole ); + } - } + } - // + return keys[ 0 ]; - var vert, vlen = vertices.length; - var face, flen = faces.length; - var cont, clen = contour.length; + }, - for ( i = 0; i < vlen; i++ ) { + getPrevKeyWith: function ( sid, h, key ) { - vert = vertices[ i ]; + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; - this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); + for ( ; key >= 0; key -- ) { - } + if ( keys[ key ].hasTarget( sid ) ) { - for ( i = 0; i < flen; i++ ) { + return keys[ key ]; - face = faces[ i ]; + } - var a = face[ 0 ] + shapesOffset; - var b = face[ 1 ] + shapesOffset; - var c = face[ 2 ] + shapesOffset; + } - this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); + return keys[ keys.length - 1 ]; } }; +// File:src/extras/animation/MorphAnimation.js + /** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com + * @author willy-vvu / http://willy-vvu.github.io */ -// points - to create a closed torus, one must use a set of points -// like so: [ a, b, c, d, a ], see first is the same as last. -// segments - the number of circumference segments to create -// phiStart - the starting radian -// phiLength - the radian (0 to 2*PI) range of the lathed section -// 2*pi is a closed lathe, less than 2PI is a portion. -THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { - - THREE.Geometry.call( this ); - - segments = segments || 12; - phiStart = phiStart || 0; - phiLength = phiLength || 2 * Math.PI; - - var inversePointLength = 1.0 / ( points.length - 1 ); - var inverseSegments = 1.0 / segments; - - for ( var i = 0, il = segments; i <= il; i ++ ) { +THREE.MorphAnimation = function ( mesh ) { - var phi = phiStart + i * inverseSegments * phiLength; + this.mesh = mesh; + this.frames = mesh.morphTargetInfluences.length; + this.currentTime = 0; + this.duration = 1000; + this.loop = true; + this.lastFrame = 0; + this.currentFrame = 0; - var c = Math.cos( phi ), - s = Math.sin( phi ); + this.isPlaying = false; - for ( var j = 0, jl = points.length; j < jl; j ++ ) { +}; - var pt = points[ j ]; +THREE.MorphAnimation.prototype = { - var vertex = new THREE.Vector3(); + constructor: THREE.MorphAnimation, - vertex.x = c * pt.x - s * pt.y; - vertex.y = s * pt.x + c * pt.y; - vertex.z = pt.z; + play: function () { - this.vertices.push( vertex ); + this.isPlaying = true; - } + }, - } + pause: function () { - var np = points.length; + this.isPlaying = false; - for ( var i = 0, il = segments; i < il; i ++ ) { + }, - for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { + update: function ( delta ) { - var base = j + np * i; - var a = base; - var b = base + np; - var c = base + 1 + np; - var d = base + 1; + if ( this.isPlaying === false ) return; - var u0 = i * inverseSegments; - var v0 = j * inversePointLength; - var u1 = u0 + inverseSegments; - var v1 = v0 + inversePointLength; + this.currentTime += delta; - this.faces.push( new THREE.Face3( a, b, d ) ); + if ( this.loop === true && this.currentTime > this.duration ) { - this.faceVertexUvs[ 0 ].push( [ + this.currentTime %= this.duration; - new THREE.Vector2( u0, v0 ), - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u0, v1 ) + } - ] ); + this.currentTime = Math.min( this.currentTime, this.duration ); - this.faces.push( new THREE.Face3( b, c, d ) ); + var interpolation = this.duration / this.frames; + var frame = Math.floor( this.currentTime / interpolation ); - this.faceVertexUvs[ 0 ].push( [ + var influences = this.mesh.morphTargetInfluences; - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u0, v1 ) + if ( frame != this.currentFrame ) { - ] ); + influences[ this.lastFrame ] = 0; + influences[ this.currentFrame ] = 1; + influences[ frame ] = 0; + this.lastFrame = this.currentFrame; + this.currentFrame = frame; } - } + influences[ frame ] = ( this.currentTime % interpolation ) / interpolation; + influences[ this.lastFrame ] = 1 - influences[ frame ]; - this.mergeVertices(); - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); + } }; -THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); +// File:src/extras/geometries/BoxGeometry.js /** * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as */ -THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { +THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { THREE.Geometry.call( this ); - this.width = width; - this.height = height; + this.type = 'BoxGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; this.widthSegments = widthSegments || 1; this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; + + var scope = this; - var ix, iz; var width_half = width / 2; var height_half = height / 2; + var depth_half = depth / 2; - var gridX = this.widthSegments; - var gridZ = this.heightSegments; + buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx + buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py + buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny + buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz + buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz - var gridX1 = gridX + 1; - var gridZ1 = gridZ + 1; + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { - var segment_width = this.width / gridX; - var segment_height = this.height / gridZ; + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; - var normal = new THREE.Vector3( 0, 0, 1 ); + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { - for ( iz = 0; iz < gridZ1; iz ++ ) { + w = 'z'; - for ( ix = 0; ix < gridX1; ix ++ ) { + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { - var x = ix * segment_width - width_half; - var y = iz * segment_height - height_half; + w = 'y'; + gridY = scope.depthSegments; + + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { - this.vertices.push( new THREE.Vector3( x, - y, 0 ) ); + w = 'x'; + gridX = scope.depthSegments; } - } + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); + + normal[ w ] = depth > 0 ? 1 : - 1; + + for ( iy = 0; iy < gridY1; iy ++ ) { - for ( iz = 0; iz < gridZ; iz ++ ) { + for ( ix = 0; ix < gridX1; ix ++ ) { - for ( ix = 0; ix < gridX; ix ++ ) { + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; - var a = ix + gridX1 * iz; - var b = ix + gridX1 * ( iz + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iz + 1 ); - var d = ( ix + 1 ) + gridX1 * iz; + scope.vertices.push( vector ); - var uva = new THREE.Vector2( ix / gridX, 1 - iz / gridZ ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ ); + } - var face = new THREE.Face3( a, b, d ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + } - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + for ( iy = 0; iy < gridY; iy ++ ) { - face = new THREE.Face3( b, c, d ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + for ( ix = 0; ix < gridX; ix ++ ) { - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); + var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); + var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); + var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); + + var face = new THREE.Face3( a + offset, b + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + face = new THREE.Face3( b + offset, c + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } } } - this.computeCentroids(); + this.mergeVertices(); }; -THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; + +// File:src/extras/geometries/CircleGeometry.js /** - * @author Kaleb Murphy + * @author hughes */ -THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); - innerRadius = innerRadius || 0; - outerRadius = outerRadius || 50; + this.type = 'CircleGeometry'; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8; + radius = radius || 50; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring + var i, uvs = [], + center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + this.vertices.push(center); + uvs.push( centerUV ); - var vertex = new THREE.Vector3(); - var segment = thetaStart + o / thetaSegments * thetaLength; + for ( i = 0; i <= segments; i ++ ) { - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + var vertex = new THREE.Vector3(); + var segment = thetaStart + i / segments * thetaLength; - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, - ( vertex.y / radius + 1 ) / 2 + 1 ) ); - } + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - radius += radiusStep; + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); } var n = new THREE.Vector3( 0, 0, 1 ); - for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring + for ( i = 1; i <= segments; i ++ ) { + + this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); - var thetaSegment = i * thetaSegments; + } - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + this.computeFaceNormals(); - var segment = o + thetaSegment; + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - var v1 = segment + i; - var v2 = segment + thetaSegments + i; - var v3 = segment + thetaSegments + 1 + i; +}; - this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ], uvs[ v2 ], uvs[ v3 ] ]); +THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; - v1 = segment + i; - v2 = segment + thetaSegments + 1 + i; - v3 = segment + 1 + i; +// File:src/extras/geometries/CubeGeometry.js - this.faces.push( new THREE.Face3( v1, v2, v3, [ n, n, n ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ], uvs[ v2 ], uvs[ v3 ] ]); +/** + * @author mrdoob / http://mrdoob.com/ + */ - } - } - this.computeCentroids(); - this.computeFaceNormals(); +THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); + return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); -}; + }; -THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); +// File:src/extras/geometries/CylinderGeometry.js /** * @author mrdoob / http://mrdoob.com/ */ -THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { THREE.Geometry.call( this ); - this.radius = radius = radius || 50; + this.type = 'CylinderGeometry'; + + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; + + radiusTop = radiusTop !== undefined ? radiusTop : 20; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + height = height !== undefined ? height : 100; - this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); - this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); + radialSegments = radialSegments || 8; + heightSegments = heightSegments || 1; - this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0; - this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; - this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; - this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + var heightHalf = height / 2; var x, y, vertices = [], uvs = []; @@ -32952,15 +30919,17 @@ THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStar var verticesRow = []; var uvsRow = []; - for ( x = 0; x <= widthSegments; x ++ ) { + var v = y / heightSegments; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - var u = x / widthSegments; - var v = y / heightSegments; + for ( x = 0; x <= radialSegments; x ++ ) { + + var u = x / radialSegments; var vertex = new THREE.Vector3(); - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.x = radius * Math.sin( u * thetaLength + thetaStart ); + vertex.y = - v * height + heightHalf; + vertex.z = radius * Math.cos( u * thetaLength + thetaStart ); this.vertices.push( vertex ); @@ -32974,4007 +30943,4191 @@ THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStar } - for ( y = 0; y < this.heightSegments; y ++ ) { - - for ( x = 0; x < this.widthSegments; x ++ ) { - - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = vertices[ y + 1 ][ x ]; - var v4 = vertices[ y + 1 ][ x + 1 ]; - - var n1 = this.vertices[ v1 ].clone().normalize(); - var n2 = this.vertices[ v2 ].clone().normalize(); - var n3 = this.vertices[ v3 ].clone().normalize(); - var n4 = this.vertices[ v4 ].clone().normalize(); - - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x ].clone(); - var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); - - if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) { - - this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); - - } else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) { + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + for ( x = 0; x < radialSegments; x ++ ) { - } else { + if ( radiusTop !== 0 ) { - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + } else { - } + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); } - } - - this.computeCentroids(); - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For creating 3D text geometry in three.js - * - * Text = 3D Text - * - * parameters = { - * size: <float>, // size of the text - * height: <float>, // thickness to extrude text - * curveSegments: <int>, // number of points on the curves - * - * font: <string>, // font name - * weight: <string>, // font weight (normal, bold) - * style: <string>, // font style (normal, italics) - * - * bevelEnabled: <bool>, // turn on bevel - * bevelThickness: <float>, // how deep into text bevel goes - * bevelSize: <float>, // how far from text outline is bevel - * } - * - */ - -/* Usage Examples - - // TextGeometry wrapper - - var text3d = new TextGeometry( text, options ); - - // Complete manner - - var textShapes = THREE.FontUtils.generateShapes( text, options ); - var text3d = new ExtrudeGeometry( textShapes, options ); - -*/ - - -THREE.TextGeometry = function ( text, parameters ) { - - parameters = parameters || {}; - - var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - - // translate parameters to ExtrudeGeometry API - - parameters.amount = parameters.height !== undefined ? parameters.height : 50; - - // defaults - - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); + nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); - THREE.ExtrudeGeometry.call( this, textShapes, parameters ); + for ( y = 0; y < heightSegments; y ++ ) { -}; + var v1 = vertices[ y ][ x ]; + var v2 = vertices[ y + 1 ][ x ]; + var v3 = vertices[ y + 1 ][ x + 1 ]; + var v4 = vertices[ y ][ x + 1 ]; -THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); -/** - * @author oosmoxiecode - * @author mrdoob / http://mrdoob.com/ - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 - */ + var uv1 = uvs[ y ][ x ].clone(); + var uv2 = uvs[ y + 1 ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); + var uv4 = uvs[ y ][ x + 1 ].clone(); -THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - THREE.Geometry.call( this ); + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - var scope = this; + } - this.radius = radius || 100; - this.tube = tube || 40; - this.radialSegments = radialSegments || 8; - this.tubularSegments = tubularSegments || 6; - this.arc = arc || Math.PI * 2; + } - var center = new THREE.Vector3(), uvs = [], normals = []; + // top cap - for ( var j = 0; j <= this.radialSegments; j ++ ) { + if ( openEnded === false && radiusTop > 0 ) { - for ( var i = 0; i <= this.tubularSegments; i ++ ) { + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); - var u = i / this.tubularSegments * this.arc; - var v = j / this.radialSegments * Math.PI * 2; + for ( x = 0; x < radialSegments; x ++ ) { - center.x = this.radius * Math.cos( u ); - center.y = this.radius * Math.sin( u ); + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; - var vertex = new THREE.Vector3(); - vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = this.tube * Math.sin( v ); + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); - this.vertices.push( vertex ); + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 0 ); - uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) ); - normals.push( vertex.clone().sub( center ).normalize() ); + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } - } + } - for ( var j = 1; j <= this.radialSegments; j ++ ) { + // bottom cap - for ( var i = 1; i <= this.tubularSegments; i ++ ) { + if ( openEnded === false && radiusBottom > 0 ) { - var a = ( this.tubularSegments + 1 ) * j + i - 1; - var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1; - var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i; - var d = ( this.tubularSegments + 1 ) * j + i; + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); - var face = new THREE.Face3( a, b, d, [ normals[ a ], normals[ b ], normals[ d ] ] ); - face.normal.add( normals[ a ] ); - face.normal.add( normals[ b ] ); - face.normal.add( normals[ d ] ); - face.normal.normalize(); + for ( x = 0; x < radialSegments; x ++ ) { - this.faces.push( face ); + var v1 = vertices[ heightSegments ][ x + 1 ]; + var v2 = vertices[ heightSegments ][ x ]; + var v3 = this.vertices.length - 1; - this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); - face = new THREE.Face3( b, c, d, [ normals[ b ], normals[ c ], normals[ d ] ] ); - face.normal.add( normals[ b ] ); - face.normal.add( normals[ c ] ); - face.normal.add( normals[ d ] ); - face.normal.normalize(); + var uv1 = uvs[ heightSegments ][ x + 1 ].clone(); + var uv2 = uvs[ heightSegments ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 1 ); - this.faces.push( face ); + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); } } - this.computeCentroids(); + this.computeFaceNormals(); }; -THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author oosmoxiecode - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 - */ - -THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { - - THREE.Geometry.call( this ); - - var scope = this; - - this.radius = radius || 100; - this.tube = tube || 40; - this.radialSegments = radialSegments || 64; - this.tubularSegments = tubularSegments || 8; - this.p = p || 2; - this.q = q || 3; - this.heightScale = heightScale || 1; - this.grid = new Array( this.radialSegments ); - - var tang = new THREE.Vector3(); - var n = new THREE.Vector3(); - var bitan = new THREE.Vector3(); - - for ( var i = 0; i < this.radialSegments; ++ i ) { +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry; - this.grid[ i ] = new Array( this.tubularSegments ); - var u = i / this.radialSegments * 2 * this.p * Math.PI; - var p1 = getPos( u, this.q, this.p, this.radius, this.heightScale ); - var p2 = getPos( u + 0.01, this.q, this.p, this.radius, this.heightScale ); - tang.subVectors( p2, p1 ); - n.addVectors( p2, p1 ); +// File:src/extras/geometries/ExtrudeGeometry.js - bitan.crossVectors( tang, n ); - n.crossVectors( bitan, tang ); - bitan.normalize(); - n.normalize(); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * curveSegments: <int>, // number of points on the curves + * steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too + * amount: <int>, // Depth to extrude the shape + * + * bevelEnabled: <bool>, // turn on bevel + * bevelThickness: <float>, // how deep into the original shape bevel goes + * bevelSize: <float>, // how far from shape outline is bevel + * bevelSegments: <int>, // number of bevel layers + * + * extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) + * frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals + * + * material: <int> // material index for front and back faces + * extrudeMaterial: <int> // material index for extrusion and beveled faces + * uvGenerator: <Object> // object that provides UV generator functions + * + * } + **/ - for ( var j = 0; j < this.tubularSegments; ++ j ) { +THREE.ExtrudeGeometry = function ( shapes, options ) { - var v = j / this.tubularSegments * 2 * Math.PI; - var cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - var cy = this.tube * Math.sin( v ); + if ( typeof( shapes ) === "undefined" ) { + shapes = []; + return; + } - var pos = new THREE.Vector3(); - pos.x = p1.x + cx * n.x + cy * bitan.x; - pos.y = p1.y + cx * n.y + cy * bitan.y; - pos.z = p1.z + cx * n.z + cy * bitan.z; + THREE.Geometry.call( this ); - this.grid[ i ][ j ] = scope.vertices.push( pos ) - 1; + this.type = 'ExtrudeGeometry'; - } + shapes = shapes instanceof Array ? shapes : [ shapes ]; - } + this.addShapeList( shapes, options ); - for ( var i = 0; i < this.radialSegments; ++ i ) { + this.computeFaceNormals(); - for ( var j = 0; j < this.tubularSegments; ++ j ) { + // can't really use automatic vertex normals + // as then front and back sides get smoothed too + // should do separate smoothing just for sides - var ip = ( i + 1 ) % this.radialSegments; - var jp = ( j + 1 ) % this.tubularSegments; + //this.computeVertexNormals(); - var a = this.grid[ i ][ j ]; - var b = this.grid[ ip ][ j ]; - var c = this.grid[ ip ][ jp ]; - var d = this.grid[ i ][ jp ]; + //console.log( "took", ( Date.now() - startTime ) ); - var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments ); - var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments ); - var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments ); - var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments ); +}; - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); +THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + var sl = shapes.length; - } + for ( var s = 0; s < sl; s ++ ) { + var shape = shapes[ s ]; + this.addShape( shape, options ); } +}; - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - - function getPos( u, in_q, in_p, radius, heightScale ) { +THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = in_q / in_p * u; - var cs = Math.cos( quOverP ); + var amount = options.amount !== undefined ? options.amount : 100; - var tx = radius * ( 2 + cs ) * 0.5 * cu; - var ty = radius * ( 2 + cs ) * su * 0.5; - var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; + var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 + var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 + var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - return new THREE.Vector3( tx, ty, tz ); + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false - } + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; -}; + var steps = options.steps !== undefined ? options.steps : 1; -THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; -/** - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * - * Modified from the TorusKnotGeometry by @oosmoxiecode - * - * Creates a tube which extrudes along a 3d spline - * - * Uses parallel transport frames as described in - * http://www.cs.indiana.edu/pub/techreports/TR425.pdf - */ + var material = options.material; + var extrudeMaterial = options.extrudeMaterial; -THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) { + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; - THREE.Geometry.call( this ); + var splineTube, binormal, normal, position2; + if ( extrudePath ) { - this.path = path; - this.segments = segments || 64; - this.radius = radius || 1; - this.radialSegments = radialSegments || 8; - this.closed = closed || false; + extrudePts = extrudePath.getSpacedPoints( steps ); - this.grid = []; + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion - var scope = this, + // SETUP TNB variables - tangent, - normal, - binormal, + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? - numpoints = this.segments + 1, + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); - x, y, z, - tx, ty, tz, - u, v, + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - cx, cy, - pos, pos2 = new THREE.Vector3(), - i, j, - ip, jp, - a, b, c, d, - uva, uvb, uvc, uvd; + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); - var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ), - tangents = frames.tangents, - normals = frames.normals, - binormals = frames.binormals; + } - // proxy internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; + // Safeguards if bevels are not enabled - function vert( x, y, z ) { + if ( ! bevelEnabled ) { - return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; } + // Variables initalization - // consruct the grid + var ahole, h, hl; // looping of holes + var scope = this; - for ( i = 0; i < numpoints; i++ ) { + var shapesOffset = this.vertices.length; - this.grid[ i ] = []; + var shapePoints = shape.extractPoints( curveSegments ); - u = i / ( numpoints - 1 ); + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - pos = path.getPointAt( u ); + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ) ; - tangent = tangents[ i ]; - normal = normals[ i ]; - binormal = binormals[ i ]; + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe ... - for ( j = 0; j < this.radialSegments; j++ ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - v = j / this.radialSegments * 2 * Math.PI; + ahole = holes[ h ]; - cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - cy = this.radius * Math.sin( v ); + if ( THREE.Shape.Utils.isClockWise( ahole ) ) { - pos2.copy( pos ); - pos2.x += cx * normal.x + cy * binormal.x; - pos2.y += cx * normal.y + cy * binormal.y; - pos2.z += cx * normal.z + cy * binormal.z; + holes[ h ] = ahole.reverse(); - this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + } } - } + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! - // construct the mesh + } - for ( i = 0; i < this.segments; i++ ) { - for ( j = 0; j < this.radialSegments; j++ ) { + var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); - ip = ( this.closed ) ? (i + 1) % this.segments : i + 1; - jp = (j + 1) % this.radialSegments; + /* Vertices */ - a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** - b = this.grid[ ip ][ j ]; - c = this.grid[ ip ][ jp ]; - d = this.grid[ i ][ jp ]; + var contour = vertices; // vertices has all points but contour has only points of circumference - uva = new THREE.Vector2( i / this.segments, j / this.radialSegments ); - uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radialSegments ); - uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radialSegments ); - uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radialSegments ); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + ahole = holes[ h ]; - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + vertices = vertices.concat( ahole ); - } } - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; -THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + function scalePt2 ( pt, vec, size ) { + if ( ! vec ) THREE.error( "THREE.ExtrudeGeometry: vec does not exist" ); -// For computing of Frenet frames, exposing the tangents, normals and binormals the spline -THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { + return vec.clone().multiplyScalar( size ).add( pt ); - var tangent = new THREE.Vector3(), - normal = new THREE.Vector3(), - binormal = new THREE.Vector3(), + } - tangents = [], - normals = [], - binormals = [], + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length; - vec = new THREE.Vector3(), - mat = new THREE.Matrix4(), - numpoints = segments + 1, - theta, - epsilon = 0.0001, - smallest, + // Find directions for point movement - tx, ty, tz, - i, u, v; + function getBevelVec( inPt, inPrev, inNext ) { - // expose internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; + var EPSILON = 0.0000000001; + + // computes for inPt the corresponding point inPt' on a new contour + // shiftet by 1 unit (length of normalized vector) to the left + // if we walk along contour clockwise, this new contour is outside the old one + // + // inPt' is the intersection of the two lines parallel to the two + // adjacent edges of inPt at a distance of 1 unit on the left side. + + var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt + + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html + + var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; + var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; + + var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + + // check for colinear edges + var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear + + // length of vectors for normalizing + + var v_prev_len = Math.sqrt( v_prev_lensq ); + var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + + // shift adjacent points by unit vectors to the left + + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + + // scaling factor for v_prev to intersection point + + var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + // vector from inPt to intersection point + + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ) + if ( v_trans_lensq <= 2 ) { + return new THREE.Vector2( v_trans_x, v_trans_y ); + } else { + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + } + + } else { // handle special case of colinear edges - // compute the tangent vectors for each segment on the path + var direction_eq = false; // assumes: opposite + if ( v_prev_x > EPSILON ) { + if ( v_next_x > EPSILON ) { direction_eq = true; } + } else { + if ( v_prev_x < - EPSILON ) { + if ( v_next_x < - EPSILON ) { direction_eq = true; } + } else { + if ( Math.sign(v_prev_y) == Math.sign(v_next_y) ) { direction_eq = true; } + } + } - for ( i = 0; i < numpoints; i++ ) { + if ( direction_eq ) { + // console.log("Warning: lines are a straight sequence"); + v_trans_x = - v_prev_y; + v_trans_y = v_prev_x; + shrink_by = Math.sqrt( v_prev_lensq ); + } else { + // console.log("Warning: lines are a straight spike"); + v_trans_x = v_prev_x; + v_trans_y = v_prev_y; + shrink_by = Math.sqrt( v_prev_lensq / 2 ); + } - u = i / ( numpoints - 1 ); + } - tangents[ i ] = path.getTangentAt( u ); - tangents[ i ].normalize(); + return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); } - initialNormal3(); - function initialNormal1(lastBinormal) { - // fixed start binormal. Has dangers of 0 vectors - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); - normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - } + var contourMovements = []; - function initialNormal2() { + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - // This uses the Frenet-Serret formula for deriving binormal - var t2 = path.getTangentAt( epsilon ); + if ( j === il ) j = 0; + if ( k === il ) k = 0; - normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); - binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); } - function initialNormal3() { - // select an initial normal vector perpenicular to the first tangent vector, - // and in the direction of the smallest tangent xyz component + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - smallest = Number.MAX_VALUE; - tx = Math.abs( tangents[ 0 ].x ); - ty = Math.abs( tangents[ 0 ].y ); - tz = Math.abs( tangents[ 0 ].z ); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - if ( tx <= smallest ) { - smallest = tx; - normal.set( 1, 0, 0 ); - } + ahole = holes[ h ]; - if ( ty <= smallest ) { - smallest = ty; - normal.set( 0, 1, 0 ); - } + oneHoleMovements = []; + + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - if ( tz <= smallest ) { - normal.set( 0, 0, 1 ); } - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); } - // compute the slowly-varying normal and binormal vectors for each segment on the path + // Loop bevelSegments, 1 for the front, 1 for the back + + for ( b = 0; b < bevelSegments; b ++ ) { + //for ( b = bevelSegments; b > 0; b -- ) { + + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + + //z = bevelThickness * t; + bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ) ; // curved + //bs = bevelSize * t ; // linear + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - for ( i = 1; i < numpoints; i++ ) { + v( vert.x, vert.y, - z ); - normals[ i ] = normals[ i-1 ].clone(); + } - binormals[ i ] = binormals[ i-1 ].clone(); + // expand holes - vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - if ( vec.length() > epsilon ) { + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - vec.normalize(); + for ( i = 0, il = ahole.length; i < il; i ++ ) { - theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + v( vert.x, vert.y, - z ); - } + } - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + } } + bs = bevelSize; - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + // Back facing vertices - if ( closed ) { + for ( i = 0; i < vlen; i ++ ) { - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); - theta /= ( numpoints - 1 ); + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { + if ( ! extrudeByPath ) { - theta = -theta; + v( vert.x, vert.y, 0 ); - } + } else { - for ( i = 1; i < numpoints; i++ ) { + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); + binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); + + position2.copy( extrudePts[0] ).add(normal).add(binormal); + + v( position2.x, position2.y, position2.z ); } } -}; -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley -*/ + // Add stepped vertices... + // Including front facing vertices -THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { + var s; - THREE.Geometry.call( this ); + for ( s = 1; s <= steps; s ++ ) { - radius = radius || 1; - detail = detail || 0; + for ( i = 0; i < vlen; i ++ ) { - var that = this; + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - for ( var i = 0, l = vertices.length; i < l; i ++ ) { + if ( ! extrudeByPath ) { - prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) ); + v( vert.x, vert.y, amount / steps * s ); - } + } else { - var midpoints = [], p = this.vertices; + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - var f = []; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); + + position2.copy( extrudePts[s] ).add( normal ).add( binormal ); + + v( position2.x, position2.y, position2.z ); - var v1 = p[ faces[ i ][ 0 ] ]; - var v2 = p[ faces[ i ][ 1 ] ]; - var v3 = p[ faces[ i ][ 2 ] ]; + } - f[ i ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + } } - for ( var i = 0, l = f.length; i < l; i ++ ) { - subdivide(f[ i ], detail); + // Add bevel segments planes - } + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); + bs = bevelSize * Math.sin ( t * Math.PI / 2 ) ; - // Handle case when face straddles the seam + // contract shape - for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { + for ( i = 0, il = contour.length; i < il; i ++ ) { - var uvs = this.faceVertexUvs[ 0 ][ i ]; + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, amount + z ); - var x0 = uvs[ 0 ].x; - var x1 = uvs[ 1 ].x; - var x2 = uvs[ 2 ].x; + } - var max = Math.max( x0, Math.max( x1, x2 ) ); - var min = Math.min( x0, Math.min( x1, x2 ) ); + // expand holes - if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - if ( x0 < 0.2 ) uvs[ 0 ].x += 1; - if ( x1 < 0.2 ) uvs[ 1 ].x += 1; - if ( x2 < 0.2 ) uvs[ 2 ].x += 1; + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - } + for ( i = 0, il = ahole.length; i < il; i ++ ) { - } + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + if ( ! extrudeByPath ) { - // Apply radius + v( vert.x, vert.y, amount + z ); - for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + } else { - this.vertices[ i ].multiplyScalar( radius ); + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - } + } + } - // Merge vertices + } - this.mergeVertices(); + } - this.computeCentroids(); + /* Faces */ - this.computeFaceNormals(); + // Top and bottom faces - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + buildLidFaces(); + // Sides faces - // Project vector onto sphere's surface + buildSideFaces(); - function prepare( vector ) { - var vertex = vector.normalize().clone(); - vertex.index = that.vertices.push( vertex ) - 1; + ///// Internal functions - // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + function buildLidFaces() { - var u = azimuth( vector ) / 2 / Math.PI + 0.5; - var v = inclination( vector ) / Math.PI + 0.5; - vertex.uv = new THREE.Vector2( u, 1 - v ); + if ( bevelEnabled ) { - return vertex; + var layer = 0 ; // steps + 1 + var offset = vlen * layer; - } + // Bottom faces + for ( i = 0; i < flen; i ++ ) { - // Approximate a curved face with recursively sub-divided triangles. + face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - function make( v1, v2, v3 ) { + } - var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - that.faces.push( face ); + layer = steps + bevelSegments * 2; + offset = vlen * layer; - var azi = azimuth( face.centroid ); + // Top faces - that.faceVertexUvs[ 0 ].push( [ - correctUV( v1.uv, v1, azi ), - correctUV( v2.uv, v2, azi ), - correctUV( v3.uv, v3, azi ) - ] ); + for ( i = 0; i < flen; i ++ ) { - } + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); + } - // Analytically subdivide a face to the required detail level. + } else { - function subdivide(face, detail ) { + // Bottom faces - var cols = Math.pow(2, detail); - var cells = Math.pow(4, detail); - var a = prepare( that.vertices[ face.a ] ); - var b = prepare( that.vertices[ face.b ] ); - var c = prepare( that.vertices[ face.c ] ); - var v = []; + for ( i = 0; i < flen; i ++ ) { - // Construct all of the vertices for this subdivision. + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - for ( var i = 0 ; i <= cols; i ++ ) { + } - v[ i ] = []; + // Top faces - var aj = prepare( a.clone().lerp( c, i / cols ) ); - var bj = prepare( b.clone().lerp( c, i / cols ) ); - var rows = cols - i; + for ( i = 0; i < flen; i ++ ) { - for ( var j = 0; j <= rows; j ++) { + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - if ( j == 0 && i == cols ) { + } + } - v[ i ][ j ] = aj; + } - } else { + // Create faces for the z-sides of the shape - v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); + function buildSideFaces() { - } + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); + + //, true + layeroffset += ahole.length; } - // Construct all of the faces. + } - for ( var i = 0; i < cols ; i ++ ) { + function sidewalls( contour, layeroffset ) { - for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { + var j, k; + i = contour.length; - var k = Math.floor( j / 2 ); + while ( -- i >= 0 ) { - if ( j % 2 == 0 ) { + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; - make( - v[ i ][ k + 1], - v[ i + 1 ][ k ], - v[ i ][ k ] - ); + //console.log('b', i,j, i-1, k,vertices.length); - } else { + var s = 0, sl = steps + bevelSegments * 2; - make( - v[ i ][ k + 1 ], - v[ i + 1][ k + 1], - v[ i + 1 ][ k ] - ); + for ( s = 0; s < sl; s ++ ) { - } + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); - } + var a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; + + f4( a, b, c, d, contour, s, sl, j, k ); + } } } - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { + function v( x, y, z ) { - return Math.atan2( vector.z, -vector.x ); + scope.vertices.push( new THREE.Vector3( x, y, z ) ); } + function f3( a, b, c ) { - // Angle above the XZ plane. + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; - function inclination( vector ) { + // normal, color, material + scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + + var uvs = uvgen.generateTopUV( scope, a, b, c ); - return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + scope.faceVertexUvs[ 0 ].push( uvs ); } + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { - // Texture fixing helper. Spheres have some odd behaviours. + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; - function correctUV( uv, vector, azimuth ) { + scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); + scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); - return uv.clone(); + var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); - } + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + } }; -THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ExtrudeGeometry.WorldUVGenerator = { -/** - * @author timothypratley / https://github.com/timothypratley - */ + generateTopUV: function ( geometry, indexA, indexB, indexC ) { -THREE.IcosahedronGeometry = function ( radius, detail ) { + var vertices = geometry.vertices; - this.radius = radius; - this.detail = detail; + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; - var t = ( 1 + Math.sqrt( 5 ) ) / 2; + return [ + new THREE.Vector2( a.x, a.y ), + new THREE.Vector2( b.x, b.y ), + new THREE.Vector2( c.x, c.y ) + ]; - var vertices = [ - [ -1, t, 0 ], [ 1, t, 0 ], [ -1, -t, 0 ], [ 1, -t, 0 ], - [ 0, -1, t ], [ 0, 1, t ], [ 0, -1, -t ], [ 0, 1, -t ], - [ t, 0, -1 ], [ t, 0, 1 ], [ -t, 0, -1 ], [ -t, 0, 1 ] - ]; + }, - var faces = [ - [ 0, 11, 5 ], [ 0, 5, 1 ], [ 0, 1, 7 ], [ 0, 7, 10 ], [ 0, 10, 11 ], - [ 1, 5, 9 ], [ 5, 11, 4 ], [ 11, 10, 2 ], [ 10, 7, 6 ], [ 7, 1, 8 ], - [ 3, 9, 4 ], [ 3, 4, 2 ], [ 3, 2, 6 ], [ 3, 6, 8 ], [ 3, 8, 9 ], - [ 4, 9, 5 ], [ 2, 4, 11 ], [ 6, 2, 10 ], [ 8, 6, 7 ], [ 9, 8, 1 ] - ]; + generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { + + var vertices = geometry.vertices; - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; + var d = vertices[ indexD ]; + if ( Math.abs( a.y - b.y ) < 0.01 ) { + return [ + new THREE.Vector2( a.x, 1 - a.z ), + new THREE.Vector2( b.x, 1 - b.z ), + new THREE.Vector2( c.x, 1 - c.z ), + new THREE.Vector2( d.x, 1 - d.z ) + ]; + } else { + return [ + new THREE.Vector2( a.y, 1 - a.z ), + new THREE.Vector2( b.y, 1 - b.z ), + new THREE.Vector2( c.y, 1 - c.z ), + new THREE.Vector2( d.y, 1 - d.z ) + ]; + } + } }; -THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +// File:src/extras/geometries/ShapeGeometry.js /** - * @author timothypratley / https://github.com/timothypratley - */ + * @author jonobr1 / http://jonobr1.com + * + * Creates a one-sided polygonal geometry from a path shape. Similar to + * ExtrudeGeometry. + * + * parameters = { + * + * curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT. + * + * material: <int> // material index for front and back faces + * uvGenerator: <Object> // object that provides UV generator functions + * + * } + **/ -THREE.OctahedronGeometry = function ( radius, detail ) { +THREE.ShapeGeometry = function ( shapes, options ) { - var vertices = [ - [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ] - ]; + THREE.Geometry.call( this ); - var faces = [ - [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ] - ]; + this.type = 'ShapeGeometry'; + + if ( shapes instanceof Array === false ) shapes = [ shapes ]; + + this.addShapeList( shapes, options ); + + this.computeFaceNormals(); - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); }; -THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry; /** - * @author timothypratley / https://github.com/timothypratley + * Add an array of shapes to THREE.ShapeGeometry. */ +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { -THREE.TetrahedronGeometry = function ( radius, detail ) { + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - var vertices = [ - [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] - ]; + this.addShape( shapes[ i ], options ); - var faces = [ - [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ] - ]; + } - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + return this; }; -THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); - /** - * @author zz85 / https://github.com/zz85 - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - * - * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); - * + * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. */ +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { -THREE.ParametricGeometry = function ( func, slices, stacks ) { + if ( options === undefined ) options = {}; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - THREE.Geometry.call( this ); + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; - var verts = this.vertices; - var faces = this.faces; - var uvs = this.faceVertexUvs[ 0 ]; + // - var i, il, j, p; - var u, v; + var i, l, hole; - var stackCount = stacks + 1; - var sliceCount = slices + 1; + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); - for ( i = 0; i <= stacks; i ++ ) { + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - v = i / stacks; + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ); - for ( j = 0; j <= slices; j ++ ) { + if ( reverse ) { - u = j / slices; + vertices = vertices.reverse(); - p = func( u, v ); - verts.push( p ); + // Maybe we should also check if holes are in the opposite direction, just to be safe... - } - } + for ( i = 0, l = holes.length; i < l; i ++ ) { - var a, b, c, d; - var uva, uvb, uvc, uvd; + hole = holes[ i ]; - for ( i = 0; i < stacks; i ++ ) { + if ( THREE.Shape.Utils.isClockWise( hole ) ) { - for ( j = 0; j < slices; j ++ ) { + holes[ i ] = hole.reverse(); - a = i * sliceCount + j; - b = i * sliceCount + j + 1; - c = (i + 1) * sliceCount + j + 1; - d = (i + 1) * sliceCount + j; + } - uva = new THREE.Vector2( j / slices, i / stacks ); - uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); - uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); - uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); + } - faces.push( new THREE.Face3( a, b, d ) ); - uvs.push( [ uva, uvb, uvd ] ); + reverse = false; - faces.push( new THREE.Face3( b, c, d ) ); - uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); + } - } + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); - } + // Vertices - // console.log(this); + var contour = vertices; - // magic bullet - // var diff = this.mergeVertices(); - // console.log('removed ', diff, ' vertices by merging'); + for ( i = 0, l = holes.length; i < l; i ++ ) { - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); + hole = holes[ i ]; + vertices = vertices.concat( hole ); -}; + } -THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); + // -/** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ + var vert, vlen = vertices.length; + var face, flen = faces.length; -THREE.AxisHelper = function ( size ) { + for ( i = 0; i < vlen; i ++ ) { - size = size || 1; + vert = vertices[ i ]; - var geometry = new THREE.Geometry(); + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); - geometry.vertices.push( - new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) - ); + } - geometry.colors.push( - new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), - new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), - new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) - ); + for ( i = 0; i < flen; i ++ ) { - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + face = faces[ i ]; - THREE.Line.call( this, geometry, material, THREE.LinePieces ); + var a = face[ 0 ] + shapesOffset; + var b = face[ 1 ] + shapesOffset; + var c = face[ 2 ] + shapesOffset; + + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) ); + + } }; -THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); +// File:src/extras/geometries/LatheGeometry.js /** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 * @author bhouston / http://exocortex.com - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * hex - color in hex value */ -THREE.ArrowHelper = function ( dir, origin, length, hex ) { - - // dir is assumed to be normalized - - THREE.Object3D.call( this ); - - if ( hex === undefined ) hex = 0xffff00; - if ( length === undefined ) length = 1; - - this.position = origin; - - var lineGeometry = new THREE.Geometry(); - lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); - lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); - - this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - var coneGeometry = new THREE.CylinderGeometry( 0, 0.05, 0.25, 5, 1 ); - coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0.875, 0 ) ); - - this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length ); +// points - to create a closed torus, one must use a set of points +// like so: [ a, b, c, d, a ], see first is the same as last. +// segments - the number of circumference segments to create +// phiStart - the starting radian +// phiLength - the radian (0 to 2*PI) range of the lathed section +// 2*pi is a closed lathe, less than 2PI is a portion. -}; +THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { -THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); + THREE.Geometry.call( this ); -THREE.ArrowHelper.prototype.setDirection = function () { + this.type = 'LatheGeometry'; - var axis = new THREE.Vector3(); - var radians; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - return function ( dir ) { + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; - // dir is assumed to be normalized + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; - if ( dir.y > 0.99999 ) { + for ( var i = 0, il = segments; i <= il; i ++ ) { - this.quaternion.set( 0, 0, 0, 1 ); + var phi = phiStart + i * inverseSegments * phiLength; - } else if ( dir.y < - 0.99999 ) { + var c = Math.cos( phi ), + s = Math.sin( phi ); - this.quaternion.set( 1, 0, 0, 0 ); + for ( var j = 0, jl = points.length; j < jl; j ++ ) { - } else { + var pt = points[ j ]; - axis.set( dir.z, 0, - dir.x ).normalize(); + var vertex = new THREE.Vector3(); - radians = Math.acos( dir.y ); + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; - this.quaternion.setFromAxisAngle( axis, radians ); + this.vertices.push( vertex ); } - }; - -}(); - -THREE.ArrowHelper.prototype.setLength = function ( length ) { + } - this.scale.set( length, length, length ); + var np = points.length; -}; + for ( var i = 0, il = segments; i < il; i ++ ) { -THREE.ArrowHelper.prototype.setColor = function ( hex ) { + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { - this.line.material.color.setHex( hex ); - this.cone.material.color.setHex( hex ); + var base = j + np * i; + var a = base; + var b = base + np; + var c = base + 1 + np; + var d = base + 1; -}; + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; -/** - * @author mrdoob / http://mrdoob.com/ - */ + this.faces.push( new THREE.Face3( a, b, d ) ); -THREE.BoxHelper = function ( object ) { + this.faceVertexUvs[ 0 ].push( [ - // 5____4 - // 1/___0/| - // | 6__|_7 - // 2/___3/ + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u0, v1 ) - var vertices = [ - new THREE.Vector3( 1, 1, 1 ), - new THREE.Vector3( - 1, 1, 1 ), - new THREE.Vector3( - 1, - 1, 1 ), - new THREE.Vector3( 1, - 1, 1 ), - - new THREE.Vector3( 1, 1, - 1 ), - new THREE.Vector3( - 1, 1, - 1 ), - new THREE.Vector3( - 1, - 1, - 1 ), - new THREE.Vector3( 1, - 1, - 1 ) - ]; + ] ); - this.vertices = vertices; + this.faces.push( new THREE.Face3( b, c, d ) ); - // TODO: Wouldn't be nice if Line had .segments? + this.faceVertexUvs[ 0 ].push( [ - var geometry = new THREE.Geometry(); - geometry.vertices.push( - vertices[ 0 ], vertices[ 1 ], - vertices[ 1 ], vertices[ 2 ], - vertices[ 2 ], vertices[ 3 ], - vertices[ 3 ], vertices[ 0 ], - - vertices[ 4 ], vertices[ 5 ], - vertices[ 5 ], vertices[ 6 ], - vertices[ 6 ], vertices[ 7 ], - vertices[ 7 ], vertices[ 4 ], - - vertices[ 0 ], vertices[ 4 ], - vertices[ 1 ], vertices[ 5 ], - vertices[ 2 ], vertices[ 6 ], - vertices[ 3 ], vertices[ 7 ] - ); + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); + ] ); - if ( object !== undefined ) { - this.update( object ); + } } -}; + this.mergeVertices(); + this.computeFaceNormals(); + this.computeVertexNormals(); -THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); +}; -THREE.BoxHelper.prototype.update = function ( object ) { +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry; - var geometry = object.geometry; +// File:src/extras/geometries/PlaneGeometry.js - if ( geometry.boundingBox === null ) { +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ - geometry.computeBoundingBox(); +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { - } + console.info( 'THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.' ); - var min = geometry.boundingBox.min; - var max = geometry.boundingBox.max; - var vertices = this.vertices; + THREE.Geometry.call( this ); - vertices[ 0 ].set( max.x, max.y, max.z ); - vertices[ 1 ].set( min.x, max.y, max.z ); - vertices[ 2 ].set( min.x, min.y, max.z ); - vertices[ 3 ].set( max.x, min.y, max.z ); - vertices[ 4 ].set( max.x, max.y, min.z ); - vertices[ 5 ].set( min.x, max.y, min.z ); - vertices[ 6 ].set( min.x, min.y, min.z ); - vertices[ 7 ].set( max.x, min.y, min.z ); + this.type = 'PlaneGeometry'; - this.geometry.computeBoundingSphere(); - this.geometry.verticesNeedUpdate = true; + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; + this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); }; -/** - * @author WestLangley / http://github.com/WestLangley - */ +THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; -// a helper to show the world-axis-aligned bounding box for an object +// File:src/extras/geometries/PlaneBufferGeometry.js -THREE.BoundingBoxHelper = function ( object, hex ) { +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ - var color = hex || 0x888888; +THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) { - this.object = object; + THREE.BufferGeometry.call( this ); - this.box = new THREE.Box3(); + this.type = 'PlaneBufferGeometry'; - THREE.Mesh.call( this, new THREE.CubeGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; -}; + var width_half = width / 2; + var height_half = height / 2; -THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); + var gridX = widthSegments || 1; + var gridY = heightSegments || 1; -THREE.BoundingBoxHelper.prototype.update = function () { + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; - this.box.setFromObject( this.object ); + var segment_width = width / gridX; + var segment_height = height / gridY; - this.box.size( this.scale ); + var vertices = new Float32Array( gridX1 * gridY1 * 3 ); + var normals = new Float32Array( gridX1 * gridY1 * 3 ); + var uvs = new Float32Array( gridX1 * gridY1 * 2 ); - this.box.center( this.position ); + var offset = 0; + var offset2 = 0; -}; + for ( var iy = 0; iy < gridY1; iy ++ ) { -/** - * @author alteredq / http://alteredqualia.com/ - * - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * http://evanw.github.com/lightgl.js/tests/shadowmap.html - */ + var y = iy * segment_height - height_half; -THREE.CameraHelper = function ( camera ) { + for ( var ix = 0; ix < gridX1; ix ++ ) { - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); + var x = ix * segment_width - width_half; - var pointMap = {}; + vertices[ offset ] = x; + vertices[ offset + 1 ] = - y; - // colors + normals[ offset + 2 ] = 1; - var hexFrustum = 0xffaa00; - var hexCone = 0xff0000; - var hexUp = 0x00aaff; - var hexTarget = 0xffffff; - var hexCross = 0x333333; + uvs[ offset2 ] = ix / gridX; + uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); - // near + offset += 3; + offset2 += 2; - addLine( "n1", "n2", hexFrustum ); - addLine( "n2", "n4", hexFrustum ); - addLine( "n4", "n3", hexFrustum ); - addLine( "n3", "n1", hexFrustum ); + } - // far + } - addLine( "f1", "f2", hexFrustum ); - addLine( "f2", "f4", hexFrustum ); - addLine( "f4", "f3", hexFrustum ); - addLine( "f3", "f1", hexFrustum ); + offset = 0; - // sides + var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); - addLine( "n1", "f1", hexFrustum ); - addLine( "n2", "f2", hexFrustum ); - addLine( "n3", "f3", hexFrustum ); - addLine( "n4", "f4", hexFrustum ); + for ( var iy = 0; iy < gridY; iy ++ ) { - // cone + for ( var ix = 0; ix < gridX; ix ++ ) { - addLine( "p", "n1", hexCone ); - addLine( "p", "n2", hexCone ); - addLine( "p", "n3", hexCone ); - addLine( "p", "n4", hexCone ); + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; - // up + indices[ offset ] = a; + indices[ offset + 1 ] = b; + indices[ offset + 2 ] = d; - addLine( "u1", "u2", hexUp ); - addLine( "u2", "u3", hexUp ); - addLine( "u3", "u1", hexUp ); + indices[ offset + 3 ] = b; + indices[ offset + 4 ] = c; + indices[ offset + 5 ] = d; - // target + offset += 6; - addLine( "c", "t", hexTarget ); - addLine( "p", "c", hexCross ); + } - // cross + } - addLine( "cn1", "cn2", hexCross ); - addLine( "cn3", "cn4", hexCross ); + this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); + this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - addLine( "cf1", "cf2", hexCross ); - addLine( "cf3", "cf4", hexCross ); +}; - function addLine( a, b, hex ) { +THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; - addPoint( a, hex ); - addPoint( b, hex ); +// File:src/extras/geometries/RingGeometry.js - } +/** + * @author Kaleb Murphy + */ - function addPoint( id, hex ) { +THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - geometry.vertices.push( new THREE.Vector3() ); - geometry.colors.push( new THREE.Color( hex ) ); + THREE.Geometry.call( this ); - if ( pointMap[ id ] === undefined ) { + this.type = 'RingGeometry'; - pointMap[ id ] = []; + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - } + innerRadius = innerRadius || 0; + outerRadius = outerRadius || 50; - pointMap[ id ].push( geometry.vertices.length - 1 ); + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - } + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 8; - THREE.Line.call( this, geometry, material, THREE.LinePieces ); + var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - this.camera = camera; - this.matrixWorld = camera.matrixWorld; - this.matrixAutoUpdate = false; + for ( i = 0; i < phiSegments + 1; i ++ ) { // concentric circles inside ring - this.pointMap = pointMap; + for ( o = 0; o < thetaSegments + 1; o ++ ) { // number of segments per circle - this.update(); + var vertex = new THREE.Vector3(); + var segment = thetaStart + o / thetaSegments * thetaLength; + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); -}; + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); + } -THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); + radius += radiusStep; -THREE.CameraHelper.prototype.update = function () { + } - var vector = new THREE.Vector3(); - var camera = new THREE.Camera(); - var projector = new THREE.Projector(); + var n = new THREE.Vector3( 0, 0, 1 ); - return function () { + for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring - var scope = this; + var thetaSegment = i * (thetaSegments + 1); - var w = 1, h = 1; + for ( o = 0; o < thetaSegments ; o ++ ) { // number of segments per circle - // we need just camera projection matrix - // world matrix must be identity + var segment = o + thetaSegment; - camera.projectionMatrix.copy( this.camera.projectionMatrix ); + var v1 = segment; + var v2 = segment + thetaSegments + 1; + var v3 = segment + thetaSegments + 2; - // center / target + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - setPoint( "c", 0, 0, -1 ); - setPoint( "t", 0, 0, 1 ); + v1 = segment; + v2 = segment + thetaSegments + 2; + v3 = segment + 1; - // near + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - setPoint( "n1", -w, -h, -1 ); - setPoint( "n2", w, -h, -1 ); - setPoint( "n3", -w, h, -1 ); - setPoint( "n4", w, h, -1 ); + } + } - // far + this.computeFaceNormals(); - setPoint( "f1", -w, -h, 1 ); - setPoint( "f2", w, -h, 1 ); - setPoint( "f3", -w, h, 1 ); - setPoint( "f4", w, h, 1 ); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - // up +}; - setPoint( "u1", w * 0.7, h * 1.1, -1 ); - setPoint( "u2", -w * 0.7, h * 1.1, -1 ); - setPoint( "u3", 0, h * 2, -1 ); +THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; - // cross - setPoint( "cf1", -w, 0, 1 ); - setPoint( "cf2", w, 0, 1 ); - setPoint( "cf3", 0, -h, 1 ); - setPoint( "cf4", 0, h, 1 ); +// File:src/extras/geometries/SphereGeometry.js - setPoint( "cn1", -w, 0, -1 ); - setPoint( "cn2", w, 0, -1 ); - setPoint( "cn3", 0, -h, -1 ); - setPoint( "cn4", 0, h, -1 ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - function setPoint( point, x, y, z ) { +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - vector.set( x, y, z ); - projector.unprojectVector( vector, camera ); + THREE.Geometry.call( this ); - var points = scope.pointMap[ point ]; + this.type = 'SphereGeometry'; - if ( points !== undefined ) { + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - for ( var i = 0, il = points.length; i < il; i ++ ) { + radius = radius || 50; - scope.geometry.vertices[ points[ i ] ].copy( vector ); + widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - } + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - } + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - } + var x, y, vertices = [], uvs = []; - this.geometry.verticesNeedUpdate = true; + for ( y = 0; y <= heightSegments; y ++ ) { - }; + var verticesRow = []; + var uvsRow = []; -}(); + for ( x = 0; x <= widthSegments; x ++ ) { -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + var u = x / widthSegments; + var v = y / heightSegments; -THREE.DirectionalLightHelper = function ( light, size ) { + var vertex = new THREE.Vector3(); + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - THREE.Object3D.call( this ); + this.vertices.push( vertex ); - this.light = light; - this.light.updateMatrixWorld(); + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + } - var geometry = new THREE.PlaneGeometry( size, size ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + vertices.push( verticesRow ); + uvs.push( uvsRow ); - this.lightPlane = new THREE.Mesh( geometry, material ); - this.add( this.lightPlane ); + } - geometry = new THREE.Geometry(); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - geometry.computeLineDistances(); + for ( y = 0; y < heightSegments; y ++ ) { - material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + for ( x = 0; x < widthSegments; x ++ ) { - this.targetLine = new THREE.Line( geometry, material ); - this.add( this.targetLine ); + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = vertices[ y + 1 ][ x ]; + var v4 = vertices[ y + 1 ][ x + 1 ]; - this.update(); + var n1 = this.vertices[ v1 ].clone().normalize(); + var n2 = this.vertices[ v2 ].clone().normalize(); + var n3 = this.vertices[ v3 ].clone().normalize(); + var n4 = this.vertices[ v4 ].clone().normalize(); -}; + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x ].clone(); + var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); -THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + if ( Math.abs( this.vertices[ v1 ].y ) === radius ) { -THREE.DirectionalLightHelper.prototype.dispose = function () { + uv1.x = ( uv1.x + uv2.x ) / 2; + this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); -}; + } else if ( Math.abs( this.vertices[ v3 ].y ) === radius ) { -THREE.DirectionalLightHelper.prototype.update = function () { + uv3.x = ( uv3.x + uv4.x ) / 2; + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - var vector = new THREE.Vector3(); + } else { - return function () { + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - vector.getPositionFromMatrix( this.light.matrixWorld ).negate(); + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - this.lightPlane.lookAt( vector ); - this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + } - this.targetLine.geometry.vertices[ 1 ].copy( vector ); - this.targetLine.geometry.verticesNeedUpdate = true; - this.targetLine.material.color.copy( this.lightPlane.material.color ); + } } -}(); + this.computeFaceNormals(); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ +}; -THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; - this.object = object; +// File:src/extras/geometries/TextGeometry.js - this.size = size || 1; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For creating 3D text geometry in three.js + * + * Text = 3D Text + * + * parameters = { + * size: <float>, // size of the text + * height: <float>, // thickness to extrude text + * curveSegments: <int>, // number of points on the curves + * + * font: <string>, // font name + * weight: <string>, // font weight (normal, bold) + * style: <string>, // font style (normal, italics) + * + * bevelEnabled: <bool>, // turn on bevel + * bevelThickness: <float>, // how deep into text bevel goes + * bevelSize: <float>, // how far from text outline is bevel + * } + * + */ - var color = hex || 0xffff00; +/* Usage Examples - var width = linewidth || 1; + // TextGeometry wrapper - var geometry = new THREE.Geometry(); + var text3d = new TextGeometry( text, options ); - var faces = this.object.geometry.faces; + // Complete manner - for ( var i = 0, l = faces.length; i < l; i ++ ) { + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); +*/ - } - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); +THREE.TextGeometry = function ( text, parameters ) { - this.matrixAutoUpdate = false; + parameters = parameters || {}; - this.normalMatrix = new THREE.Matrix3(); + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - this.update(); + // translate parameters to ExtrudeGeometry API -}; + parameters.amount = parameters.height !== undefined ? parameters.height : 50; -THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + // defaults -THREE.FaceNormalsHelper.prototype.update = ( function ( object ) { + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - var v1 = new THREE.Vector3(); + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); - return function ( object ) { + this.type = 'TextGeometry'; - this.object.updateMatrixWorld( true ); +}; - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); +THREE.TextGeometry.prototype.constructor = THREE.TextGeometry; - var vertices = this.geometry.vertices; +// File:src/extras/geometries/TorusGeometry.js - var faces = this.object.geometry.faces; +/** + * @author oosmoxiecode + * @author mrdoob / http://mrdoob.com/ + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 + */ - var worldMatrix = this.object.matrixWorld; +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { - for ( var i = 0, l = faces.length; i < l; i ++ ) { + THREE.Geometry.call( this ); - var face = faces[ i ]; + this.type = 'TorusGeometry'; - v1.copy( face.normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - var idx = 2 * i; + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 8; + tubularSegments = tubularSegments || 6; + arc = arc || Math.PI * 2; - vertices[ idx ].copy( face.centroid ).applyMatrix4( worldMatrix ); + var center = new THREE.Vector3(), uvs = [], normals = []; - vertices[ idx + 1 ].addVectors( vertices[ idx ], v1 ); + for ( var j = 0; j <= radialSegments; j ++ ) { - } + for ( var i = 0; i <= tubularSegments; i ++ ) { - this.geometry.verticesNeedUpdate = true; + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; - return this; + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); - } + var vertex = new THREE.Vector3(); + vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = tube * Math.sin( v ); -}()); + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -THREE.GridHelper = function ( size, step ) { + } - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + for ( var j = 1; j <= radialSegments; j ++ ) { - this.color1 = new THREE.Color( 0x444444 ); - this.color2 = new THREE.Color( 0x888888 ); + for ( var i = 1; i <= tubularSegments; i ++ ) { - for ( var i = - size; i <= size; i += step ) { + var a = ( tubularSegments + 1 ) * j + i - 1; + var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; + var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; + var d = ( tubularSegments + 1 ) * j + i; - geometry.vertices.push( - new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), - new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) - ); + var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); - var color = i === 0 ? this.color1 : this.color2; + face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); - geometry.colors.push( color, color, color, color ); + } } - THREE.Line.call( this, geometry, material, THREE.LinePieces ); + this.computeFaceNormals(); }; -THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; -THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { +// File:src/extras/geometries/TorusKnotGeometry.js - this.color1.set( colorCenterLine ); - this.color2.set( colorGrid ); +/** + * @author oosmoxiecode + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 + */ - this.geometry.colorsNeedUpdate = true; +THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { -} + THREE.Geometry.call( this ); -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + this.type = 'TorusKnotGeometry'; -THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + p: p, + q: q, + heightScale: heightScale + }; - THREE.Object3D.call( this ); + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 64; + tubularSegments = tubularSegments || 8; + p = p || 2; + q = q || 3; + heightScale = heightScale || 1; + + var grid = new Array( radialSegments ); + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); - this.light = light; - this.light.updateMatrixWorld(); + for ( var i = 0; i < radialSegments; ++ i ) { - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + grid[ i ] = new Array( tubularSegments ); + var u = i / radialSegments * 2 * p * Math.PI; + var p1 = getPos( u, q, p, radius, heightScale ); + var p2 = getPos( u + 0.01, q, p, radius, heightScale ); + tang.subVectors( p2, p1 ); + n.addVectors( p2, p1 ); - this.colors = [ new THREE.Color(), new THREE.Color() ]; + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + for ( var j = 0; j < tubularSegments; ++ j ) { - for ( var i = 0, il = 8; i < il; i ++ ) { + var v = j / tubularSegments * 2 * Math.PI; + var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + var cy = tube * Math.sin( v ); - geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; + var pos = new THREE.Vector3(); + pos.x = p1.x + cx * n.x + cy * bitan.x; + pos.y = p1.y + cx * n.y + cy * bitan.y; + pos.z = p1.z + cx * n.z + cy * bitan.z; + + grid[ i ][ j ] = this.vertices.push( pos ) - 1; + + } } - var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); + for ( var i = 0; i < radialSegments; ++ i ) { - this.lightSphere = new THREE.Mesh( geometry, material ); - this.add( this.lightSphere ); + for ( var j = 0; j < tubularSegments; ++ j ) { - this.update(); + var ip = ( i + 1 ) % radialSegments; + var jp = ( j + 1 ) % tubularSegments; -}; + var a = grid[ i ][ j ]; + var b = grid[ ip ][ j ]; + var c = grid[ ip ][ jp ]; + var d = grid[ i ][ jp ]; -THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); + var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); + var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); + var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); -THREE.HemisphereLightHelper.prototype.dispose = function () { - this.lightSphere.geometry.dispose(); - this.lightSphere.material.dispose(); -}; + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); -THREE.HemisphereLightHelper.prototype.update = function () { + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - var vector = new THREE.Vector3(); + } + } - return function () { + this.computeFaceNormals(); + this.computeVertexNormals(); - this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + function getPos( u, in_q, in_p, radius, heightScale ) { - this.lightSphere.lookAt( vector.getPositionFromMatrix( this.light.matrixWorld ).negate() ); - this.lightSphere.geometry.colorsNeedUpdate = true; + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); + + var tx = radius * ( 2 + cs ) * 0.5 * cu; + var ty = radius * ( 2 + cs ) * su * 0.5; + var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; + + return new THREE.Vector3( tx, ty, tz ); } -}(); +}; + +THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; +// File:src/extras/geometries/TubeGeometry.js /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * @author jonobr1 / https://github.com/jonobr1 + * + * Modified from the TorusKnotGeometry by @oosmoxiecode + * + * Creates a tube which extrudes along a 3d spline + * + * Uses parallel transport frames as described in + * http://www.cs.indiana.edu/pub/techreports/TR425.pdf */ -THREE.PointLightHelper = function ( light, sphereSize ) { +THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, taper ) { - this.light = light; - this.light.updateMatrixWorld(); + THREE.Geometry.call( this ); - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.type = 'TubeGeometry'; - THREE.Mesh.call( this, geometry, material ); + this.parameters = { + path: path, + segments: segments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; - this.matrixWorld = this.light.matrixWorld; - this.matrixAutoUpdate = false; + segments = segments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; + taper = taper || THREE.TubeGeometry.NoTaper; - /* - var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + var grid = []; - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + var scope = this, - var d = light.distance; + tangent, + normal, + binormal, - if ( d === 0.0 ) { + numpoints = segments + 1, - this.lightDistance.visible = false; + u, v, r, + + cx, cy, + pos, pos2 = new THREE.Vector3(), + i, j, + ip, jp, + a, b, c, d, + uva, uvb, uvc, uvd; + + var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), + tangents = frames.tangents, + normals = frames.normals, + binormals = frames.binormals; + + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - } else { + function vert( x, y, z ) { - this.lightDistance.scale.set( d, d, d ); + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; } - this.add( this.lightDistance ); - */ + // consruct the grid -}; + for ( i = 0; i < numpoints; i ++ ) { -THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); + grid[ i ] = []; -THREE.PointLightHelper.prototype.dispose = function () { + u = i / ( numpoints - 1 ); - this.geometry.dispose(); - this.material.dispose(); -}; + pos = path.getPointAt( u ); -THREE.PointLightHelper.prototype.update = function () { + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; - this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + r = radius * taper( u ); - /* - var d = this.light.distance; + for ( j = 0; j < radialSegments; j ++ ) { - if ( d === 0.0 ) { + v = j / radialSegments * 2 * Math.PI; - this.lightDistance.visible = false; + cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = r * Math.sin( v ); - } else { + pos2.copy( pos ); + pos2.x += cx * normal.x + cy * binormal.x; + pos2.y += cx * normal.y + cy * binormal.y; + pos2.z += cx * normal.z + cy * binormal.z; - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + } } - */ - -}; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ + // construct the mesh -THREE.SpotLightHelper = function ( light ) { + for ( i = 0; i < segments; i ++ ) { - THREE.Object3D.call( this ); + for ( j = 0; j < radialSegments; j ++ ) { - this.light = light; - this.light.updateMatrixWorld(); + ip = ( closed ) ? (i + 1) % segments : i + 1; + jp = (j + 1) % radialSegments; - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; + a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = grid[ ip ][ j ]; + c = grid[ ip ][ jp ]; + d = grid[ i ][ jp ]; - var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); + uva = new THREE.Vector2( i / segments, j / radialSegments ); + uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); + uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); + uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - this.cone = new THREE.Mesh( geometry, material ); - this.add( this.cone ); + } + } - this.update(); + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; -THREE.SpotLightHelper.prototype.dispose = function () { - this.cone.geometry.dispose(); - this.cone.material.dispose(); -}; +THREE.TubeGeometry.NoTaper = function ( u ) { -THREE.SpotLightHelper.prototype.update = function () { + return 1; - var vector = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); +}; - return function () { +THREE.TubeGeometry.SinusoidalTaper = function ( u ) { - var coneLength = this.light.distance ? this.light.distance : 10000; - var coneWidth = coneLength * Math.tan( this.light.angle ); + return Math.sin( Math.PI * u ); - this.cone.scale.set( coneWidth, coneWidth, coneLength ); +}; - vector.getPositionFromMatrix( this.light.matrixWorld ); - vector2.getPositionFromMatrix( this.light.target.matrixWorld ); +// For computing of Frenet frames, exposing the tangents, normals and binormals the spline +THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { - this.cone.lookAt( vector2.sub( vector ) ); + var normal = new THREE.Vector3(), - this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + tangents = [], + normals = [], + binormals = [], - }; + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), -}(); + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ + tx, ty, tz, + i, u; -THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - this.object = object; + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - this.size = size || 1; + // compute the tangent vectors for each segment on the path - var color = hex || 0xff0000; + for ( i = 0; i < numpoints; i ++ ) { - var width = linewidth || 1; + u = i / ( numpoints - 1 ); - var geometry = new THREE.Geometry(); + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); - var vertices = object.geometry.vertices; + } - var faces = object.geometry.faces; + initialNormal3(); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + /* + function initialNormal1(lastBinormal) { + // fixed start binormal. Has dangers of 0 vectors + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); + normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + } - var face = faces[ i ]; + function initialNormal2() { - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); + normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); + binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); - } + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); } + */ - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; + function initialNormal3() { + // select an initial normal vector perpenicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component - this.normalMatrix = new THREE.Matrix3(); + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + smallest = Number.MAX_VALUE; + tx = Math.abs( tangents[ 0 ].x ); + ty = Math.abs( tangents[ 0 ].y ); + tz = Math.abs( tangents[ 0 ].z ); - this.update(); + if ( tx <= smallest ) { + smallest = tx; + normal.set( 1, 0, 0 ); + } -}; + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); + } -THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + if ( tz <= smallest ) { + normal.set( 0, 0, 1 ); + } -THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - var v1 = new THREE.Vector3(); + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + } - return function( object ) { - var keys = [ 'a', 'b', 'c', 'd' ]; + // compute the slowly-varying normal and binormal vectors for each segment on the path - this.object.updateMatrixWorld( true ); + for ( i = 1; i < numpoints; i ++ ) { - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); + normals[ i ] = normals[ i - 1 ].clone(); - var vertices = this.geometry.vertices; + binormals[ i ] = binormals[ i - 1 ].clone(); - var verts = this.object.geometry.vertices; + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - var faces = this.object.geometry.faces; + if ( vec.length() > epsilon ) { - var worldMatrix = this.object.matrixWorld; + vec.normalize(); - var idx = 0; + theta = Math.acos( THREE.Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - for ( var i = 0, l = faces.length; i < l; i ++ ) { + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - var face = faces[ i ]; + } - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; + } - var normal = face.vertexNormals[ j ]; - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + if ( closed ) { - v1.add( vertices[ idx ] ); - idx = idx + 1; + theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) ); + theta /= ( numpoints - 1 ); - vertices[ idx ].copy( v1 ); - idx = idx + 1; + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { - } + theta = - theta; } - this.geometry.verticesNeedUpdate = true; + for ( i = 1; i < numpoints; i ++ ) { - return this; + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } } +}; -}()); +// File:src/extras/geometries/PolyhedronGeometry.js /** - * @author mrdoob / http://mrdoob.com/ + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley * @author WestLangley / http://github.com/WestLangley */ -THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = size || 1; +THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { - var color = hex || 0x0000ff; - - var width = linewidth || 1; - - var geometry = new THREE.Geometry(); - - var vertices = object.geometry.vertices; + THREE.Geometry.call( this ); - var faces = object.geometry.faces; + this.type = 'PolyhedronGeometry'; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - var face = faces[ i ]; + radius = radius || 1; + detail = detail || 0; - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + var that = this; - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); + for ( var i = 0, l = vertices.length; i < l; i += 3 ) { - } + prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); } - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.update(); - -}; - -THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function( object ) { + var p = this.vertices; - var keys = [ 'a', 'b', 'c', 'd' ]; + var faces = []; - this.object.updateMatrixWorld( true ); + for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { - var vertices = this.geometry.vertices; + var v1 = p[ indices[ i ] ]; + var v2 = p[ indices[ i + 1 ] ]; + var v3 = p[ indices[ i + 2 ] ]; - var verts = this.object.geometry.vertices; + faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - var faces = this.object.geometry.faces; + } - var worldMatrix = this.object.matrixWorld; + var centroid = new THREE.Vector3(); - var idx = 0; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - for ( var i = 0, l = faces.length; i < l; i ++ ) { + subdivide( faces[ i ], detail ); - var face = faces[ i ]; + } - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; + // Handle case when face straddles the seam - var tangent = face.vertexTangents[ j ]; + for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + var uvs = this.faceVertexUvs[ 0 ][ i ]; - v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); + var x0 = uvs[ 0 ].x; + var x1 = uvs[ 1 ].x; + var x2 = uvs[ 2 ].x; - v1.add( vertices[ idx ] ); - idx = idx + 1; + var max = Math.max( x0, Math.max( x1, x2 ) ); + var min = Math.min( x0, Math.min( x1, x2 ) ); - vertices[ idx ].copy( v1 ); - idx = idx + 1; + if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary - } + if ( x0 < 0.2 ) uvs[ 0 ].x += 1; + if ( x1 < 0.2 ) uvs[ 1 ].x += 1; + if ( x2 < 0.2 ) uvs[ 2 ].x += 1; } - this.geometry.verticesNeedUpdate = true; + } - return this; + + // Apply radius + + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + + this.vertices[ i ].multiplyScalar( radius ); } -}()); -/** - * @author mrdoob / http://mrdoob.com/ - */ + // Merge vertices -THREE.WireframeHelper = function ( object ) { + this.mergeVertices(); - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; + this.computeFaceNormals(); - var keys = [ 'a', 'b', 'c', 'd' ]; - var geometry = new THREE.Geometry(); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - var vertices = object.geometry.vertices; - var faces = object.geometry.faces; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + // Project vector onto sphere's surface - var face = faces[ i ]; + function prepare( vector ) { - for ( var j = 0; j < 3; j ++ ) { + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. - var key = edge.toString(); + var u = azimuth( vector ) / 2 / Math.PI + 0.5; + var v = inclination( vector ) / Math.PI + 0.5; + vertex.uv = new THREE.Vector2( u, 1 - v ); - if ( hash[ key ] === undefined ) { + return vertex; - geometry.vertices.push( vertices[ edge[ 0 ] ] ); - geometry.vertices.push( vertices[ edge[ 1 ] ] ); + } - hash[ key ] = true; - } + // Approximate a curved face with recursively sub-divided triangles. - } + function make( v1, v2, v3 ) { - } + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + that.faces.push( face ); - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffffff } ), THREE.LinePieces ); + centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; + var azi = azimuth( centroid ); -}; + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); -THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); + } -/** - * @author alteredq / http://alteredqualia.com/ - */ -THREE.ImmediateRenderObject = function () { + // Analytically subdivide a face to the required detail level. - THREE.Object3D.call( this ); + function subdivide( face, detail ) { - this.render = function ( renderCallback ) { }; + var cols = Math.pow(2, detail); + var a = prepare( that.vertices[ face.a ] ); + var b = prepare( that.vertices[ face.b ] ); + var c = prepare( that.vertices[ face.c ] ); + var v = []; -}; + // Construct all of the vertices for this subdivision. -THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); + for ( var i = 0 ; i <= cols; i ++ ) { -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + v[ i ] = []; -THREE.LensFlare = function ( texture, size, distance, blending, color ) { + var aj = prepare( a.clone().lerp( c, i / cols ) ); + var bj = prepare( b.clone().lerp( c, i / cols ) ); + var rows = cols - i; - THREE.Object3D.call( this ); + for ( var j = 0; j <= rows; j ++) { - this.lensFlares = []; + if ( j == 0 && i == cols ) { - this.positionScreen = new THREE.Vector3(); - this.customUpdateCallback = undefined; + v[ i ][ j ] = aj; - if( texture !== undefined ) { + } else { - this.add( texture, size, distance, blending, color ); + v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); - } + } -}; + } -THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); + } + // Construct all of the faces. -/* - * Add: adds another flare - */ + for ( var i = 0; i < cols ; i ++ ) { -THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { + for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { - if( size === undefined ) size = -1; - if( distance === undefined ) distance = 0; - if( opacity === undefined ) opacity = 1; - if( color === undefined ) color = new THREE.Color( 0xffffff ); - if( blending === undefined ) blending = THREE.NormalBlending; + var k = Math.floor( j / 2 ); - distance = Math.min( distance, Math.max( 0, distance ) ); + if ( j % 2 == 0 ) { - this.lensFlares.push( { texture: texture, // THREE.Texture - size: size, // size in pixels (-1 = use texture.width) - distance: distance, // distance (0-1) from light source (0=at light source) - x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back - scale: 1, // scale - rotation: 1, // rotation - opacity: opacity, // opacity - color: color, // color - blending: blending } ); // blending + make( + v[ i ][ k + 1], + v[ i + 1 ][ k ], + v[ i ][ k ] + ); -}; + } else { + make( + v[ i ][ k + 1 ], + v[ i + 1][ k + 1], + v[ i + 1 ][ k ] + ); -/* - * Update lens flares update positions on all flares based on the screen position - * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. - */ + } -THREE.LensFlare.prototype.updateLensFlares = function () { + } - var f, fl = this.lensFlares.length; - var flare; - var vecX = -this.positionScreen.x * 2; - var vecY = -this.positionScreen.y * 2; + } - for( f = 0; f < fl; f ++ ) { + } - flare = this.lensFlares[ f ]; - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; + // Angle around the Y axis, counter-clockwise when looking from above. - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + function azimuth( vector ) { + + return Math.atan2( vector.z, - vector.x ); } -}; + // Angle above the XZ plane. + + function inclination( vector ) { + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + } + // Texture fixing helper. Spheres have some odd behaviours. + function correctUV( uv, vector, azimuth ) { + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); + return uv.clone(); + } +}; +THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry; +// File:src/extras/geometries/DodecahedronGeometry.js /** - * @author alteredq / http://alteredqualia.com/ + * @author Abe Pazos / https://hamoid.com */ -THREE.MorphBlendMesh = function( geometry, material ) { +THREE.DodecahedronGeometry = function ( radius, detail ) { - THREE.Mesh.call( this, geometry, material ); + this.parameters = { + radius: radius, + detail: detail + }; - this.animationsMap = {}; - this.animationsList = []; + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; - // prepare default animation - // (all frames played together in 1 second) + var vertices = [ - var numFrames = this.geometry.morphTargets.length; + // (±1, ±1, ±1) + -1, -1, -1, -1, -1, 1, + -1, 1, -1, -1, 1, 1, + 1, -1, -1, 1, -1, 1, + 1, 1, -1, 1, 1, 1, - var name = "__default"; + // (0, ±1/φ, ±φ) + 0, -r, -t, 0, -r, t, + 0, r, -t, 0, r, t, - var startFrame = 0; - var endFrame = numFrames - 1; + // (±1/φ, ±φ, 0) + -r, -t, 0, -r, t, 0, + r, -t, 0, r, t, 0, - var fps = numFrames / 1; + // (±φ, 0, ±1/φ) + -t, 0, -r, t, 0, -r, + -t, 0, r, t, 0, r + ]; - this.createAnimation( name, startFrame, endFrame, fps ); - this.setAnimationWeight( name, 1 ); + var indices = [ + 3, 11, 7, 3, 7, 15, 3, 15, 13, + 7, 19, 17, 7, 17, 6, 7, 6, 15, + 17, 4, 8, 17, 8, 10, 17, 10, 6, + 8, 0, 16, 8, 16, 2, 8, 2, 10, + 0, 12, 1, 0, 1, 18, 0, 18, 16, + 6, 10, 2, 6, 2, 13, 6, 13, 15, + 2, 16, 18, 2, 18, 3, 2, 3, 13, + 18, 1, 9, 18, 9, 11, 18, 11, 3, + 4, 14, 12, 4, 12, 0, 4, 0, 8, + 11, 9, 5, 11, 5, 19, 11, 19, 7, + 19, 5, 14, 19, 14, 4, 19, 4, 17, + 1, 12, 14, 1, 14, 5, 1, 5, 9 + ]; -}; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); -THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); +}; -THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { +THREE.DodecahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry; - var animation = { +// File:src/extras/geometries/IcosahedronGeometry.js - startFrame: start, - endFrame: end, +/** + * @author timothypratley / https://github.com/timothypratley + */ - length: end - start + 1, +THREE.IcosahedronGeometry = function ( radius, detail ) { - fps: fps, - duration: ( end - start ) / fps, + var t = ( 1 + Math.sqrt( 5 ) ) / 2; - lastFrame: 0, - currentFrame: 0, + var vertices = [ + - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, + 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, + t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 + ]; - active: false, + var indices = [ + 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, + 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, + 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, + 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 + ]; - time: 0, - direction: 1, - weight: 1, + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - directionBackwards: false, - mirroredLoop: false + this.type = 'IcosahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail }; - - this.animationsMap[ name ] = animation; - this.animationsList.push( animation ); - }; -THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { +THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry; - var pattern = /([a-z]+)(\d+)/; +// File:src/extras/geometries/OctahedronGeometry.js - var firstAnimation, frameRanges = {}; +/** + * @author timothypratley / https://github.com/timothypratley + */ - var geometry = this.geometry; +THREE.OctahedronGeometry = function ( radius, detail ) { - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + this.parameters = { + radius: radius, + detail: detail + }; - var morph = geometry.morphTargets[ i ]; - var chunks = morph.name.match( pattern ); + var vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0,- 1, 0, 0, 0, 1, 0, 0,- 1 + ]; - if ( chunks && chunks.length > 1 ) { + var indices = [ + 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2 + ]; - var name = chunks[ 1 ]; - var num = chunks[ 2 ]; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity }; + this.type = 'OctahedronGeometry'; - var range = frameRanges[ name ]; + this.parameters = { + radius: radius, + detail: detail + }; +}; - if ( i < range.start ) range.start = i; - if ( i > range.end ) range.end = i; +THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry; - if ( ! firstAnimation ) firstAnimation = name; +// File:src/extras/geometries/TetrahedronGeometry.js - } +/** + * @author timothypratley / https://github.com/timothypratley + */ - } +THREE.TetrahedronGeometry = function ( radius, detail ) { + + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; - for ( var name in frameRanges ) { + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; - var range = frameRanges[ name ]; - this.createAnimation( name, range.start, range.end, fps ); + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - } + this.type = 'TetrahedronGeometry'; - this.firstAnimation = firstAnimation; + this.parameters = { + radius: radius, + detail: detail + }; }; -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - - var animation = this.animationsMap[ name ]; +THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; - if ( animation ) { +// File:src/extras/geometries/ParametricGeometry.js - animation.direction = 1; - animation.directionBackwards = false; +/** + * @author zz85 / https://github.com/zz85 + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + * + * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); + * + */ - } +THREE.ParametricGeometry = function ( func, slices, stacks ) { -}; + THREE.Geometry.call( this ); -THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { + this.type = 'ParametricGeometry'; - var animation = this.animationsMap[ name ]; + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; - if ( animation ) { + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; - animation.direction = -1; - animation.directionBackwards = true; + var i, j, p; + var u, v; - } + var sliceCount = slices + 1; -}; + for ( i = 0; i <= stacks; i ++ ) { -THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + v = i / stacks; - var animation = this.animationsMap[ name ]; + for ( j = 0; j <= slices; j ++ ) { - if ( animation ) { + u = j / slices; - animation.fps = fps; - animation.duration = ( animation.end - animation.start ) / animation.fps; + p = func( u, v ); + verts.push( p ); + } } -}; + var a, b, c, d; + var uva, uvb, uvc, uvd; -THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + for ( i = 0; i < stacks; i ++ ) { - var animation = this.animationsMap[ name ]; + for ( j = 0; j < slices; j ++ ) { - if ( animation ) { + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = (i + 1) * sliceCount + j + 1; + d = (i + 1) * sliceCount + j; - animation.duration = duration; - animation.fps = ( animation.end - animation.start ) / animation.duration; + uva = new THREE.Vector2( j / slices, i / stacks ); + uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); + uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); + uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); - } + faces.push( new THREE.Face3( a, b, d ) ); + uvs.push( [ uva, uvb, uvd ] ); -}; + faces.push( new THREE.Face3( b, c, d ) ); + uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); -THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + } - var animation = this.animationsMap[ name ]; + } - if ( animation ) { + // console.log(this); - animation.weight = weight; + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); - } + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; - var animation = this.animationsMap[ name ]; +// File:src/extras/helpers/AxisHelper.js - if ( animation ) { +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ - animation.time = time; +THREE.AxisHelper = function ( size ) { - } + size = size || 1; -}; + var vertices = new Float32Array( [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ] ); -THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + var colors = new Float32Array( [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ] ); - var time = 0; + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - var animation = this.animationsMap[ name ]; + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - if ( animation ) { + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - time = animation.time; +}; - } +THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; - return time; +// File:src/extras/helpers/ArrowHelper.js -}; +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://github.com/zz85 + * @author bhouston / http://exocortex.com + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * color - color in hex value + * headLength - Number + * headWidth - Number + */ -THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { +THREE.ArrowHelper = ( function () { - var duration = -1; + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); - var animation = this.animationsMap[ name ]; + var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); - if ( animation ) { + return function ( dir, origin, length, color, headLength, headWidth ) { - duration = animation.duration; + // dir is assumed to be normalized - } + THREE.Object3D.call( this ); - return duration; + if ( color === undefined ) color = 0xffff00; + if ( length === undefined ) length = 1; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; -}; + this.position.copy( origin ); -THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); - var animation = this.animationsMap[ name ]; + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); - if ( animation ) { + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); - animation.time = 0; - animation.active = true; + } - } else { +}() ); - console.warn( "animation[" + name + "] undefined" ); +THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.ArrowHelper.prototype.constructor = THREE.ArrowHelper; - } +THREE.ArrowHelper.prototype.setDirection = ( function () { -}; + var axis = new THREE.Vector3(); + var radians; -THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { + return function ( dir ) { - var animation = this.animationsMap[ name ]; + // dir is assumed to be normalized - if ( animation ) { + if ( dir.y > 0.99999 ) { - animation.active = false; + this.quaternion.set( 0, 0, 0, 1 ); - } + } else if ( dir.y < - 0.99999 ) { -}; + this.quaternion.set( 1, 0, 0, 0 ); -THREE.MorphBlendMesh.prototype.update = function ( delta ) { + } else { - for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { + axis.set( dir.z, 0, - dir.x ).normalize(); - var animation = this.animationsList[ i ]; + radians = Math.acos( dir.y ); - if ( ! animation.active ) continue; + this.quaternion.setFromAxisAngle( axis, radians ); - var frameTime = animation.duration / animation.length; + } - animation.time += animation.direction * delta; + }; - if ( animation.mirroredLoop ) { +}() ); - if ( animation.time > animation.duration || animation.time < 0 ) { +THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { - animation.direction *= -1; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; - if ( animation.time > animation.duration ) { + this.line.scale.set( 1, length - headLength, 1 ); + this.line.updateMatrix(); - animation.time = animation.duration; - animation.directionBackwards = true; + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); - } +}; - if ( animation.time < 0 ) { +THREE.ArrowHelper.prototype.setColor = function ( color ) { - animation.time = 0; - animation.directionBackwards = false; + this.line.material.color.set( color ); + this.cone.material.color.set( color ); - } +}; - } +// File:src/extras/helpers/BoxHelper.js - } else { +/** + * @author mrdoob / http://mrdoob.com/ + */ - animation.time = animation.time % animation.duration; +THREE.BoxHelper = function ( object ) { - if ( animation.time < 0 ) animation.time += animation.duration; + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( 72 ), 3 ) ); - } + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); - var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); - var weight = animation.weight; + if ( object !== undefined ) { - if ( keyframe !== animation.currentFrame ) { + this.update( object ); - this.morphTargetInfluences[ animation.lastFrame ] = 0; - this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; + } - this.morphTargetInfluences[ keyframe ] = 0; +}; - animation.lastFrame = animation.currentFrame; - animation.currentFrame = keyframe; +THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.BoxHelper.prototype.constructor = THREE.BoxHelper; - } +THREE.BoxHelper.prototype.update = function ( object ) { - var mix = ( animation.time % frameTime ) / frameTime; + var geometry = object.geometry; - if ( animation.directionBackwards ) mix = 1 - mix; + if ( geometry.boundingBox === null ) { - this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; - this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + geometry.computeBoundingBox(); } -}; + var min = geometry.boundingBox.min; + var max = geometry.boundingBox.max; -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ + + 0: max.x, max.y, max.z + 1: min.x, max.y, max.z + 2: min.x, min.y, max.z + 3: max.x, min.y, max.z + 4: max.x, max.y, min.z + 5: min.x, max.y, min.z + 6: min.x, min.y, min.z + 7: max.x, min.y, min.z + */ -THREE.LensFlarePlugin = function () { + var vertices = this.geometry.attributes.position.array; - var _gl, _renderer, _precision, _lensFlare = {}; + vertices[ 0 ] = max.x; vertices[ 1 ] = max.y; vertices[ 2 ] = max.z; + vertices[ 3 ] = min.x; vertices[ 4 ] = max.y; vertices[ 5 ] = max.z; - this.init = function ( renderer ) { + vertices[ 6 ] = min.x; vertices[ 7 ] = max.y; vertices[ 8 ] = max.z; + vertices[ 9 ] = min.x; vertices[ 10 ] = min.y; vertices[ 11 ] = max.z; - _gl = renderer.context; - _renderer = renderer; + vertices[ 12 ] = min.x; vertices[ 13 ] = min.y; vertices[ 14 ] = max.z; + vertices[ 15 ] = max.x; vertices[ 16 ] = min.y; vertices[ 17 ] = max.z; - _precision = renderer.getPrecision(); + vertices[ 18 ] = max.x; vertices[ 19 ] = min.y; vertices[ 20 ] = max.z; + vertices[ 21 ] = max.x; vertices[ 22 ] = max.y; vertices[ 23 ] = max.z; - _lensFlare.vertices = new Float32Array( 8 + 8 ); - _lensFlare.faces = new Uint16Array( 6 ); + // - var i = 0; - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. + vertices[ 24 ] = max.x; vertices[ 25 ] = max.y; vertices[ 26 ] = min.z; + vertices[ 27 ] = min.x; vertices[ 28 ] = max.y; vertices[ 29 ] = min.z; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; + vertices[ 30 ] = min.x; vertices[ 31 ] = max.y; vertices[ 32 ] = min.z; + vertices[ 33 ] = min.x; vertices[ 34 ] = min.y; vertices[ 35 ] = min.z; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + vertices[ 36 ] = min.x; vertices[ 37 ] = min.y; vertices[ 38 ] = min.z; + vertices[ 39 ] = max.x; vertices[ 40 ] = min.y; vertices[ 41 ] = min.z; - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; + vertices[ 42 ] = max.x; vertices[ 43 ] = min.y; vertices[ 44 ] = min.z; + vertices[ 45 ] = max.x; vertices[ 46 ] = max.y; vertices[ 47 ] = min.z; - i = 0; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; + // - // buffers + vertices[ 48 ] = max.x; vertices[ 49 ] = max.y; vertices[ 50 ] = max.z; + vertices[ 51 ] = max.x; vertices[ 52 ] = max.y; vertices[ 53 ] = min.z; - _lensFlare.vertexBuffer = _gl.createBuffer(); - _lensFlare.elementBuffer = _gl.createBuffer(); + vertices[ 54 ] = min.x; vertices[ 55 ] = max.y; vertices[ 56 ] = max.z; + vertices[ 57 ] = min.x; vertices[ 58 ] = max.y; vertices[ 59 ] = min.z; - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); + vertices[ 60 ] = min.x; vertices[ 61 ] = min.y; vertices[ 62 ] = max.z; + vertices[ 63 ] = min.x; vertices[ 64 ] = min.y; vertices[ 65 ] = min.z; - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); + vertices[ 66 ] = max.x; vertices[ 67 ] = min.y; vertices[ 68 ] = max.z; + vertices[ 69 ] = max.x; vertices[ 70 ] = min.y; vertices[ 71 ] = min.z; - // textures + this.geometry.attributes.position.needsUpdate = true; + + this.geometry.computeBoundingSphere(); - _lensFlare.tempTexture = _gl.createTexture(); - _lensFlare.occlusionTexture = _gl.createTexture(); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); +}; - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); +// File:src/extras/helpers/BoundingBoxHelper.js - if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { +/** + * @author WestLangley / http://github.com/WestLangley + */ - _lensFlare.hasVertexTexture = false; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); +// a helper to show the world-axis-aligned bounding box for an object - } else { +THREE.BoundingBoxHelper = function ( object, hex ) { - _lensFlare.hasVertexTexture = true; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); + var color = ( hex !== undefined ) ? hex : 0x888888; - } + this.object = object; - _lensFlare.attributes = {}; - _lensFlare.uniforms = {}; + this.box = new THREE.Box3(); - _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); - _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); + THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); - _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); - _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); - _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); - _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); - _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); - _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); - _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); - _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); +}; - }; +THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); +THREE.BoundingBoxHelper.prototype.constructor = THREE.BoundingBoxHelper; +THREE.BoundingBoxHelper.prototype.update = function () { - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - * Then _lensFlare.update_lensFlares() is called to re-position and - * update transparency of flares. Then they are rendered. - * - */ + this.box.setFromObject( this.object ); - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + this.box.size( this.scale ); + + this.box.center( this.position ); - var flares = scene.__webglFlares, - nFlares = flares.length; +}; - if ( ! nFlares ) return; +// File:src/extras/helpers/CameraHelper.js - var tempPosition = new THREE.Vector3(); +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * http://evanw.github.com/lightgl.js/tests/shadowmap.html + */ - var invAspect = viewportHeight / viewportWidth, - halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; +THREE.CameraHelper = function ( camera ) { - var size = 16 / viewportHeight, - scale = new THREE.Vector2( size * invAspect, size ); + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); - var screenPosition = new THREE.Vector3( 1, 1, 0 ), - screenPositionPixels = new THREE.Vector2( 1, 1 ); + var pointMap = {}; - var uniforms = _lensFlare.uniforms, - attributes = _lensFlare.attributes; + // colors - // set _lensFlare program and reset blending + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; - _gl.useProgram( _lensFlare.program ); + // near - _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); - _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/unforms + // far - _gl.uniform1i( uniforms.occlusionMap, 0 ); - _gl.uniform1i( uniforms.map, 1 ); + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + // sides - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); - _gl.disable( _gl.CULL_FACE ); - _gl.depthMask( false ); + // cone - var i, j, jl, flare, sprite; + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); - for ( i = 0; i < nFlares; i ++ ) { + // up - size = 16 / viewportHeight; - scale.set( size * invAspect, size ); + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); - // calc object screen position + // target - flare = flares[ i ]; + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); - tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + // cross - tempPosition.applyMatrix4( camera.matrixWorldInverse ); - tempPosition.applyProjection( camera.projectionMatrix ); + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); - // setup arrays for gl programs + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); - screenPosition.copy( tempPosition ) + function addLine( a, b, hex ) { - screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; - screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + addPoint( a, hex ); + addPoint( b, hex ); - // screen cull + } - if ( _lensFlare.hasVertexTexture || ( - screenPositionPixels.x > 0 && - screenPositionPixels.x < viewportWidth && - screenPositionPixels.y > 0 && - screenPositionPixels.y < viewportHeight ) ) { + function addPoint( id, hex ) { - // save current RGB to temp texture + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( hex ) ); - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + if ( pointMap[ id ] === undefined ) { + pointMap[ id ] = []; - // render pink quad + } - _gl.uniform1i( uniforms.renderType, 0 ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + pointMap[ id ].push( geometry.vertices.length - 1 ); - _gl.disable( _gl.BLEND ); - _gl.enable( _gl.DEPTH_TEST ); + } - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + this.camera = camera; + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - // copy result to occlusionMap + this.pointMap = pointMap; - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + this.update(); +}; - // restore graphics +THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.CameraHelper.prototype.constructor = THREE.CameraHelper; - _gl.uniform1i( uniforms.renderType, 1 ); - _gl.disable( _gl.DEPTH_TEST ); +THREE.CameraHelper.prototype.update = function () { - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + var geometry, pointMap; + + var vector = new THREE.Vector3(); + var camera = new THREE.Camera(); + var setPoint = function ( point, x, y, z ) { - // update object positions + vector.set( x, y, z ).unproject( camera ); - flare.positionScreen.copy( screenPosition ) + var points = pointMap[ point ]; - if ( flare.customUpdateCallback ) { + if ( points !== undefined ) { - flare.customUpdateCallback( flare ); + for ( var i = 0, il = points.length; i < il; i ++ ) { - } else { + geometry.vertices[ points[ i ] ].copy( vector ); - flare.updateLensFlares(); + } - } + } - // render flares + }; - _gl.uniform1i( uniforms.renderType, 2 ); - _gl.enable( _gl.BLEND ); + return function () { - for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { + geometry = this.geometry; + pointMap = this.pointMap; - sprite = flare.lensFlares[ j ]; + var w = 1, h = 1; - if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { + // we need just camera projection matrix + // world matrix must be identity - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; + camera.projectionMatrix.copy( this.camera.projectionMatrix ); - size = sprite.size * sprite.scale / viewportHeight; + // center / target - scale.x = size * invAspect; - scale.y = size; + setPoint( "c", 0, 0, - 1 ); + setPoint( "t", 0, 0, 1 ); - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform1f( uniforms.rotation, sprite.rotation ); + // near - _gl.uniform1f( uniforms.opacity, sprite.opacity ); - _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); + setPoint( "n1", - w, - h, - 1 ); + setPoint( "n2", w, - h, - 1 ); + setPoint( "n3", - w, h, - 1 ); + setPoint( "n4", w, h, - 1 ); - _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - _renderer.setTexture( sprite.texture, 1 ); + // far - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + setPoint( "f1", - w, - h, 1 ); + setPoint( "f2", w, - h, 1 ); + setPoint( "f3", - w, h, 1 ); + setPoint( "f4", w, h, 1 ); - } + // up - } + setPoint( "u1", w * 0.7, h * 1.1, - 1 ); + setPoint( "u2", - w * 0.7, h * 1.1, - 1 ); + setPoint( "u3", 0, h * 2, - 1 ); - } + // cross - } + setPoint( "cf1", - w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, - h, 1 ); + setPoint( "cf4", 0, h, 1 ); - // restore gl + setPoint( "cn1", - w, 0, - 1 ); + setPoint( "cn2", w, 0, - 1 ); + setPoint( "cn3", 0, - h, - 1 ); + setPoint( "cn4", 0, h, - 1 ); - _gl.enable( _gl.CULL_FACE ); - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthMask( true ); + geometry.verticesNeedUpdate = true; }; - function createProgram ( shader, precision ) { - - var program = _gl.createProgram(); +}(); - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); +// File:src/extras/helpers/DirectionalLightHelper.js - var prefix = "precision " + precision + " float;\n"; +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ - _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); +THREE.DirectionalLightHelper = function ( light, size ) { - _gl.compileShader( fragmentShader ); - _gl.compileShader( vertexShader ); + THREE.Object3D.call( this ); - _gl.attachShader( program, fragmentShader ); - _gl.attachShader( program, vertexShader ); + this.light = light; + this.light.updateMatrixWorld(); - _gl.linkProgram( program ); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - return program; + size = size || 1; - }; + var geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3( - size, size, 0 ), + new THREE.Vector3( size, size, 0 ), + new THREE.Vector3( size, - size, 0 ), + new THREE.Vector3( - size, - size, 0 ), + new THREE.Vector3( - size, size, 0 ) + ); -}; + var material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + this.lightPlane = new THREE.Line( geometry, material ); + this.add( this.lightPlane ); -THREE.ShadowMapPlugin = function () { + geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3(), + new THREE.Vector3() + ); - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(), + this.targetLine = new THREE.Line( geometry, material ); + this.add( this.targetLine ); - _min = new THREE.Vector3(), - _max = new THREE.Vector3(), + this.update(); - _matrixPosition = new THREE.Vector3(); +}; - this.init = function ( renderer ) { +THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.DirectionalLightHelper.prototype.constructor = THREE.DirectionalLightHelper; - _gl = renderer.context; - _renderer = renderer; +THREE.DirectionalLightHelper.prototype.dispose = function () { - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); +}; - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); +THREE.DirectionalLightHelper.prototype.update = function () { - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var v3 = new THREE.Vector3(); - }; + return function () { - this.render = function ( scene, camera ) { + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); - if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; + this.lightPlane.lookAt( v3 ); + this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.update( scene, camera ); + this.targetLine.geometry.vertices[ 1 ].copy( v3 ); + this.targetLine.geometry.verticesNeedUpdate = true; + this.targetLine.material.color.copy( this.lightPlane.material.color ); }; - this.update = function ( scene, camera ) { +}(); - var i, il, j, jl, n, +// File:src/extras/helpers/EdgesHelper.js - shadowMap, shadowMatrix, shadowCamera, - program, buffer, material, - webglObject, object, light, - renderList, +/** + * @author WestLangley / http://github.com/WestLangley + * @param object THREE.Mesh whose geometry will be used + * @param hex line color + * @param thresholdAngle the minimim angle (in degrees), + * between the face normals of adjacent faces, + * that is required to render an edge. A value of 10 means + * an edge is only rendered if the angle is at least 10 degrees. + */ - lights = [], - k = 0, +THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { - fog = null; + var color = ( hex !== undefined ) ? hex : 0xffffff; + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - // set GL state for depth map + var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; - _gl.enable( _gl.CULL_FACE ); - _gl.frontFace( _gl.CCW ); + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + var geometry2; - _gl.cullFace( _gl.FRONT ); + if ( object.geometry instanceof THREE.BufferGeometry ) { - } else { + geometry2 = new THREE.Geometry(); + geometry2.fromBufferGeometry( object.geometry ); - _gl.cullFace( _gl.BACK ); + } else { - } + geometry2 = object.geometry.clone(); - _renderer.setDepthTest( true ); + } - // preprocess lights - // - skip lights that are not casting shadows - // - create virtual lights for cascaded shadow maps + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); - for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { + var vertices = geometry2.vertices; + var faces = geometry2.faces; + var numEdges = 0; - light = scene.__lights[ i ]; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - if ( ! light.castShadow ) continue; + var face = faces[ i ]; - if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { + for ( var j = 0; j < 3; j ++ ) { - for ( n = 0; n < light.shadowCascadeCount; n ++ ) { + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - var virtualLight; + var key = edge.toString(); - if ( ! light.shadowCascadeArray[ n ] ) { + if ( hash[ key ] === undefined ) { - virtualLight = createVirtualLight( light, n ); - virtualLight.originalCamera = camera; + hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; + numEdges ++; - var gyro = new THREE.Gyroscope(); - gyro.position = light.shadowCascadeOffset; + } else { - gyro.add( virtualLight ); - gyro.add( virtualLight.target ); + hash[ key ].face2 = i; - camera.add( gyro ); + } - light.shadowCascadeArray[ n ] = virtualLight; + } - console.log( "Created virtualLight", virtualLight ); + } - } else { + var coords = new Float32Array( numEdges * 2 * 3 ); - virtualLight = light.shadowCascadeArray[ n ]; + var index = 0; - } + for ( var key in hash ) { - updateVirtualLight( light, n ); + var h = hash[ key ]; - lights[ k ] = virtualLight; - k ++; + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { + + var vertex = vertices[ h.vert1 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + vertex = vertices[ h.vert2 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + } - } + } - } else { + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - lights[ k ] = light; - k ++; + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - } + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - } +}; - // render depth map +THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; - for ( i = 0, il = lights.length; i < il; i ++ ) { +// File:src/extras/helpers/FaceNormalsHelper.js - light = lights[ i ]; +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - if ( ! light.shadowMap ) { +THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { - var shadowFilter = THREE.LinearFilter; + this.object = object; - if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { + this.size = ( size !== undefined ) ? size : 1; - shadowFilter = THREE.NearestFilter; + var color = ( hex !== undefined ) ? hex : 0xffff00; - } + var width = ( linewidth !== undefined ) ? linewidth : 1; - var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; + var geometry = new THREE.Geometry(); - light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); - light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + var faces = this.object.geometry.faces; - light.shadowMatrix = new THREE.Matrix4(); + for ( var i = 0, l = faces.length; i < l; i ++ ) { - } + geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - if ( ! light.shadowCamera ) { + } - if ( light instanceof THREE.SpotLight ) { + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); + this.matrixAutoUpdate = false; - } else if ( light instanceof THREE.DirectionalLight ) { + this.normalMatrix = new THREE.Matrix3(); - light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); + this.update(); - } else { +}; - console.error( "Unsupported light type for shadow" ); - continue; +THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper; - } +THREE.FaceNormalsHelper.prototype.update = function () { - scene.add( light.shadowCamera ); + var vertices = this.geometry.vertices; - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + var object = this.object; + var objectVertices = object.geometry.vertices; + var objectFaces = object.geometry.faces; + var objectWorldMatrix = object.matrixWorld; - } + object.updateMatrixWorld( true ); - if ( light.shadowCameraVisible && ! light.cameraHelper ) { + this.normalMatrix.getNormalMatrix( objectWorldMatrix ); - light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); - light.shadowCamera.add( light.cameraHelper ); + for ( var i = 0, i2 = 0, l = objectFaces.length; i < l; i ++, i2 += 2 ) { - } + var face = objectFaces[ i ]; - if ( light.isVirtual && virtualLight.originalCamera == camera ) { + vertices[ i2 ].copy( objectVertices[ face.a ] ) + .add( objectVertices[ face.b ] ) + .add( objectVertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( objectWorldMatrix ); - updateShadowCamera( camera, light ); + vertices[ i2 + 1 ].copy( face.normal ) + .applyMatrix3( this.normalMatrix ) + .normalize() + .multiplyScalar( this.size ) + .add( vertices[ i2 ] ); - } + } - shadowMap = light.shadowMap; - shadowMatrix = light.shadowMatrix; - shadowCamera = light.shadowCamera; + this.geometry.verticesNeedUpdate = true; - shadowCamera.position.getPositionFromMatrix( light.matrixWorld ); - _matrixPosition.getPositionFromMatrix( light.target.matrixWorld ); - shadowCamera.lookAt( _matrixPosition ); - shadowCamera.updateMatrixWorld(); + return this; - shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); +}; - if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; - if ( light.shadowCameraVisible ) light.cameraHelper.update(); - // compute shadow matrix +// File:src/extras/helpers/GridHelper.js - shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); +THREE.GridHelper = function ( size, step ) { - // update camera matrices and frustum + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + this.color1 = new THREE.Color( 0x444444 ); + this.color2 = new THREE.Color( 0x888888 ); - // render shadow map + for ( var i = - size; i <= size; i += step ) { - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); + geometry.vertices.push( + new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), + new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) + ); - // set object matrices & frustum culling + var color = i === 0 ? this.color1 : this.color2; - renderList = scene.__webglObjects; + geometry.colors.push( color, color, color, color ); - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + } - webglObject = renderList[ j ]; - object = webglObject.object; + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - webglObject.render = false; +}; - if ( object.visible && object.castShadow ) { +THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.GridHelper.prototype.constructor = THREE.GridHelper; - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { +THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + this.color1.set( colorCenterLine ); + this.color2.set( colorGrid ); - webglObject.render = true; + this.geometry.colorsNeedUpdate = true; - } +} - } +// File:src/extras/helpers/HemisphereLightHelper.js - } +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - // render regular objects +THREE.HemisphereLightHelper = function ( light, sphereSize ) { - var objectMaterial, useMorphing, useSkinning; + THREE.Object3D.call( this ); - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + this.light = light; + this.light.updateMatrixWorld(); - webglObject = renderList[ j ]; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - if ( webglObject.render ) { + this.colors = [ new THREE.Color(), new THREE.Color() ]; - object = webglObject.object; - buffer = webglObject.buffer; + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - // culling is overriden globally for all objects - // while rendering depth map + for ( var i = 0, il = 8; i < il; i ++ ) { - // need to deal with MeshFaceMaterial somehow - // in that case just use the first of material.materials for now - // (proper solution would require to break objects by materials - // similarly to regular rendering and then set corresponding - // depth materials per each chunk instead of just once per object) + geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; - objectMaterial = getObjectMaterial( object ); + } - useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); - if ( object.customDepthMaterial ) { + this.lightSphere = new THREE.Mesh( geometry, material ); + this.add( this.lightSphere ); - material = object.customDepthMaterial; + this.update(); - } else if ( useSkinning ) { +}; - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; +THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.HemisphereLightHelper.prototype.constructor = THREE.HemisphereLightHelper; - } else if ( useMorphing ) { +THREE.HemisphereLightHelper.prototype.dispose = function () { + this.lightSphere.geometry.dispose(); + this.lightSphere.material.dispose(); +}; - material = _depthMaterialMorph; +THREE.HemisphereLightHelper.prototype.update = function () { - } else { + var vector = new THREE.Vector3(); - material = _depthMaterial; + return function () { - } + this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); - if ( buffer instanceof THREE.BufferGeometry ) { + this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + this.lightSphere.geometry.colorsNeedUpdate = true; - _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); + } - } else { +}(); - _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); +// File:src/extras/helpers/PointLightHelper.js - } +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - } +THREE.PointLightHelper = function ( light, sphereSize ) { - } + this.light = light; + this.light.updateMatrixWorld(); - // set matrices and render immediate objects + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - renderList = scene.__webglObjectsImmediate; + THREE.Mesh.call( this, geometry, material ); - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; - webglObject = renderList[ j ]; - object = webglObject.object; + /* + var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - if ( object.visible && object.castShadow ) { + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + var d = light.distance; - _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); + if ( d === 0.0 ) { - } + this.lightDistance.visible = false; - } + } else { - } + this.lightDistance.scale.set( d, d, d ); - // restore GL state + } - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); + this.add( this.lightDistance ); + */ - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); +}; - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { +THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); +THREE.PointLightHelper.prototype.constructor = THREE.PointLightHelper; - _gl.cullFace( _gl.BACK ); +THREE.PointLightHelper.prototype.dispose = function () { - } + this.geometry.dispose(); + this.material.dispose(); +}; - }; +THREE.PointLightHelper.prototype.update = function () { - function createVirtualLight( light, cascade ) { + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - var virtualLight = new THREE.DirectionalLight(); + /* + var d = this.light.distance; - virtualLight.isVirtual = true; + if ( d === 0.0 ) { - virtualLight.onlyShadow = true; - virtualLight.castShadow = true; + this.lightDistance.visible = false; - virtualLight.shadowCameraNear = light.shadowCameraNear; - virtualLight.shadowCameraFar = light.shadowCameraFar; + } else { - virtualLight.shadowCameraLeft = light.shadowCameraLeft; - virtualLight.shadowCameraRight = light.shadowCameraRight; - virtualLight.shadowCameraBottom = light.shadowCameraBottom; - virtualLight.shadowCameraTop = light.shadowCameraTop; + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); - virtualLight.shadowCameraVisible = light.shadowCameraVisible; + } + */ - virtualLight.shadowDarkness = light.shadowDarkness; +}; - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; - virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; +// File:src/extras/helpers/SkeletonHelper.js - virtualLight.pointsWorld = []; - virtualLight.pointsFrustum = []; +/** + * @author Sean Griffin / http://twitter.com/sgrif + * @author Michael Guerrero / http://realitymeltdown.com + * @author mrdoob / http://mrdoob.com/ + * @author ikerr / http://verold.com + */ - var pointsWorld = virtualLight.pointsWorld, - pointsFrustum = virtualLight.pointsFrustum; +THREE.SkeletonHelper = function ( object ) { - for ( var i = 0; i < 8; i ++ ) { + this.bones = this.getBoneList( object ); - pointsWorld[ i ] = new THREE.Vector3(); - pointsFrustum[ i ] = new THREE.Vector3(); + var geometry = new THREE.Geometry(); - } + for ( var i = 0; i < this.bones.length; i ++ ) { - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; + var bone = this.bones[ i ]; - pointsFrustum[ 0 ].set( -1, -1, nearZ ); - pointsFrustum[ 1 ].set( 1, -1, nearZ ); - pointsFrustum[ 2 ].set( -1, 1, nearZ ); - pointsFrustum[ 3 ].set( 1, 1, nearZ ); + if ( bone.parent instanceof THREE.Bone ) { - pointsFrustum[ 4 ].set( -1, -1, farZ ); - pointsFrustum[ 5 ].set( 1, -1, farZ ); - pointsFrustum[ 6 ].set( -1, 1, farZ ); - pointsFrustum[ 7 ].set( 1, 1, farZ ); + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( 0, 0, 1 ) ); + geometry.colors.push( new THREE.Color( 0, 1, 0 ) ); - return virtualLight; + } } - // Synchronize virtual light with the original light + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } ); - function updateVirtualLight( light, cascade ) { + THREE.Line.call( this, geometry, material, THREE.LinePieces ); - var virtualLight = light.shadowCascadeArray[ cascade ]; + this.root = object; - virtualLight.position.copy( light.position ); - virtualLight.target.position.copy( light.target.position ); - virtualLight.lookAt( virtualLight.target ); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; + + this.update(); + +}; - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - virtualLight.shadowDarkness = light.shadowDarkness; - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; +THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper; - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; +THREE.SkeletonHelper.prototype.getBoneList = function( object ) { - var pointsFrustum = virtualLight.pointsFrustum; + var boneList = []; - pointsFrustum[ 0 ].z = nearZ; - pointsFrustum[ 1 ].z = nearZ; - pointsFrustum[ 2 ].z = nearZ; - pointsFrustum[ 3 ].z = nearZ; + if ( object instanceof THREE.Bone ) { - pointsFrustum[ 4 ].z = farZ; - pointsFrustum[ 5 ].z = farZ; - pointsFrustum[ 6 ].z = farZ; - pointsFrustum[ 7 ].z = farZ; + boneList.push( object ); } - // Fit shadow camera's ortho frustum to camera frustum + for ( var i = 0; i < object.children.length; i ++ ) { - function updateShadowCamera( camera, light ) { + boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); - var shadowCamera = light.shadowCamera, - pointsFrustum = light.pointsFrustum, - pointsWorld = light.pointsWorld; + } - _min.set( Infinity, Infinity, Infinity ); - _max.set( -Infinity, -Infinity, -Infinity ); + return boneList; - for ( var i = 0; i < 8; i ++ ) { +}; - var p = pointsWorld[ i ]; +THREE.SkeletonHelper.prototype.update = function () { - p.copy( pointsFrustum[ i ] ); - THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); + var geometry = this.geometry; - p.applyMatrix4( shadowCamera.matrixWorldInverse ); + var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld ); - if ( p.x < _min.x ) _min.x = p.x; - if ( p.x > _max.x ) _max.x = p.x; + var boneMatrix = new THREE.Matrix4(); - if ( p.y < _min.y ) _min.y = p.y; - if ( p.y > _max.y ) _max.y = p.y; + var j = 0; - if ( p.z < _min.z ) _min.z = p.z; - if ( p.z > _max.z ) _max.z = p.z; + for ( var i = 0; i < this.bones.length; i ++ ) { - } + var bone = this.bones[ i ]; - shadowCamera.left = _min.x; - shadowCamera.right = _max.x; - shadowCamera.top = _max.y; - shadowCamera.bottom = _min.y; + if ( bone.parent instanceof THREE.Bone ) { - // can't really fit near/far - //shadowCamera.near = _min.z; - //shadowCamera.far = _max.z; + boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); + geometry.vertices[ j ].setFromMatrixPosition( boneMatrix ); - shadowCamera.updateProjectionMatrix(); + boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); + geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix ); - } + j += 2; - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use for shadow maps + } - function getObjectMaterial( object ) { + } - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; + geometry.verticesNeedUpdate = true; - }; + geometry.computeBoundingSphere(); }; -THREE.ShadowMapPlugin.__projector = new THREE.Projector(); +// File:src/extras/helpers/SpotLightHelper.js /** - * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ - */ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ -THREE.SpritePlugin = function () { +THREE.SpotLightHelper = function ( light ) { - var _gl, _renderer, _precision, _sprite = {}; + THREE.Object3D.call( this ); - this.init = function ( renderer ) { + this.light = light; + this.light.updateMatrixWorld(); - _gl = renderer.context; - _renderer = renderer; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - _precision = renderer.getPrecision(); + var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); - _sprite.vertices = new Float32Array( 8 + 8 ); - _sprite.faces = new Uint16Array( 6 ); + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - var i = 0; + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - _sprite.vertices[ i++ ] = -0.5; _sprite.vertices[ i++ ] = -0.5; // vertex 0 - _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 0; // uv 0 + this.cone = new THREE.Mesh( geometry, material ); + this.add( this.cone ); - _sprite.vertices[ i++ ] = 0.5; _sprite.vertices[ i++ ] = -0.5; // vertex 1 - _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 0; // uv 1 + this.update(); - _sprite.vertices[ i++ ] = 0.5; _sprite.vertices[ i++ ] = 0.5; // vertex 2 - _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // uv 2 +}; - _sprite.vertices[ i++ ] = -0.5; _sprite.vertices[ i++ ] = 0.5; // vertex 3 - _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 1; // uv 3 +THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); +THREE.SpotLightHelper.prototype.constructor = THREE.SpotLightHelper; - i = 0; +THREE.SpotLightHelper.prototype.dispose = function () { + this.cone.geometry.dispose(); + this.cone.material.dispose(); +}; - _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2; - _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3; +THREE.SpotLightHelper.prototype.update = function () { - _sprite.vertexBuffer = _gl.createBuffer(); - _sprite.elementBuffer = _gl.createBuffer(); + var vector = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); - _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW ); + return function () { - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW ); + var coneLength = this.light.distance ? this.light.distance : 10000; + var coneWidth = coneLength * Math.tan( this.light.angle ); - _sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ], _precision ); + this.cone.scale.set( coneWidth, coneWidth, coneLength ); - _sprite.attributes = {}; - _sprite.uniforms = {}; + vector.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); - _sprite.attributes.position = _gl.getAttribLocation ( _sprite.program, "position" ); - _sprite.attributes.uv = _gl.getAttribLocation ( _sprite.program, "uv" ); + this.cone.lookAt( vector2.sub( vector ) ); - _sprite.uniforms.uvOffset = _gl.getUniformLocation( _sprite.program, "uvOffset" ); - _sprite.uniforms.uvScale = _gl.getUniformLocation( _sprite.program, "uvScale" ); + this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - _sprite.uniforms.rotation = _gl.getUniformLocation( _sprite.program, "rotation" ); - _sprite.uniforms.scale = _gl.getUniformLocation( _sprite.program, "scale" ); - _sprite.uniforms.alignment = _gl.getUniformLocation( _sprite.program, "alignment" ); - _sprite.uniforms.halfViewport = _gl.getUniformLocation( _sprite.program, "halfViewport" ); + }; - _sprite.uniforms.color = _gl.getUniformLocation( _sprite.program, "color" ); - _sprite.uniforms.map = _gl.getUniformLocation( _sprite.program, "map" ); - _sprite.uniforms.opacity = _gl.getUniformLocation( _sprite.program, "opacity" ); +}(); - _sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" ); - _sprite.uniforms.sizeAttenuation = _gl.getUniformLocation( _sprite.program, "sizeAttenuation" ); - _sprite.uniforms.screenPosition = _gl.getUniformLocation( _sprite.program, "screenPosition" ); - _sprite.uniforms.modelViewMatrix = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" ); - _sprite.uniforms.projectionMatrix = _gl.getUniformLocation( _sprite.program, "projectionMatrix" ); +// File:src/extras/helpers/VertexNormalsHelper.js - _sprite.uniforms.fogType = _gl.getUniformLocation( _sprite.program, "fogType" ); - _sprite.uniforms.fogDensity = _gl.getUniformLocation( _sprite.program, "fogDensity" ); - _sprite.uniforms.fogNear = _gl.getUniformLocation( _sprite.program, "fogNear" ); - _sprite.uniforms.fogFar = _gl.getUniformLocation( _sprite.program, "fogFar" ); - _sprite.uniforms.fogColor = _gl.getUniformLocation( _sprite.program, "fogColor" ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - _sprite.uniforms.alphaTest = _gl.getUniformLocation( _sprite.program, "alphaTest" ); +THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - }; + this.object = object; - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + this.size = ( size !== undefined ) ? size : 1; - var sprites = scene.__webglSprites, - nSprites = sprites.length; + var color = ( hex !== undefined ) ? hex : 0xff0000; - if ( ! nSprites ) return; + var width = ( linewidth !== undefined ) ? linewidth : 1; - var attributes = _sprite.attributes, - uniforms = _sprite.uniforms; + var geometry = new THREE.Geometry(); - var halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; + var faces = object.geometry.faces; - // setup gl + for ( var i = 0, l = faces.length; i < l; i ++ ) { - _gl.useProgram( _sprite.program ); + var face = faces[ i ]; - _gl.enableVertexAttribArray( attributes.position ); - _gl.enableVertexAttribArray( attributes.uv ); + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - _gl.disable( _gl.CULL_FACE ); - _gl.enable( _gl.BLEND ); + geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer ); - _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + } - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer ); + } - _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.uniform1i( uniforms.map, 0 ); + this.matrixAutoUpdate = false; - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; + this.normalMatrix = new THREE.Matrix3(); - if ( fog ) { + this.update(); - _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); +}; - if ( fog instanceof THREE.Fog ) { +THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper; - _gl.uniform1f( uniforms.fogNear, fog.near ); - _gl.uniform1f( uniforms.fogFar, fog.far ); +THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { - _gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; + var v1 = new THREE.Vector3(); - } else if ( fog instanceof THREE.FogExp2 ) { + return function( object ) { - _gl.uniform1f( uniforms.fogDensity, fog.density ); + var keys = [ 'a', 'b', 'c', 'd' ]; - _gl.uniform1i( uniforms.fogType, 2 ); - oldFogType = 2; - sceneFogType = 2; + this.object.updateMatrixWorld( true ); - } + this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - } else { + var vertices = this.geometry.vertices; - _gl.uniform1i( uniforms.fogType, 0 ); - oldFogType = 0; - sceneFogType = 0; + var verts = this.object.geometry.vertices; - } + var faces = this.object.geometry.faces; + var worldMatrix = this.object.matrixWorld; - // update positions and sort + var idx = 0; - var i, sprite, material, screenPosition, fogType, scale = []; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - for( i = 0; i < nSprites; i ++ ) { + var face = faces[ i ]; - sprite = sprites[ i ]; - material = sprite.material; + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - if ( ! sprite.visible || material.opacity === 0 ) continue; + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; - if ( ! material.useScreenCoordinates ) { + var normal = face.vertexNormals[ j ]; - sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); - sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - } else { + v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); - sprite.z = - sprite.position.z; + v1.add( vertices[ idx ] ); + idx = idx + 1; + + vertices[ idx ].copy( v1 ); + idx = idx + 1; } } - sprites.sort( painterSortStable ); + this.geometry.verticesNeedUpdate = true; - // render all sprites + return this; - for( i = 0; i < nSprites; i ++ ) { + } - sprite = sprites[ i ]; - material = sprite.material; +}()); - if ( ! sprite.visible || material.opacity === 0 ) continue; +// File:src/extras/helpers/VertexTangentsHelper.js - if ( material.map && material.map.image && material.map.image.width ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ - _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); +THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { - if ( material.useScreenCoordinates === true ) { + this.object = object; - _gl.uniform1i( uniforms.useScreenCoordinates, 1 ); - _gl.uniform3f( - uniforms.screenPosition, - ( ( sprite.position.x * _renderer.devicePixelRatio ) - halfViewportWidth ) / halfViewportWidth, - ( halfViewportHeight - ( sprite.position.y * _renderer.devicePixelRatio ) ) / halfViewportHeight, - Math.max( 0, Math.min( 1, sprite.position.z ) ) - ); + this.size = ( size !== undefined ) ? size : 1; - scale[ 0 ] = _renderer.devicePixelRatio * sprite.scale.x; - scale[ 1 ] = _renderer.devicePixelRatio * sprite.scale.y; + var color = ( hex !== undefined ) ? hex : 0x0000ff; - } else { + var width = ( linewidth !== undefined ) ? linewidth : 1; - _gl.uniform1i( uniforms.useScreenCoordinates, 0 ); - _gl.uniform1i( uniforms.sizeAttenuation, material.sizeAttenuation ? 1 : 0 ); - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); + var geometry = new THREE.Geometry(); - scale[ 0 ] = sprite.scale.x; - scale[ 1 ] = sprite.scale.y; + var faces = object.geometry.faces; - } + for ( var i = 0, l = faces.length; i < l; i ++ ) { - if ( scene.fog && material.fog ) { + var face = faces[ i ]; - fogType = sceneFogType; + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - } else { + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); - fogType = 0; + } - } + } - if ( oldFogType !== fogType ) { + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - _gl.uniform1i( uniforms.fogType, fogType ); - oldFogType = fogType; + this.matrixAutoUpdate = false; - } + this.update(); - _gl.uniform2f( uniforms.uvScale, material.uvScale.x, material.uvScale.y ); - _gl.uniform2f( uniforms.uvOffset, material.uvOffset.x, material.uvOffset.y ); - _gl.uniform2f( uniforms.alignment, material.alignment.x, material.alignment.y ); +}; - _gl.uniform1f( uniforms.opacity, material.opacity ); - _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); +THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.VertexTangentsHelper.prototype.constructor = THREE.VertexTangentsHelper; - _gl.uniform1f( uniforms.rotation, sprite.rotation ); - _gl.uniform2fv( uniforms.scale, scale ); - _gl.uniform2f( uniforms.halfViewport, halfViewportWidth, halfViewportHeight ); +THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { - _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - _renderer.setDepthTest( material.depthTest ); - _renderer.setDepthWrite( material.depthWrite ); - _renderer.setTexture( material.map, 0 ); + var v1 = new THREE.Vector3(); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + return function( object ) { - } + var keys = [ 'a', 'b', 'c', 'd' ]; - } + this.object.updateMatrixWorld( true ); - // restore gl + var vertices = this.geometry.vertices; - _gl.enable( _gl.CULL_FACE ); + var verts = this.object.geometry.vertices; - }; + var faces = this.object.geometry.faces; - function createProgram ( shader, precision ) { + var worldMatrix = this.object.matrixWorld; - var program = _gl.createProgram(); + var idx = 0; - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + for ( var i = 0, l = faces.length; i < l; i ++ ) { - var prefix = "precision " + precision + " float;\n"; + var face = faces[ i ]; - _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - _gl.compileShader( fragmentShader ); - _gl.compileShader( vertexShader ); + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; - _gl.attachShader( program, fragmentShader ); - _gl.attachShader( program, vertexShader ); + var tangent = face.vertexTangents[ j ]; - _gl.linkProgram( program ); + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - return program; + v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); - }; + v1.add( vertices[ idx ] ); + idx = idx + 1; - function painterSortStable ( a, b ) { + vertices[ idx ].copy( v1 ); + idx = idx + 1; - if ( a.z !== b.z ) { + } - return b.z - a.z; + } - } else { + this.geometry.verticesNeedUpdate = true; - return b.id - a.id; + return this; - } + } - }; +}()); -}; +// File:src/extras/helpers/WireframeHelper.js /** - * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ */ -THREE.DepthPassPlugin = function () { +THREE.WireframeHelper = function ( object, hex ) { - this.enabled = false; - this.renderTarget = null; + var color = ( hex !== undefined ) ? hex : 0xffffff; - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(); + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); - this.init = function ( renderer ) { + if ( object.geometry instanceof THREE.Geometry ) { - _gl = renderer.context; - _renderer = renderer; + var vertices = object.geometry.vertices; + var faces = object.geometry.faces; + var numEdges = 0; - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + // allocate maximal size + var edges = new Uint32Array( 6 * faces.length ); - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + for ( var i = 0, l = faces.length; i < l; i ++ ) { - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; + var face = faces[ i ]; - }; + for ( var j = 0; j < 3; j ++ ) { - this.render = function ( scene, camera ) { + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - if ( ! this.enabled ) return; + var key = edge.toString(); - this.update( scene, camera ); + if ( hash[ key ] === undefined ) { - }; + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - this.update = function ( scene, camera ) { + } - var i, il, j, jl, n, + } - program, buffer, material, - webglObject, object, light, - renderList, + } - fog = null; + var coords = new Float32Array( numEdges * 2 * 3 ); + + for ( var i = 0, l = numEdges; i < l; i ++ ) { + + for ( var j = 0; j < 2; j ++ ) { + + var vertex = vertices[ edges [ 2 * i + j] ]; + + var index = 6 * i + 3 * j; + coords[ index + 0 ] = vertex.x; + coords[ index + 1 ] = vertex.y; + coords[ index + 2 ] = vertex.z; + + } + + } + + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); + + } else if ( object.geometry instanceof THREE.BufferGeometry ) { + + if ( object.geometry.attributes.index !== undefined ) { // Indexed BufferGeometry + + var vertices = object.geometry.attributes.position.array; + var indices = object.geometry.attributes.index.array; + var drawcalls = object.geometry.drawcalls; + var numEdges = 0; + + if ( drawcalls.length === 0 ) { - // set GL state for depth map + drawcalls = [ { count : indices.length, index : 0, start : 0 } ]; - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); + } - _renderer.setDepthTest( true ); + // allocate maximal size + var edges = new Uint32Array( 2 * indices.length ); - // update scene + for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) { - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + var start = drawcalls[ o ].start; + var count = drawcalls[ o ].count; + var index = drawcalls[ o ].index; - // update camera matrices and frustum + for ( var i = start, il = start + count; i < il; i += 3 ) { - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + for ( var j = 0; j < 3; j ++ ) { - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + edge[ 0 ] = index + indices[ i + j ]; + edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; + edge.sort( sortFunction ); - // render depth map + var key = edge.toString(); - _renderer.setRenderTarget( this.renderTarget ); - _renderer.clear(); + if ( hash[ key ] === undefined ) { - // set object matrices & frustum culling + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - renderList = scene.__webglObjects; + } - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + } - webglObject = renderList[ j ]; - object = webglObject.object; + } - webglObject.render = false; + } - if ( object.visible ) { + var coords = new Float32Array( numEdges * 2 * 3 ); - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + for ( var i = 0, l = numEdges; i < l; i ++ ) { - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + for ( var j = 0; j < 2; j ++ ) { - webglObject.render = true; + var index = 6 * i + 3 * j; + var index2 = 3 * edges[ 2 * i + j]; + coords[ index + 0 ] = vertices[ index2 ]; + coords[ index + 1 ] = vertices[ index2 + 1 ]; + coords[ index + 2 ] = vertices[ index2 + 2 ]; } } - } + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - // render regular objects + } else { // non-indexed BufferGeometry - var objectMaterial, useMorphing, useSkinning; + var vertices = object.geometry.attributes.position.array; + var numEdges = vertices.length / 3; + var numTris = numEdges / 3; - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + var coords = new Float32Array( numEdges * 2 * 3 ); - webglObject = renderList[ j ]; + for ( var i = 0, l = numTris; i < l; i ++ ) { - if ( webglObject.render ) { + for ( var j = 0; j < 3; j ++ ) { - object = webglObject.object; - buffer = webglObject.buffer; + var index = 18 * i + 6 * j; - // todo: create proper depth material for particles + var index1 = 9 * i + 3 * j; + coords[ index + 0 ] = vertices[ index1 ]; + coords[ index + 1 ] = vertices[ index1 + 1 ]; + coords[ index + 2 ] = vertices[ index1 + 2 ]; - if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; + var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); + coords[ index + 3 ] = vertices[ index2 ]; + coords[ index + 4 ] = vertices[ index2 + 1 ]; + coords[ index + 5 ] = vertices[ index2 + 2 ]; - objectMaterial = getObjectMaterial( object ); + } - if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); + } - useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + geometry.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - if ( object.customDepthMaterial ) { + } - material = object.customDepthMaterial; + } - } else if ( useSkinning ) { + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - } else if ( useMorphing ) { +}; - material = _depthMaterialMorph; +THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); +THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; - } else { +// File:src/extras/objects/ImmediateRenderObject.js - material = _depthMaterial; +/** + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.ImmediateRenderObject = function () { - if ( buffer instanceof THREE.BufferGeometry ) { + THREE.Object3D.call( this ); - _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); + this.render = function ( renderCallback ) {}; - } else { +}; - _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); +THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; - } +// File:src/extras/objects/MorphBlendMesh.js - } +/** + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.MorphBlendMesh = function( geometry, material ) { - // set matrices and render immediate objects + THREE.Mesh.call( this, geometry, material ); - renderList = scene.__webglObjectsImmediate; + this.animationsMap = {}; + this.animationsList = []; - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + // prepare default animation + // (all frames played together in 1 second) - webglObject = renderList[ j ]; - object = webglObject.object; + var numFrames = this.geometry.morphTargets.length; - if ( object.visible ) { + var name = "__default"; - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + var startFrame = 0; + var endFrame = numFrames - 1; - _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); + var fps = numFrames / 1; - } + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); - } +}; - // restore GL state +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); +THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); + var animation = { - }; + startFrame: start, + endFrame: end, - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use + length: end - start + 1, - function getObjectMaterial( object ) { + fps: fps, + duration: ( end - start ) / fps, - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; + lastFrame: 0, + currentFrame: 0, + + active: false, + + time: 0, + direction: 1, + weight: 1, + + directionBackwards: false, + mirroredLoop: false }; + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); + }; +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { -/** - * @author mikael emtinger / http://gomo.se/ - */ + var pattern = /([a-z]+)_?(\d+)/; -THREE.ShaderFlares = { + var firstAnimation, frameRanges = {}; - 'lensFlareVertexTexture': { + var geometry = this.geometry; - vertexShader: [ + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - "uniform lowp int renderType;", + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", + if ( chunks && chunks.length > 1 ) { - "uniform sampler2D occlusionMap;", + var name = chunks[ 1 ]; - "attribute vec2 position;", - "attribute vec2 uv;", + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; - "varying vec2 vUV;", - "varying float vVisibility;", + var range = frameRanges[ name ]; - "void main() {", + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; - "vUV = uv;", + if ( ! firstAnimation ) firstAnimation = name; - "vec2 pos = position;", + } - "if( renderType == 2 ) {", + } - "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", + for ( var name in frameRanges ) { - "vVisibility = visibility.r / 9.0;", - "vVisibility *= 1.0 - visibility.g / 9.0;", - "vVisibility *= visibility.b / 9.0;", - "vVisibility *= 1.0 - visibility.a / 9.0;", + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + } - "}", + this.firstAnimation = firstAnimation; - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", +}; - "}" +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - ].join( "\n" ), + var animation = this.animationsMap[ name ]; - fragmentShader: [ + if ( animation ) { - "uniform lowp int renderType;", + animation.direction = 1; + animation.directionBackwards = false; - "uniform sampler2D map;", - "uniform float opacity;", - "uniform vec3 color;", + } - "varying vec2 vUV;", - "varying float vVisibility;", +}; - "void main() {", +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - // pink square + var animation = this.animationsMap[ name ]; - "if( renderType == 0 ) {", + if ( animation ) { - "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + animation.direction = - 1; + animation.directionBackwards = true; - // restore + } - "} else if( renderType == 1 ) {", +}; - "gl_FragColor = texture2D( map, vUV );", +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { - // flare + var animation = this.animationsMap[ name ]; - "} else {", + if ( animation ) { - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * vVisibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; - "}", + } - "}" - ].join( "\n" ) +}; - }, +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + var animation = this.animationsMap[ name ]; - 'lensFlare': { + if ( animation ) { - vertexShader: [ + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; - "uniform lowp int renderType;", + } - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", +}; - "attribute vec2 position;", - "attribute vec2 uv;", +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { - "varying vec2 vUV;", + var animation = this.animationsMap[ name ]; - "void main() {", + if ( animation ) { - "vUV = uv;", + animation.weight = weight; - "vec2 pos = position;", + } - "if( renderType == 2 ) {", +}; - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { - "}", + var animation = this.animationsMap[ name ]; - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + if ( animation ) { - "}" + animation.time = time; - ].join( "\n" ), + } - fragmentShader: [ +}; - "precision mediump float;", +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { - "uniform lowp int renderType;", + var time = 0; - "uniform sampler2D map;", - "uniform sampler2D occlusionMap;", - "uniform float opacity;", - "uniform vec3 color;", + var animation = this.animationsMap[ name ]; - "varying vec2 vUV;", + if ( animation ) { - "void main() {", + time = animation.time; - // pink square + } - "if( renderType == 0 ) {", + return time; - "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", +}; - // restore +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { - "} else if( renderType == 1 ) {", + var duration = - 1; - "gl_FragColor = texture2D( map, vUV );", + var animation = this.animationsMap[ name ]; - // flare + if ( animation ) { - "} else {", + duration = animation.duration; - "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", - "visibility = ( 1.0 - visibility / 4.0 );", + } - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * visibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", + return duration; - "}", +}; - "}" +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { - ].join( "\n" ) + var animation = this.animationsMap[ name ]; - } + if ( animation ) { -}; + animation.time = 0; + animation.active = true; -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * - */ + } else { -THREE.ShaderSprite = { + THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); - 'sprite': { + } - vertexShader: [ +}; - "uniform int useScreenCoordinates;", - "uniform int sizeAttenuation;", - "uniform vec3 screenPosition;", - "uniform mat4 modelViewMatrix;", - "uniform mat4 projectionMatrix;", - "uniform float rotation;", - "uniform vec2 scale;", - "uniform vec2 alignment;", - "uniform vec2 uvOffset;", - "uniform vec2 uvScale;", - "uniform vec2 halfViewport;", +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { - "attribute vec2 position;", - "attribute vec2 uv;", + var animation = this.animationsMap[ name ]; - "varying vec2 vUV;", + if ( animation ) { - "void main() {", + animation.active = false; - "vUV = uvOffset + uv * uvScale;", + } - "vec2 alignedPosition = ( position + alignment ) * scale;", +}; - "vec2 rotatedPosition;", - "rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;", - "rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;", +THREE.MorphBlendMesh.prototype.update = function ( delta ) { - "vec4 finalPosition;", + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { - "if( useScreenCoordinates != 0 ) {", + var animation = this.animationsList[ i ]; - "finalPosition = vec4( screenPosition.xy + ( rotatedPosition / halfViewport ), screenPosition.z, 1.0 );", + if ( ! animation.active ) continue; - "} else {", + var frameTime = animation.duration / animation.length; - "finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );", - "finalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );", - "finalPosition = projectionMatrix * finalPosition;", + animation.time += animation.direction * delta; - "}", + if ( animation.mirroredLoop ) { - "gl_Position = finalPosition;", + if ( animation.time > animation.duration || animation.time < 0 ) { - "}" + animation.direction *= - 1; - ].join( "\n" ), + if ( animation.time > animation.duration ) { - fragmentShader: [ + animation.time = animation.duration; + animation.directionBackwards = true; - "uniform vec3 color;", - "uniform sampler2D map;", - "uniform float opacity;", + } - "uniform int fogType;", - "uniform vec3 fogColor;", - "uniform float fogDensity;", - "uniform float fogNear;", - "uniform float fogFar;", - "uniform float alphaTest;", + if ( animation.time < 0 ) { - "varying vec2 vUV;", + animation.time = 0; + animation.directionBackwards = false; - "void main() {", + } - "vec4 texture = texture2D( map, vUV );", + } - "if ( texture.a < alphaTest ) discard;", + } else { - "gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );", + animation.time = animation.time % animation.duration; - "if ( fogType > 0 ) {", + if ( animation.time < 0 ) animation.time += animation.duration; - "float depth = gl_FragCoord.z / gl_FragCoord.w;", - "float fogFactor = 0.0;", + } - "if ( fogType == 1 ) {", + var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; - "fogFactor = smoothstep( fogNear, fogFar, depth );", + if ( keyframe !== animation.currentFrame ) { - "} else {", + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; - "const float LOG2 = 1.442695;", - "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", - "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + this.morphTargetInfluences[ keyframe ] = 0; - "}", + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; - "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + } - "}", + var mix = ( animation.time % frameTime ) / frameTime; - "}" + if ( animation.directionBackwards ) mix = 1 - mix; - ].join( "\n" ) + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; } }; + diff --git a/gz3d/client/js/include/three.min.js b/gz3d/client/js/include/three.min.js index db4f8f5ccfae7af502d6c0c7e2877ae11ee3b233..85e55962cbbb97d43925c3b7fa903f850942daec 100644 --- a/gz3d/client/js/include/three.min.js +++ b/gz3d/client/js/include/three.min.js @@ -1,705 +1,835 @@ -// three.js - http://github.com/mrdoob/three.js -'use strict';var THREE={REVISION:"62"};self.console=self.console||{info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}};String.prototype.trim=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")};THREE.extend=function(a,b){if(Object.keys)for(var c=Object.keys(b),d=0,e=c.length;d<e;d++){var f=c[d];Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(b,f))}else for(f in c={}.hasOwnProperty,b)c.call(b,f)&&(a[f]=b[f]);return a}; -(function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c<b.length&&!self.requestAnimationFrame;++c)self.requestAnimationFrame=self[b[c]+"RequestAnimationFrame"],self.cancelAnimationFrame=self[b[c]+"CancelAnimationFrame"]||self[b[c]+"CancelRequestAnimationFrame"];void 0===self.requestAnimationFrame&&void 0!==self.setTimeout&&(self.requestAnimationFrame=function(b){var c=Date.now(),f=Math.max(0,16-(c-a)),h=self.setTimeout(function(){b(c+f)},f);a=c+f;return h});void 0===self.cancelAnimationFrame&&void 0!== -self.clearTimeout&&(self.cancelAnimationFrame=function(a){self.clearTimeout(a)})})();THREE.CullFaceNone=0;THREE.CullFaceBack=1;THREE.CullFaceFront=2;THREE.CullFaceFrontBack=3;THREE.FrontFaceDirectionCW=0;THREE.FrontFaceDirectionCCW=1;THREE.BasicShadowMap=0;THREE.PCFShadowMap=1;THREE.PCFSoftShadowMap=2;THREE.FrontSide=0;THREE.BackSide=1;THREE.DoubleSide=2;THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NoBlending=0; -THREE.NormalBlending=1;THREE.AdditiveBlending=2;THREE.SubtractiveBlending=3;THREE.MultiplyBlending=4;THREE.CustomBlending=5;THREE.AddEquation=100;THREE.SubtractEquation=101;THREE.ReverseSubtractEquation=102;THREE.ZeroFactor=200;THREE.OneFactor=201;THREE.SrcColorFactor=202;THREE.OneMinusSrcColorFactor=203;THREE.SrcAlphaFactor=204;THREE.OneMinusSrcAlphaFactor=205;THREE.DstAlphaFactor=206;THREE.OneMinusDstAlphaFactor=207;THREE.DstColorFactor=208;THREE.OneMinusDstColorFactor=209; -THREE.SrcAlphaSaturateFactor=210;THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.AddOperation=2;THREE.UVMapping=function(){};THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.RepeatWrapping=1E3;THREE.ClampToEdgeWrapping=1001;THREE.MirroredRepeatWrapping=1002;THREE.NearestFilter=1003;THREE.NearestMipMapNearestFilter=1004;THREE.NearestMipMapLinearFilter=1005; -THREE.LinearFilter=1006;THREE.LinearMipMapNearestFilter=1007;THREE.LinearMipMapLinearFilter=1008;THREE.UnsignedByteType=1009;THREE.ByteType=1010;THREE.ShortType=1011;THREE.UnsignedShortType=1012;THREE.IntType=1013;THREE.UnsignedIntType=1014;THREE.FloatType=1015;THREE.UnsignedShort4444Type=1016;THREE.UnsignedShort5551Type=1017;THREE.UnsignedShort565Type=1018;THREE.AlphaFormat=1019;THREE.RGBFormat=1020;THREE.RGBAFormat=1021;THREE.LuminanceFormat=1022;THREE.LuminanceAlphaFormat=1023; -THREE.RGB_S3TC_DXT1_Format=2001;THREE.RGBA_S3TC_DXT1_Format=2002;THREE.RGBA_S3TC_DXT3_Format=2003;THREE.RGBA_S3TC_DXT5_Format=2004;THREE.Color=function(a){void 0!==a&&this.set(a);return this}; +// threejs.org/license +'use strict';var THREE={REVISION:"71"};"object"===typeof module&&(module.exports=THREE);void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0<a?1:+a});THREE.log=function(){console.log.apply(console,arguments)};THREE.warn=function(){console.warn.apply(console,arguments)};THREE.error=function(){console.error.apply(console,arguments)};THREE.MOUSE={LEFT:0,MIDDLE:1,RIGHT:2};THREE.CullFaceNone=0;THREE.CullFaceBack=1;THREE.CullFaceFront=2;THREE.CullFaceFrontBack=3;THREE.FrontFaceDirectionCW=0; +THREE.FrontFaceDirectionCCW=1;THREE.BasicShadowMap=0;THREE.PCFShadowMap=1;THREE.PCFSoftShadowMap=2;THREE.FrontSide=0;THREE.BackSide=1;THREE.DoubleSide=2;THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NoBlending=0;THREE.NormalBlending=1;THREE.AdditiveBlending=2;THREE.SubtractiveBlending=3;THREE.MultiplyBlending=4;THREE.CustomBlending=5;THREE.AddEquation=100;THREE.SubtractEquation=101;THREE.ReverseSubtractEquation=102; +THREE.MinEquation=103;THREE.MaxEquation=104;THREE.ZeroFactor=200;THREE.OneFactor=201;THREE.SrcColorFactor=202;THREE.OneMinusSrcColorFactor=203;THREE.SrcAlphaFactor=204;THREE.OneMinusSrcAlphaFactor=205;THREE.DstAlphaFactor=206;THREE.OneMinusDstAlphaFactor=207;THREE.DstColorFactor=208;THREE.OneMinusDstColorFactor=209;THREE.SrcAlphaSaturateFactor=210;THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.AddOperation=2;THREE.UVMapping=300;THREE.CubeReflectionMapping=301;THREE.CubeRefractionMapping=302; +THREE.EquirectangularReflectionMapping=303;THREE.EquirectangularRefractionMapping=304;THREE.SphericalReflectionMapping=305;THREE.RepeatWrapping=1E3;THREE.ClampToEdgeWrapping=1001;THREE.MirroredRepeatWrapping=1002;THREE.NearestFilter=1003;THREE.NearestMipMapNearestFilter=1004;THREE.NearestMipMapLinearFilter=1005;THREE.LinearFilter=1006;THREE.LinearMipMapNearestFilter=1007;THREE.LinearMipMapLinearFilter=1008;THREE.UnsignedByteType=1009;THREE.ByteType=1010;THREE.ShortType=1011; +THREE.UnsignedShortType=1012;THREE.IntType=1013;THREE.UnsignedIntType=1014;THREE.FloatType=1015;THREE.HalfFloatType=1025;THREE.UnsignedShort4444Type=1016;THREE.UnsignedShort5551Type=1017;THREE.UnsignedShort565Type=1018;THREE.AlphaFormat=1019;THREE.RGBFormat=1020;THREE.RGBAFormat=1021;THREE.LuminanceFormat=1022;THREE.LuminanceAlphaFormat=1023;THREE.RGBEFormat=THREE.RGBAFormat;THREE.RGB_S3TC_DXT1_Format=2001;THREE.RGBA_S3TC_DXT1_Format=2002;THREE.RGBA_S3TC_DXT3_Format=2003; +THREE.RGBA_S3TC_DXT5_Format=2004;THREE.RGB_PVRTC_4BPPV1_Format=2100;THREE.RGB_PVRTC_2BPPV1_Format=2101;THREE.RGBA_PVRTC_4BPPV1_Format=2102;THREE.RGBA_PVRTC_2BPPV1_Format=2103; +THREE.Projector=function(){THREE.error("THREE.Projector has been moved to /examples/js/renderers/Projector.js.");this.projectVector=function(a,b){THREE.warn("THREE.Projector: .projectVector() is now vector.project().");a.project(b)};this.unprojectVector=function(a,b){THREE.warn("THREE.Projector: .unprojectVector() is now vector.unproject().");a.unproject(b)};this.pickingRay=function(a,b){THREE.error("THREE.Projector: .pickingRay() is now raycaster.setFromCamera().")}}; +THREE.CanvasRenderer=function(){THREE.error("THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js");this.domElement=document.createElement("canvas");this.clear=function(){};this.render=function(){};this.setClearColor=function(){};this.setSize=function(){}};THREE.Color=function(a){return 3===arguments.length?this.setRGB(arguments[0],arguments[1],arguments[2]):this.set(a)}; THREE.Color.prototype={constructor:THREE.Color,r:1,g:1,b:1,set:function(a){a instanceof THREE.Color?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1<c&&(c-=1);return c<1/6?a+6*(b-a)* -c:0.5>c?b:c<2/3?a+6*(b-a)*(2/3-c):a},b=0.5>=c?c*(1+b):c+b-c*b,c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= +c:.5>c?b:c<2/3?a+6*(b-a)*(2/3-c):a};b=.5>=c?c*(1+b):c+b-c*b;c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r;this.g= -a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<< -8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(){var a={h:0,s:0,l:0};return function(){var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),h,g=(f+e)/2;if(f===e)f=h=0;else{var i=e-f,f=0.5>=g?i/(e+f):i/(2-e-f);switch(e){case b:h=(c-d)/i+(c<d?6:0);break;case c:h=(d-b)/i+2;break;case d:h=(b-c)/i+4}h/=6}a.h=h;a.s=f;a.l=g;return a}}(),getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"}, -offsetHSL:function(a,b,c){var d=this.getHSL();d.h+=a;d.s+=b;d.l+=c;this.setHSL(d.h,d.s,d.l);return this},add:function(a){this.r+=a.r;this.g+=a.g;this.b+=a.b;return this},addColors:function(a,b){this.r=a.r+b.r;this.g=a.g+b.g;this.b=a.b+b.b;return this},addScalar:function(a){this.r+=a;this.g+=a;this.b+=a;return this},multiply:function(a){this.r*=a.r;this.g*=a.g;this.b*=a.b;return this},multiplyScalar:function(a){this.r*=a;this.g*=a;this.b*=a;return this},lerp:function(a,b){this.r+=(a.r-this.r)*b;this.g+= -(a.g-this.g)*b;this.b+=(a.b-this.b)*b;return this},equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a){this.r=a[0];this.g=a[1];this.b=a[2];return this},toArray:function(){return[this.r,this.g,this.b]},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}}; +a.g;this.b=a.b;return this},copyGammaToLinear:function(a,b){void 0===b&&(b=2);this.r=Math.pow(a.r,b);this.g=Math.pow(a.g,b);this.b=Math.pow(a.b,b);return this},copyLinearToGamma:function(a,b){void 0===b&&(b=2);var c=0<b?1/b:1;this.r=Math.pow(a.r,c);this.g=Math.pow(a.g,c);this.b=Math.pow(a.b,c);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b= +Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f,f=.5>=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(c<d?6:0);break;case c:g=(d-b)/k+2;break;case d:g=(b-c)/k+4}g/=6}a.h=g;a.s=f;a.l=h;return a},getStyle:function(){return"rgb("+ +(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},offsetHSL:function(a,b,c){var d=this.getHSL();d.h+=a;d.s+=b;d.l+=c;this.setHSL(d.h,d.s,d.l);return this},add:function(a){this.r+=a.r;this.g+=a.g;this.b+=a.b;return this},addColors:function(a,b){this.r=a.r+b.r;this.g=a.g+b.g;this.b=a.b+b.b;return this},addScalar:function(a){this.r+=a;this.g+=a;this.b+=a;return this},multiply:function(a){this.r*=a.r;this.g*=a.g;this.b*=a.b;return this},multiplyScalar:function(a){this.r*=a;this.g*=a;this.b*=a; +return this},lerp:function(a,b){this.r+=(a.r-this.r)*b;this.g+=(a.g-this.g)*b;this.b+=(a.b-this.b)*b;return this},equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a){this.r=a[0];this.g=a[1];this.b=a[2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.r;a[b+1]=this.g;a[b+2]=this.b;return a},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}}; THREE.ColorKeywords={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643, darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055, grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184, lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130, palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888, tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};THREE.Quaternion=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._w=void 0!==d?d:1}; -THREE.Quaternion.prototype={constructor:THREE.Quaternion,_x:0,_y:0,_z:0,_w:0,_euler:void 0,_updateEuler:function(){void 0!==this._euler&&this._euler.setFromQuaternion(this,void 0,!1)},get x(){return this._x},set x(a){this._x=a;this._updateEuler()},get y(){return this._y},set y(a){this._y=a;this._updateEuler()},get z(){return this._z},set z(a){this._z=a;this._updateEuler()},get w(){return this._w},set w(a){this._w=a;this._updateEuler()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d; -this._updateEuler();return this},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._w=a._w;this._updateEuler();return this},setFromEuler:function(a,b){if(!1===a instanceof THREE.Euler)throw Error("ERROR: Quaternion's .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");var c=Math.cos(a._x/2),d=Math.cos(a._y/2),e=Math.cos(a._z/2),f=Math.sin(a._x/2),h=Math.sin(a._y/2),g=Math.sin(a._z/2);"XYZ"===a.order?(this._x=f*d*e+c*h*g,this._y=c*h* -e-f*d*g,this._z=c*d*g+f*h*e,this._w=c*d*e-f*h*g):"YXZ"===a.order?(this._x=f*d*e+c*h*g,this._y=c*h*e-f*d*g,this._z=c*d*g-f*h*e,this._w=c*d*e+f*h*g):"ZXY"===a.order?(this._x=f*d*e-c*h*g,this._y=c*h*e+f*d*g,this._z=c*d*g+f*h*e,this._w=c*d*e-f*h*g):"ZYX"===a.order?(this._x=f*d*e-c*h*g,this._y=c*h*e+f*d*g,this._z=c*d*g-f*h*e,this._w=c*d*e+f*h*g):"YZX"===a.order?(this._x=f*d*e+c*h*g,this._y=c*h*e+f*d*g,this._z=c*d*g-f*h*e,this._w=c*d*e-f*h*g):"XZY"===a.order&&(this._x=f*d*e-c*h*g,this._y=c*h*e-f*d*g,this._z= -c*d*g+f*h*e,this._w=c*d*e+f*h*g);!1!==b&&this._updateEuler();return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);this._x=a.x*d;this._y=a.y*d;this._z=a.z*d;this._w=Math.cos(c);this._updateEuler();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0],a=b[4],d=b[8],e=b[1],f=b[5],h=b[9],g=b[2],i=b[6],b=b[10],k=c+f+b;0<k?(c=0.5/Math.sqrt(k+1),this._w=0.25/c,this._x=(i-h)*c,this._y=(d-g)*c,this._z=(e-a)*c):c>f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(i-h)/c,this._x=0.25*c, -this._y=(a+e)/c,this._z=(d+g)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-g)/c,this._x=(a+e)/c,this._y=0.25*c,this._z=(h+i)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+g)/c,this._y=(h+i)/c,this._z=0.25*c);this._updateEuler();return this},inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*=-1;this._y*=-1;this._z*=-1;this._updateEuler();return this},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x* -this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);return this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f= -a._w,h=b._x,g=b._y,i=b._z,k=b._w;this._x=c*k+f*h+d*i-e*g;this._y=d*k+f*g+e*h-c*i;this._z=e*k+f*i+c*g-d*h;this._w=f*k-c*h-d*g-e*i;this._updateEuler();return this},multiplyVector3:function(a){console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)},slerp:function(a,b){var c=this._x,d=this._y,e=this._z,f=this._w,h=f*a._w+c*a._x+d*a._y+e*a._z;0>h?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z= --a._z,h=-h):this.copy(a);if(1<=h)return this._w=f,this._x=c,this._y=d,this._z=e,this;var g=Math.acos(h),i=Math.sqrt(1-h*h);if(0.001>Math.abs(i))return this._w=0.5*(f+this._w),this._x=0.5*(c+this._x),this._y=0.5*(d+this._y),this._z=0.5*(e+this._z),this;h=Math.sin((1-b)*g)/i;g=Math.sin(b*g)/i;this._w=f*h+this._w*g;this._x=c*h+this._x*g;this._y=d*h+this._y*g;this._z=e*h+this._z*g;this._updateEuler();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w}, -fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];this._w=a[3];this._updateEuler();return this},toArray:function(){return[this._x,this._y,this._z,this._w]},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; +THREE.Quaternion.prototype={constructor:THREE.Quaternion,_x:0,_y:0,_z:0,_w:0,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get w(){return this._w},set w(a){this._w=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z; +this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!1===a instanceof THREE.Euler)throw Error("THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var c=Math.cos(a._x/2),d=Math.cos(a._y/2),e=Math.cos(a._z/2),f=Math.sin(a._x/2),g=Math.sin(a._y/2),h=Math.sin(a._z/2);"XYZ"===a.order?(this._x=f*d*e+c*g*h,this._y=c*g*e-f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e-f*g*h):"YXZ"===a.order?(this._x=f*d*e+c*g*h,this._y=c*g*e-f*d*h,this._z= +c*d*h-f*g*e,this._w=c*d*e+f*g*h):"ZXY"===a.order?(this._x=f*d*e-c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e-f*g*h):"ZYX"===a.order?(this._x=f*d*e-c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h-f*g*e,this._w=c*d*e+f*g*h):"YZX"===a.order?(this._x=f*d*e+c*g*h,this._y=c*g*e+f*d*h,this._z=c*d*h-f*g*e,this._w=c*d*e-f*g*h):"XZY"===a.order&&(this._x=f*d*e-c*g*h,this._y=c*g*e-f*d*h,this._z=c*d*h+f*g*e,this._w=c*d*e+f*g*h);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a, +b){var c=b/2,d=Math.sin(c);this._x=a.x*d;this._y=a.y*d;this._z=a.z*d;this._w=Math.cos(c);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],k=b[6],b=b[10],l=c+f+b;0<l?(c=.5/Math.sqrt(l+1),this._w=.25/c,this._x=(k-g)*c,this._y=(d-h)*c,this._z=(e-a)*c):c>f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y= +.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;this.normalize();return this}}(),inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*= +-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this}, +multiply:function(a,b){return void 0!==b?(THREE.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,k=b._z,l=b._w;this._x=c*l+f*g+d*k-e*h;this._y=d*l+f*h+e*g-c*k;this._z=e*l+f*k+c*h-d*g;this._w=f*l-c*g-d*h-e*k;this.onChangeCallback();return this},multiplyVector3:function(a){THREE.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."); +return a.applyQuaternion(this)},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),k=Math.sqrt(1-g*g);if(.001>Math.abs(k))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;g=Math.sin((1-b)*h)/k;h= +Math.sin(b*h)/k;this._w=f*g+this._w*h;this._x=c*g+this._x*h;this._y=d*g+this._y*h;this._z=e*g+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback= +a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, -b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-= -a.y;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y); -return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/ -b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a){this.x=a[0];this.y=a[1];return this},toArray:function(){return[this.x,this.y]},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; +b){if(void 0!==b)return THREE.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},sub:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.x<a.x&&(this.x=a.x); +this.y<a.y&&(this.y=a.y);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x= +Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))}, +distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0=== +a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];return this},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ -a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), -this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x* -b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements,e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]); -this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,h=a.z,a=a.w,g=a*b+f*d-h*c,i=a*c+h*b-e*d,k=a*d+e*c-f*b,b=-e*b-f*c-h*d;this.x=g*a+b*-e+i*-h-k*-f;this.y=i*a+b*-f+k*-e-g*-h;this.z=k*a+b*-h+g*-f-i*-e;return this},transformDirection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]* -b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);this.z<a.z&&(this.z=a.z);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y< -a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())}, -setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c= -a.x,d=a.y,e=a.z,f=b.x,h=b.y,g=b.z;this.x=d*g-e*h;this.y=e*f-c*g;this.z=c*h-d*f;return this},angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(){console.error("REMOVED: Vector3's setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code.")}, -setEulerFromQuaternion:function(){console.error("REMOVED: Vector3's setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code.")},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},getScaleFromMatrix:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length(); -this.x=b;this.y=c;this.z=a;return this},getColumnFromMatrix:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a){this.x=a[0];this.y=a[1];this.z=a[2];return this},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}}; -THREE.extend(THREE.Vector3.prototype,{applyEuler:function(){var a=new THREE.Quaternion;return function(b){!1===b instanceof THREE.Euler&&console.error("ERROR: Vector3's .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a=new THREE.Quaternion;return function(b,c){this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),projectOnVector:function(){var a=new THREE.Vector3; -return function(b){a.copy(b).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b).multiplyScalar(2);return this.subVectors(a,this)}}()});THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*= +a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a;return function(b){!1===b instanceof THREE.Euler&&THREE.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b, +c));return this}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]* +c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,l=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-l*-f;this.y=k*a+b*-f+l*-e-h*-g;this.z=l*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(), +unproject:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*= +a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y=a.y);this.z<a.z&&(this.z=a.z);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3, +b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y): +Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())}, +setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},cross:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y= +e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this},projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0=== +a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){THREE.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")}, +setEulerFromQuaternion:function(a,b){THREE.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")},getPositionFromMatrix:function(a){THREE.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){THREE.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a, +b){THREE.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a,b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},setFromMatrixScale:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length();a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a; +return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z= +a.array[b+2];return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x; -case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this}, -addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this}, -applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b, -this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],h=a[1],g=a[5],i=a[9];c=a[2];b=a[6];var k=a[10];if(0.01>Math.abs(d-h)&&0.01>Math.abs(f-c)&&0.01>Math.abs(i-b)){if(0.1>Math.abs(d+h)&&0.1>Math.abs(f+c)&&0.1>Math.abs(i+b)&&0.1>Math.abs(e+g+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;g=(g+1)/2;k=(k+1)/2;d=(d+h)/4;f=(f+c)/4;i=(i+b)/4;e>g&&e>k?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):g>k?0.01>g? -(b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(g),b=d/c,d=i/c):0.01>k?(c=b=0.707106781,d=0):(d=Math.sqrt(k),b=f/d,c=i/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-i)*(b-i)+(f-c)*(f-c)+(h-d)*(h-d));0.001>Math.abs(a)&&(a=1);this.x=(b-i)/a;this.y=(f-c)/a;this.z=(h-d)/a;this.w=Math.acos((e+g+k-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.x<a.x&&(this.x=a.x);this.y<a.y&&(this.y= -a.y);this.z<a.z&&(this.z=a.z);this.w<a.w&&(this.w=a.w);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);this.w<a.w?this.w=a.w:this.w>b.w&&(this.w=b.w);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x* -this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&& -a.w===this.w},fromArray:function(a){this.x=a[0];this.y=a[1];this.z=a[2];this.w=a[3];return this},toArray:function(){return[this.x,this.y,this.z,this.w]},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; -THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,_quaternion:void 0,_updateQuaternion:function(){void 0!==this._quaternion&&this._quaternion.setFromEuler(this,!1)},get x(){return this._x},set x(a){this._x=a;this._updateQuaternion()},get y(){return this._y},set y(a){this._y=a;this._updateQuaternion()},get z(){return this._z},set z(a){this._z=a;this._updateQuaternion()},get order(){return this._order},set order(a){this._order=a;this._updateQuaternion()}, -set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this._updateQuaternion();return this},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this._updateQuaternion();return this},setFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements,e=d[0],f=d[4],h=d[8],g=d[1],i=d[5],k=d[9],m=d[2],l=d[6],d=d[10],b=b||this._order;"XYZ"===b?(this._y=Math.asin(c(h)),0.99999>Math.abs(h)?(this._x=Math.atan2(-k,d),this._z= -Math.atan2(-f,e)):(this._x=Math.atan2(l,i),this._z=0)):"YXZ"===b?(this._x=Math.asin(-c(k)),0.99999>Math.abs(k)?(this._y=Math.atan2(h,d),this._z=Math.atan2(g,i)):(this._y=Math.atan2(-m,e),this._z=0)):"ZXY"===b?(this._x=Math.asin(c(l)),0.99999>Math.abs(l)?(this._y=Math.atan2(-m,d),this._z=Math.atan2(-f,i)):(this._y=0,this._z=Math.atan2(g,e))):"ZYX"===b?(this._y=Math.asin(-c(m)),0.99999>Math.abs(m)?(this._x=Math.atan2(l,d),this._z=Math.atan2(g,e)):(this._x=0,this._z=Math.atan2(-f,i))):"YZX"===b?(this._z= -Math.asin(c(g)),0.99999>Math.abs(g)?(this._x=Math.atan2(-k,i),this._y=Math.atan2(-m,e)):(this._x=0,this._y=Math.atan2(h,d))):"XZY"===b?(this._z=Math.asin(-c(f)),0.99999>Math.abs(f)?(this._x=Math.atan2(l,i),this._y=Math.atan2(h,e)):(this._x=Math.atan2(-k,d),this._y=0)):console.warn("WARNING: Euler.setFromRotationMatrix() given unsupported order: "+b);this._order=b;this._updateQuaternion();return this},setFromQuaternion:function(a,b,c){function d(a){return Math.min(Math.max(a,-1),1)}var e=a.x*a.x,f= -a.y*a.y,h=a.z*a.z,g=a.w*a.w,b=b||this._order;"XYZ"===b?(this._x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-e-f+h),this._y=Math.asin(d(2*(a.x*a.z+a.y*a.w))),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),g+e-f-h)):"YXZ"===b?(this._x=Math.asin(d(2*(a.x*a.w-a.y*a.z))),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),g-e-f+h),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-e+f-h)):"ZXY"===b?(this._x=Math.asin(d(2*(a.x*a.w+a.y*a.z))),this._y=Math.atan2(2*(a.y*a.w-a.z*a.x),g-e-f+h),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-e+f-h)):"ZYX"=== -b?(this._x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-e-f+h),this._y=Math.asin(d(2*(a.y*a.w-a.x*a.z))),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),g+e-f-h)):"YZX"===b?(this._x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-e+f-h),this._y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+e-f-h),this._z=Math.asin(d(2*(a.x*a.y+a.z*a.w)))):"XZY"===b?(this._x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-e+f-h),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),g+e-f-h),this._z=Math.asin(d(2*(a.z*a.w-a.x*a.y)))):console.warn("WARNING: Euler.setFromQuaternion() given unsupported order: "+ -b);this._order=b;!1!==c&&this._updateQuaternion();return this},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this._updateQuaternion();return this},toArray:function(){return[this._x,this._y,this._z,this._order]},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},clone:function(){return new THREE.Euler(this._x, -this._y,this._z,this._order)}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; -THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(0.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, +case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a, +b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},sub:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*= +a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4> +b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var l=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+l-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;l=(l+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>l?.01>e?(b=0,d=c=.707106781):(b= +Math.sqrt(e),c=d/b,d=f/b):h>l?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h),b=d/c,d=k/c):.01>l?(c=b=.707106781,d=0):(d=Math.sqrt(l),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+l-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.x<a.x&& +(this.x=a.x);this.y<a.y&&(this.y=a.y);this.z<a.z&&(this.z=a.z);this.w<a.w&&(this.w=a.w);return this},clamp:function(a,b){this.x<a.x?this.x=a.x:this.x>b.x&&(this.x=b.x);this.y<a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.z<a.z?this.z=a.z:this.z>b.z&&(this.z=b.z);this.w<a.w?this.w=a.w:this.w>b.w&&(this.w=b.w);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),floor:function(){this.x= +Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y); +this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+ +Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w}, +fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];this.w=a.array[b+3];return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}}; +THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; +THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order},set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},copy:function(a){this._x= +a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=THREE.Math.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],l=e[9],p=e[2],q=e[6],e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-l,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(q,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(l,-1,1)),.99999>Math.abs(l)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h, +k)):(this._y=Math.atan2(-p,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(q,-1,1)),.99999>Math.abs(q)?(this._y=Math.atan2(-p,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(p,-1,1)),.99999>Math.abs(p)?(this._x=Math.atan2(q,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-l,k),this._y=Math.atan2(-p,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z= +Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(q,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-l,e),this._y=0)):THREE.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeRotationFromQuaternion(b);this.setFromRotationMatrix(a,c,d);return this}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z, +b||this._order)},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a? +a.set(this._x,this._y,this._z):new THREE.Vector3(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Euler(this._x,this._y,this._z,this._order)}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; -THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0<a.length){var b=a[0];this.min.copy(b);this.max.copy(b);for(var c=1,d=a.length;c<d;c++)b=a[c],b.x<this.min.x?this.min.x=b.x:b.x>this.max.x&&(this.max.x=b.x),b.y<this.min.y?this.min.y=b.y:b.y>this.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(0.5); -this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y},center:function(a){return(a||new THREE.Vector2).addVectors(this.min,this.max).multiplyScalar(0.5)},size:function(a){return(a||new THREE.Vector2).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a); -this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a){return new THREE.Vector2((a.x-this.min.x)/(this.max.x-this.min.x), -(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max); -return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; -THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},addPoint:function(a){a.x<this.min.x?this.min.x=a.x:a.x>this.max.x&&(this.max.x=a.x);a.y<this.min.y?this.min.y=a.y:a.y>this.max.y&&(this.max.y=a.y);a.z<this.min.z?this.min.z=a.z:a.z>this.max.z&&(this.max.z=a.z)},setFromPoints:function(a){if(0<a.length){var b=a[0];this.min.copy(b);this.max.copy(b);for(var b=1,c=a.length;b<c;b++)this.addPoint(a[b])}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a= -new THREE.Vector3;return function(b,c){var d=a.copy(c).multiplyScalar(0.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),setFromObject:function(){var a=new THREE.Vector3;return function(b){var c=this;b.updateMatrixWorld(!0);this.makeEmpty();b.traverse(function(b){if(void 0!==b.geometry&&void 0!==b.geometry.vertices)for(var e=b.geometry.vertices,f=0,h=e.length;f<h;f++)a.copy(e[f]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a)});return this}}(),copy:function(a){this.min.copy(a.min); -this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z},center:function(a){return(a||new THREE.Vector3).addVectors(this.min,this.max).multiplyScalar(0.5)},size:function(a){return(a||new THREE.Vector3).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a); -this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y||a.z<this.min.z||a.z>this.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a){return new THREE.Vector3((a.x-this.min.x)/(this.max.x-this.min.x), -(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y||a.max.z<this.min.z||a.min.z>this.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= -new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=0.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y, +THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x= +this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y},center:function(a){return(a||new THREE.Vector2).addVectors(this.min,this.max).multiplyScalar(.5)},size:function(a){return(a||new THREE.Vector2).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a); +this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector2).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y> +this.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&& +a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; +THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new THREE.Vector3;return function(b,c){var d=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),setFromObject:function(){var a=new THREE.Vector3;return function(b){var c=this;b.updateMatrixWorld(!0); +this.makeEmpty();b.traverse(function(b){var e=b.geometry;if(void 0!==e)if(e instanceof THREE.Geometry)for(var f=e.vertices,e=0,g=f.length;e<g;e++)a.copy(f[e]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a);else if(e instanceof THREE.BufferGeometry&&void 0!==e.attributes.position)for(f=e.attributes.position.array,e=0,g=f.length;e<g;e+=3)a.set(f[e],f[e+1],f[e+2]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a)});return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this}, +makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z},center:function(a){return(a||new THREE.Vector3).addVectors(this.min,this.max).multiplyScalar(.5)},size:function(a){return(a||new THREE.Vector3).subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a); +this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y||a.z<this.min.z||a.z>this.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){return(b||new THREE.Vector3).set((a.x-this.min.x)/(this.max.x- +this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y||a.max.z<this.min.z||a.min.z>this.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= +new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y, this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a); -this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(a,b,c,d,e,f,h,g,i){this.elements=new Float32Array(9);this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,h||0,g||0,void 0!==i?i:1)}; -THREE.Matrix3.prototype={constructor:THREE.Matrix3,set:function(a,b,c,d,e,f,h,g,i){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=f;k[2]=h;k[5]=g;k[8]=i;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)}, -multiplyVector3Array:function(){var a=new THREE.Vector3;return function(b){for(var c=0,d=b.length;c<d;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix3(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*=a;b[6]*=a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],h=a[5],g=a[6],i=a[7],a=a[8];return b*f*a-b*h*i-c*e*a+c*h*g+d*e*i-d*f*g},getInverse:function(a, -b){var c=a.elements,d=this.elements;d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4];c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/ -c);return this},transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this},clone:function(){var a=this.elements;return new THREE.Matrix3(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8])}};THREE.Matrix4=function(a,b,c,d,e,f,h,g,i,k,m,l,p,s,t,n){var r=this.elements=new Float32Array(16);r[0]=void 0!==a?a:1;r[4]=b||0;r[8]=c||0;r[12]=d||0;r[1]=e||0;r[5]=void 0!==f?f:1;r[9]=h||0;r[13]=g||0;r[2]=i||0;r[6]=k||0;r[10]=void 0!==m?m:1;r[14]=l||0;r[3]=p||0;r[7]=s||0;r[11]=t||0;r[15]=void 0!==n?n:1}; -THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,h,g,i,k,m,l,p,s,t,n){var r=this.elements;r[0]=a;r[4]=b;r[8]=c;r[12]=d;r[1]=e;r[5]=f;r[9]=h;r[13]=g;r[2]=i;r[6]=k;r[10]=m;r[14]=l;r[3]=p;r[7]=s;r[11]=t;r[15]=n;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){this.elements.set(a.elements);return this},extractPosition:function(a){console.warn("DEPRECATED: Matrix4's .extractPosition() has been renamed to .copyPosition()."); -return this.copyPosition(a)},copyPosition:function(a){var b=this.elements,a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractRotation:function(){var a=new THREE.Vector3;return function(b){var c=this.elements,b=b.elements,d=1/a.set(b[0],b[1],b[2]).length(),e=1/a.set(b[4],b[5],b[6]).length(),f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),makeRotationFromEuler:function(a){!1=== -a instanceof THREE.Euler&&console.error("ERROR: Matrix's .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),h=Math.cos(d),d=Math.sin(d),g=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){var a=f*g,i=f*e,k=c*g,m=c*e;b[0]=h*g;b[4]=-h*e;b[8]=d;b[1]=i+k*d;b[5]=a-m*d;b[9]=-c*h;b[2]=m-a*d;b[6]=k+i*d;b[10]=f*h}else"YXZ"===a.order?(a=h*g,i=h*e,k=d*g,m=d*e,b[0]=a+m*c,b[4]=k*c-i,b[8]= -f*d,b[1]=f*e,b[5]=f*g,b[9]=-c,b[2]=i*c-k,b[6]=m+a*c,b[10]=f*h):"ZXY"===a.order?(a=h*g,i=h*e,k=d*g,m=d*e,b[0]=a-m*c,b[4]=-f*e,b[8]=k+i*c,b[1]=i+k*c,b[5]=f*g,b[9]=m-a*c,b[2]=-f*d,b[6]=c,b[10]=f*h):"ZYX"===a.order?(a=f*g,i=f*e,k=c*g,m=c*e,b[0]=h*g,b[4]=k*d-i,b[8]=a*d+m,b[1]=h*e,b[5]=m*d+a,b[9]=i*d-k,b[2]=-d,b[6]=c*h,b[10]=f*h):"YZX"===a.order?(a=f*h,i=f*d,k=c*h,m=c*d,b[0]=h*g,b[4]=m-a*e,b[8]=k*e+i,b[1]=e,b[5]=f*g,b[9]=-c*g,b[2]=-d*g,b[6]=i*e+k,b[10]=a-m*e):"XZY"===a.order&&(a=f*h,i=f*d,k=c*h,m=c*d,b[0]= -h*g,b[4]=-e,b[8]=d*g,b[1]=a*e+m,b[5]=f*g,b[9]=i*e-k,b[2]=k*e-i,b[6]=c*g,b[10]=m*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){console.warn("DEPRECATED: Matrix4's .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.");return this.makeRotationFromQuaternion(a)},makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,h=c+c,g=d+d,i=e+e,a=c*h,k=c*g,c= -c*i,m=d*g,d=d*i,e=e*i,h=f*h,g=f*g,f=f*i;b[0]=1-(m+e);b[4]=k-f;b[8]=c+g;b[1]=k+f;b[5]=1-(a+e);b[9]=d-h;b[2]=c-g;b[6]=d+h;b[10]=1-(a+m);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f){var h=this.elements;c.subVectors(d,e).normalize();0===c.length()&&(c.z=1);a.crossVectors(f,c).normalize();0===a.length()&&(c.x+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);h[0]=a.x; -h[4]=b.x;h[8]=c.x;h[1]=a.y;h[5]=b.y;h[9]=c.y;h[2]=a.z;h[6]=b.z;h[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Matrix4's .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],h=c[4],g=c[8],i=c[12],k=c[1],m=c[5],l=c[9],p=c[13],s=c[2],t=c[6],n=c[10],r=c[14],q=c[3],u=c[7],w=c[11],c=c[15], -z=d[0],B=d[4],D=d[8],x=d[12],F=d[1],A=d[5],O=d[9],C=d[13],E=d[2],I=d[6],y=d[10],v=d[14],G=d[3],R=d[7],J=d[11],d=d[15];e[0]=f*z+h*F+g*E+i*G;e[4]=f*B+h*A+g*I+i*R;e[8]=f*D+h*O+g*y+i*J;e[12]=f*x+h*C+g*v+i*d;e[1]=k*z+m*F+l*E+p*G;e[5]=k*B+m*A+l*I+p*R;e[9]=k*D+m*O+l*y+p*J;e[13]=k*x+m*C+l*v+p*d;e[2]=s*z+t*F+n*E+r*G;e[6]=s*B+t*A+n*I+r*R;e[10]=s*D+t*O+n*y+r*J;e[14]=s*x+t*C+n*v+r*d;e[3]=q*z+u*F+w*E+c*G;e[7]=q*B+u*A+w*I+c*R;e[11]=q*D+u*O+w*y+c*J;e[15]=q*x+u*C+w*v+c*d;return this},multiplyToArray:function(a,b, -c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix4's .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead."); -return a.applyProjection(this)},multiplyVector4:function(a){console.warn("DEPRECATED: Matrix4's .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(){var a=new THREE.Vector3;return function(b){for(var c=0,d=b.length;c<d;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyProjection(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),rotateAxis:function(a){console.warn("DEPRECATED: Matrix4's .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."); -a.transformDirection(this)},crossVector:function(a){console.warn("DEPRECATED: Matrix4's .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],h=a[5],g=a[9],i=a[13],k=a[2],m=a[6],l=a[10],p=a[14];return a[3]*(+e*g*m-d*i*m-e*h*l+c*i*l+d*h*p-c*g*p)+a[7]*(+b*g*p-b*i*l+e*f*l-d*f*p+d*i*k-e*g*k)+a[11]*(+b*i*m-b*h*p-e*f*m+c*f*p+e*h*k-c*i*k)+a[15]*(-d*h*k-b*g*m+b*h*l+d*f*m-c*f* -l+c*g*k)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15];return a},flattenToArrayOffset:function(a,b){var c=this.elements; -a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a=new THREE.Vector3;return function(){console.warn("DEPRECATED: Matrix4's .getPosition() has been removed. Use Vector3.getPositionFromMatrix( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements; -b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=this.elements,d=a.elements,e=d[0],f=d[4],h=d[8],g=d[12],i=d[1],k=d[5],m=d[9],l=d[13],p=d[2],s=d[6],t=d[10],n=d[14],r=d[3],q=d[7],u=d[11],d=d[15];c[0]=m*n*q-l*t*q+l*s*u-k*n*u-m*s*d+k*t*d;c[4]=g*t*q-h*n*q-g*s*u+f*n*u+h*s*d-f*t*d;c[8]=h*l*q-g*m*q+g*k*u-f*l*u-h*k*d+f*m*d;c[12]=g*m*s-h*l*s-g*k*t+f*l*t+h*k*n-f*m*n;c[1]=l*t*r-m*n*r-l*p*u+i*n*u+m*p*d-i*t*d;c[5]=h*n*r-g*t*r+g*p*u-e*n*u-h*p*d+e*t*d;c[9]=g*m*r-h*l*r-g*i*u+e*l*u+h*i*d- -e*m*d;c[13]=h*l*p-g*m*p+g*i*t-e*l*t-h*i*n+e*m*n;c[2]=k*n*r-l*s*r+l*p*q-i*n*q-k*p*d+i*s*d;c[6]=g*s*r-f*n*r-g*p*q+e*n*q+f*p*d-e*s*d;c[10]=f*l*r-g*k*r+g*i*q-e*l*q-f*i*d+e*k*d;c[14]=g*k*p-f*l*p-g*i*s+e*l*s+f*i*n-e*k*n;c[3]=m*s*r-k*t*r-m*p*q+i*t*q+k*p*u-i*s*u;c[7]=f*t*r-h*s*r+h*p*q-e*t*q-f*p*u+e*s*u;c[11]=h*k*r-f*m*r-h*i*q+e*m*q+f*i*u-e*k*u;c[15]=f*m*p-h*k*p+h*i*s-e*m*s-f*i*t+e*k*t;c=e*c[0]+i*c[4]+p*c[8]+r*c[12];if(0==c){if(b)throw Error("Matrix4.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix4.getInverse(): can't invert matrix, determinant is 0"); -this.identity();return this}this.multiplyScalar(1/c);return this},translate:function(){console.warn("DEPRECATED: Matrix4's .translate() has been removed.")},rotateX:function(){console.warn("DEPRECATED: Matrix4's .rotateX() has been removed.")},rotateY:function(){console.warn("DEPRECATED: Matrix4's .rotateY() has been removed.")},rotateZ:function(){console.warn("DEPRECATED: Matrix4's .rotateZ() has been removed.")},rotateByAxis:function(){console.warn("DEPRECATED: Matrix4's .rotateByAxis() has been removed.")}, -scale:function(a){var b=this.elements,c=a.x,d=a.y,a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(1, -0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,h=a.y,g=a.z,i=e*f,k=e*h;this.set(i*f+c,i*h-d*g,i*g+d*h,0,i*h+d*g,k*h+c,k*g-d*f,0,i*g-d*h,k*g+d*f,e*g*g+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a, -0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},compose:function(a,b,c){this.makeRotationFromQuaternion(b);this.scale(c);this.setPosition(a);return this},decompose:function(){var a=new THREE.Vector3,b=new THREE.Matrix4;return function(c,d,e){var f=this.elements,h=a.set(f[0],f[1],f[2]).length(),g=a.set(f[4],f[5],f[6]).length(),i=a.set(f[8],f[9],f[10]).length();c.x=f[12];c.y=f[13];c.z=f[14];b.elements.set(this.elements);var c=1/h,f=1/g,k=1/i;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*= -f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=k;b.elements[9]*=k;b.elements[10]*=k;d.setFromRotationMatrix(b);e.x=h;e.y=g;e.z=i;return this}}(),makeFrustum:function(a,b,c,d,e,f){var h=this.elements;h[0]=2*e/(b-a);h[4]=0;h[8]=(b+a)/(b-a);h[12]=0;h[1]=0;h[5]=2*e/(d-c);h[9]=(d+c)/(d-c);h[13]=0;h[2]=0;h[6]=0;h[10]=-(f+e)/(f-e);h[14]=-2*f*e/(f-e);h[3]=0;h[7]=0;h[11]=-1;h[15]=0;return this},makePerspective:function(a,b,c,d){var a=c*Math.tan(THREE.Math.degToRad(0.5*a)),e=-a;return this.makeFrustum(e* -b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var h=this.elements,g=b-a,i=c-d,k=f-e;h[0]=2/g;h[4]=0;h[8]=0;h[12]=-((b+a)/g);h[1]=0;h[5]=2/i;h[9]=0;h[13]=-((c+d)/i);h[2]=0;h[6]=0;h[10]=-2/k;h[14]=-((f+e)/k);h[3]=0;h[7]=0;h[11]=0;h[15]=1;return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){var a=this.elements;return new THREE.Matrix4(a[0], -a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}};THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; +this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(){this.elements=new Float32Array([1,0,0,0,1,0,0,0,1]);0<arguments.length&&THREE.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}; +THREE.Matrix3.prototype={constructor:THREE.Matrix3,set:function(a,b,c,d,e,f,g,h,k){var l=this.elements;l[0]=a;l[3]=b;l[6]=c;l[1]=d;l[4]=e;l[7]=f;l[2]=g;l[5]=h;l[8]=k;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){THREE.warn("THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)}, +multiplyVector3Array:function(a){THREE.warn("THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.");return this.applyToVector3Array(a)},applyToVector3Array:function(){var a=new THREE.Vector3;return function(b,c,d){void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix3(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*=a;b[6]*= +a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],k=a[7],a=a[8];return b*f*a-b*g*k-c*e*a+c*g*h+d*e*k-d*f*h},getInverse:function(a,b){var c=a.elements,d=this.elements;d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4]; +c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");THREE.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4]; +a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]},clone:function(){return(new THREE.Matrix3).fromArray(this.elements)}}; +THREE.Matrix4=function(){this.elements=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);0<arguments.length&&THREE.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}; +THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,g,h,k,l,p,q,n,t,r,s){var u=this.elements;u[0]=a;u[4]=b;u[8]=c;u[12]=d;u[1]=e;u[5]=f;u[9]=g;u[13]=h;u[2]=k;u[6]=l;u[10]=p;u[14]=q;u[3]=n;u[7]=t;u[11]=r;u[15]=s;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){this.elements.set(a.elements);return this},extractPosition:function(a){THREE.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().");return this.copyPosition(a)}, +copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){var d=this.elements;a.set(d[0],d[1],d[2]);b.set(d[4],d[5],d[6]);c.set(d[8],d[9],d[10]);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a=new THREE.Vector3;return function(b){var c=this.elements;b=b.elements;var d=1/a.set(b[0],b[1],b[2]).length(),e=1/a.set(b[4],b[5],b[6]).length(), +f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),makeRotationFromEuler:function(a){!1===a instanceof THREE.Euler&&THREE.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){a=f*h;var k=f*e, +l=c*h,p=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+l*d;b[5]=a-p*d;b[9]=-c*g;b[2]=p-a*d;b[6]=l+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g*h,k=g*e,l=d*h,p=d*e,b[0]=a+p*c,b[4]=l*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-l,b[6]=p+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,l=d*h,p=d*e,b[0]=a-p*c,b[4]=-f*e,b[8]=l+k*c,b[1]=k+l*c,b[5]=f*h,b[9]=p-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,l=c*h,p=c*e,b[0]=g*h,b[4]=l*d-k,b[8]=a*d+p,b[1]=g*e,b[5]=p*d+a,b[9]=k*d-l,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"=== +a.order?(a=f*g,k=f*d,l=c*g,p=c*d,b[0]=g*h,b[4]=p-a*e,b[8]=l*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+l,b[10]=a-p*e):"XZY"===a.order&&(a=f*g,k=f*d,l=c*g,p=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+p,b[5]=f*h,b[9]=k*e-l,b[2]=l*e-k,b[6]=c*h,b[10]=p*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){THREE.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return this.makeRotationFromQuaternion(a)}, +makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,k=e+e;a=c*g;var l=c*h,c=c*k,p=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(p+e);b[4]=l-f;b[8]=c+h;b[1]=l+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+p);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f){var g=this.elements;c.subVectors(d,e).normalize();0===c.length()&&(c.z=1);a.crossVectors(f, +c).normalize();0===a.length()&&(c.x+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(THREE.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8], +k=c[12],l=c[1],p=c[5],q=c[9],n=c[13],t=c[2],r=c[6],s=c[10],u=c[14],v=c[3],x=c[7],D=c[11],c=c[15],w=d[0],y=d[4],A=d[8],E=d[12],G=d[1],F=d[5],z=d[9],I=d[13],U=d[2],M=d[6],H=d[10],L=d[14],P=d[3],N=d[7],R=d[11],d=d[15];e[0]=f*w+g*G+h*U+k*P;e[4]=f*y+g*F+h*M+k*N;e[8]=f*A+g*z+h*H+k*R;e[12]=f*E+g*I+h*L+k*d;e[1]=l*w+p*G+q*U+n*P;e[5]=l*y+p*F+q*M+n*N;e[9]=l*A+p*z+q*H+n*R;e[13]=l*E+p*I+q*L+n*d;e[2]=t*w+r*G+s*U+u*P;e[6]=t*y+r*F+s*M+u*N;e[10]=t*A+r*z+s*H+u*R;e[14]=t*E+r*I+s*L+u*d;e[3]=v*w+x*G+D*U+c*P;e[7]=v*y+ +x*F+D*M+c*N;e[11]=v*A+x*z+D*H+c*R;e[15]=v*E+x*I+D*L+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*= +a;b[15]*=a;return this},multiplyVector3:function(a){THREE.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.");return a.applyProjection(this)},multiplyVector4:function(a){THREE.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(a){THREE.warn("THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead."); +return this.applyToVector3Array(a)},applyToVector3Array:function(){var a=new THREE.Vector3;return function(b,c,d){void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix4(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),rotateAxis:function(a){THREE.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.");a.transformDirection(this)},crossVector:function(a){THREE.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead."); +return a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],k=a[13],l=a[2],p=a[6],q=a[10],n=a[14];return a[3]*(+e*h*p-d*k*p-e*g*q+c*k*q+d*g*n-c*h*n)+a[7]*(+b*h*n-b*k*q+e*f*q-d*f*n+d*k*l-e*h*l)+a[11]*(+b*k*p-b*g*n-e*f*p+c*f*n+e*g*l-c*k*l)+a[15]*(-d*g*l-b*h*p+b*g*q+d*f*p-c*f*q+c*h*l)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13]; +a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a=new THREE.Vector3;return function(){THREE.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b= +this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=this.elements,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[12],k=d[1],l=d[5],p=d[9],q=d[13],n=d[2],t=d[6],r=d[10],s=d[14],u=d[3],v=d[7],x=d[11],d=d[15];c[0]=p*s*v-q*r*v+q*t*x-l*s*x-p*t*d+l*r*d;c[4]=h*r*v-g*s*v-h*t*x+f*s*x+g*t*d-f*r*d;c[8]=g*q*v-h*p*v+h*l*x-f*q*x-g*l*d+f*p*d;c[12]=h*p*t-g*q*t-h*l*r+f*q*r+g*l*s-f*p*s;c[1]=q*r*u-p*s*u-q*n*x+ +k*s*x+p*n*d-k*r*d;c[5]=g*s*u-h*r*u+h*n*x-e*s*x-g*n*d+e*r*d;c[9]=h*p*u-g*q*u-h*k*x+e*q*x+g*k*d-e*p*d;c[13]=g*q*n-h*p*n+h*k*r-e*q*r-g*k*s+e*p*s;c[2]=l*s*u-q*t*u+q*n*v-k*s*v-l*n*d+k*t*d;c[6]=h*t*u-f*s*u-h*n*v+e*s*v+f*n*d-e*t*d;c[10]=f*q*u-h*l*u+h*k*v-e*q*v-f*k*d+e*l*d;c[14]=h*l*n-f*q*n-h*k*t+e*q*t+f*k*s-e*l*s;c[3]=p*t*u-l*r*u-p*n*v+k*r*v+l*n*x-k*t*x;c[7]=f*r*u-g*t*u+g*n*v-e*r*v-f*n*x+e*t*x;c[11]=g*l*u-f*p*u-g*k*v+e*p*v+f*k*x-e*l*x;c[15]=f*p*n-g*l*n+g*k*t-e*p*t-f*k*r+e*l*r;c=e*c[0]+k*c[4]+n*c[8]+u*c[12]; +if(0==c){if(b)throw Error("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");THREE.warn("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},translate:function(a){THREE.error("THREE.Matrix4: .translate() has been removed.")},rotateX:function(a){THREE.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(a){THREE.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(a){THREE.error("THREE.Matrix4: .rotateZ() has been removed.")}, +rotateByAxis:function(a,b){THREE.error("THREE.Matrix4: .rotateByAxis() has been removed.")},scale:function(a){var b=this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1, +c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,k=e*f,l=e*g;this.set(k*f+c,k*g-d*h,k*h+d*g,0,k*g+ +d*h,l*g+c,l*h-d*f,0,k*h-d*g,l*h+d*f,e*h*h+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},compose:function(a,b,c){this.makeRotationFromQuaternion(b);this.scale(c);this.setPosition(a);return this},decompose:function(){var a=new THREE.Vector3,b=new THREE.Matrix4;return function(c,d,e){var f=this.elements,g=a.set(f[0],f[1],f[2]).length(),h=a.set(f[4],f[5],f[6]).length(),k=a.set(f[8],f[9],f[10]).length();0>this.determinant()&&(g=-g);c.x=f[12]; +c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,l=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=l;b.elements[9]*=l;b.elements[10]*=l;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0; +g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRad(.5*a));var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,k=c-d,l=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/l;g[14]=-((f+e)/l);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0], +a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){return(new THREE.Matrix4).fromArray(this.elements)}};THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; THREE.Ray.prototype={constructor:THREE.Ray,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new THREE.Vector3;c.subVectors(a,this.origin); -var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(a,b,c,d){var e=a.clone().add(b).multiplyScalar(0.5),f=b.clone().sub(a).normalize(),h=0.5*a.distanceTo(b), -g=this.origin.clone().sub(e),a=-this.direction.dot(f),b=g.dot(this.direction),i=-g.dot(f),k=g.lengthSq(),m=Math.abs(1-a*a),l,p;0<=m?(g=a*i-b,l=a*b-i,p=h*m,0<=g?l>=-p?l<=p?(h=1/m,g*=h,l*=h,a=g*(g+a*l+2*b)+l*(a*g+l+2*i)+k):(l=h,g=Math.max(0,-(a*l+b)),a=-g*g+l*(l+2*i)+k):(l=-h,g=Math.max(0,-(a*l+b)),a=-g*g+l*(l+2*i)+k):l<=-p?(g=Math.max(0,-(-a*h+b)),l=0<g?-h:Math.min(Math.max(-h,-i),h),a=-g*g+l*(l+2*i)+k):l<=p?(g=0,l=Math.min(Math.max(-h,-i),h),a=l*(l+2*i)+k):(g=Math.max(0,-(a*h+b)),l=0<g?h:Math.min(Math.max(-h, --i),h),a=-g*g+l*(l+2*i)+k)):(l=0<a?-h:h,g=Math.max(0,-(a*l+b)),a=-g*g+l*(l+2*i)+k);c&&c.copy(this.direction.clone().multiplyScalar(g).add(this.origin));d&&d.copy(f.clone().multiplyScalar(l).add(e));return a},isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)? -0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new THREE.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,h;d=1/this.direction.x;f=1/this.direction.y;h=1/this.direction.z;var g=this.origin;0<=d?(c=(a.min.x-g.x)*d,d*=a.max.x-g.x):(c=(a.max.x-g.x)*d,d*=a.min.x-g.x);0<=f?(e=(a.min.y-g.y)*f,f*= -a.max.y-g.y):(e=(a.max.y-g.y)*f,f*=a.min.y-g.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(f<d||d!==d)d=f;0<=h?(e=(a.min.z-g.z)*h,h*=a.max.z-g.z):(e=(a.max.z-g.z)*h,h*=a.min.z-g.z);if(c>h||e>d)return null;if(e>c||c!==c)c=e;if(h<d||d!==d)d=h;return 0>d?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,h,g,i){b.subVectors(f,e);c.subVectors(h,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0< -f){if(g)return null;g=1}else if(0>f)g=-1,f=-f;else return null;a.subVectors(this.origin,e);e=g*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;h=g*this.direction.dot(b.cross(a));if(0>h||e+h>f)return null;e=-g*a.dot(d);return 0>e?null:this.at(e/f,i)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}, -clone:function(){return(new THREE.Ray).copy(this)}};THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; -THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,h=b.length;f<h;f++)e=Math.max(e,d.distanceToSquared(b[f]));this.radius=Math.sqrt(e);return this}}(),copy:function(a){this.center.copy(a.center);this.radius=a.radius;return this},empty:function(){return 0>=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= +var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g){a.copy(d).add(e).multiplyScalar(.5); +b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a);var h=.5*d.distanceTo(e),k=-this.direction.dot(b),l=c.dot(this.direction),p=-c.dot(b),q=c.lengthSq(),n=Math.abs(1-k*k),t;0<n?(d=k*p-l,e=k*l-p,t=h*n,0<=d?e>=-t?e<=t?(h=1/n,d*=h,e*=h,k=d*(d+k*e+2*l)+e*(k*d+e+2*p)+q):(e=h,d=Math.max(0,-(k*e+l)),k=-d*d+e*(e+2*p)+q):(e=-h,d=Math.max(0,-(k*e+l)),k=-d*d+e*(e+2*p)+q):e<=-t?(d=Math.max(0,-(-k*h+l)),e=0<d?-h:Math.min(Math.max(-h,-p),h),k=-d*d+e*(e+2*p)+q):e<=t?(d=0,e=Math.min(Math.max(-h,-p),h),k=e*(e+ +2*p)+q):(d=Math.max(0,-(k*h+l)),e=0<d?h:Math.min(Math.max(-h,-p),h),k=-d*d+e*(e+2*p)+q)):(e=0<k?-h:h,d=Math.max(0,-(k*e+l)),k=-d*d+e*(e+2*p)+q);f&&f.copy(this.direction).multiplyScalar(d).add(this.origin);g&&g.copy(b).multiplyScalar(e).add(a);return k}}(),isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},intersectSphere:function(){var a=new THREE.Vector3;return function(b,c){a.subVectors(b.center,this.origin);var d=a.dot(this.direction),e=a.dot(a)-d*d,f=b.radius*b.radius; +if(e>f)return null;f=Math.sqrt(f-e);e=d-f;d+=f;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)}, +isIntersectionBox:function(){var a=new THREE.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g;d=1/this.direction.x;f=1/this.direction.y;g=1/this.direction.z;var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=f?(e=(a.min.y-h.y)*f,f*=a.max.y-h.y):(e=(a.max.y-h.y)*f,f*=a.min.y-h.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(f<d||d!==d)d=f;0<=g?(e=(a.min.z-h.z)*g,g*=a.max.z-h.z):(e=(a.max.z-h.z)* +g,g*=a.min.z-h.z);if(c>g||e>d)return null;if(e>c||c!==c)c=e;if(g<d||d!==d)d=g;return 0>d?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0<f){if(h)return null;h=1}else if(0>f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a)); +if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new THREE.Ray).copy(this)}};THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; +THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,g=b.length;f<g;f++)e=Math.max(e,d.distanceToSquared(b[f]));this.radius=Math.sqrt(e);return this}}(),copy:function(a){this.center.copy(a.center);this.radius=a.radius;return this},empty:function(){return 0>=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius); -return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; -THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var h=this.planes;h[0].copy(a);h[1].copy(b);h[2].copy(c);h[3].copy(d);h[4].copy(e);h[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],h=c[4],g=c[5],i=c[6],k=c[7],m=c[8],l=c[9],p=c[10],s=c[11],t=c[12],n=c[13],r=c[14],c=c[15];b[0].setComponents(f-a,k-h,s-m,c-t).normalize();b[1].setComponents(f+ -a,k+h,s+m,c+t).normalize();b[2].setComponents(f+d,k+g,s+l,c+n).normalize();b[3].setComponents(f-d,k-g,s-l,c-n).normalize();b[4].setComponents(f-e,k-i,s-p,c-r).normalize();b[5].setComponents(f+e,k+i,s+p,c+r).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){for(var b=this.planes, -c=a.center,a=-a.radius,d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=0<f.normal.x?c.min.x:c.max.x;b.x=0<f.normal.x?c.max.x:c.min.x;a.y=0<f.normal.y?c.min.y:c.max.y;b.y=0<f.normal.y?c.max.y:c.min.y;a.z=0<f.normal.z?c.min.z:c.max.z;b.z=0<f.normal.z?c.max.z:c.min.z;var h=f.distanceToPoint(a),f=f.distanceToPoint(b);if(0>h&&0>f)return!1}return!0}}(),containsPoint:function(a){for(var b= -this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}}; +THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; +THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],l=c[7],p=c[8],q=c[9],n=c[10],t=c[11],r=c[12],s=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,l-g,t-p,c-r).normalize();b[1].setComponents(f+ +a,l+g,t+p,c+r).normalize();b[2].setComponents(f+d,l+h,t+q,c+s).normalize();b[3].setComponents(f-d,l-h,t-q,c-s).normalize();b[4].setComponents(f-e,l-k,t-n,c-u).normalize();b[5].setComponents(f+e,l+k,t+n,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes, +c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=0<f.normal.x?c.min.x:c.max.x;b.x=0<f.normal.x?c.max.x:c.min.x;a.y=0<f.normal.y?c.min.y:c.max.y;b.y=0<f.normal.y?c.max.y:c.min.y;a.z=0<f.normal.z?c.min.z:c.max.z;b.z=0<f.normal.z?c.max.z:c.min.z;var g=f.distanceToPoint(a),f=f.distanceToPoint(b);if(0>g&&0>f)return!1}return!0}}(), +containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, c);return this}}(),copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, -b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),a=this.distanceToPoint(a.end);return 0>b&&0<a||0>a&&0<b},intersectLine:function(){var a=new THREE.Vector3;return function(b,c){var d=c||new THREE.Vector3,e=b.delta(a),f=this.normal.dot(e);if(0==f){if(0==this.distanceToPoint(b.start))return d.copy(b.start)}else return f=-(b.start.dot(this.normal)+this.constant)/f,0>f||1<f?void 0:d.copy(e).multiplyScalar(f).add(b.start)}}(), -coplanarPoint:function(a){return(a||new THREE.Vector3).copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){var d=d||(new THREE.Matrix3).getNormalMatrix(c),e=a.copy(this.normal).applyMatrix3(d),f=this.coplanarPoint(b);f.applyMatrix4(c);this.setFromNormalAndCoplanarPoint(e,f);return this}}(),translate:function(a){this.constant-=a.dot(this.normal);return this},equals:function(a){return a.normal.equals(this.normal)&& -a.constant==this.constant},clone:function(){return(new THREE.Plane).copy(this)}};THREE.Math={PI2:2*Math.PI,generateUUID:function(){var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),b=Array(36),c=0,d;return function(){for(var e=0;36>e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return a<b?b:a>c?c:a},clampBottom:function(a,b){return a<b?b:a},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},smoothstep:function(a, -b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(0.5-Math.random())},sign:function(a){return 0>a?-1:0<a?1:0},degToRad:function(){var a=Math.PI/ -180;return function(b){return b*a}}(),radToDeg:function(){var a=180/Math.PI;return function(b){return b*a}}()};THREE.Spline=function(a){function b(a,b,c,d,e,f,h){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*h+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,h,g,i,k,m,l,p;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);h=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: -f+2;k=this.points[c[0]];m=this.points[c[1]];l=this.points[c[2]];p=this.points[c[3]];g=h*h;i=h*g;d.x=b(k.x,m.x,l.x,p.x,h,g,i);d.y=b(k.y,m.y,l.y,p.y,h,g,i);d.z=b(k.z,m.z,l.z,p.z,h,g,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,h=new THREE.Vector3,g=[],i=0;g[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b= -a/c,d=this.getPoint(b),h.copy(d),i+=h.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!=e&&(g[b]=i,e=b);g[g.length]=i;return{chunks:g,total:i}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,h,g=[],i=new THREE.Vector3,k=this.getLength();g.push(i.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=k.chunks[b]-k.chunks[b-1];h=Math.ceil(a*c/k.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<h-1;c++)d=e+c*(1/h)*(f-e),d=this.getPoint(d), -g.push(i.copy(d).clone());g.push(i.copy(this.points[b]).clone())}this.points=g}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}(); -THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,h,g){a.subVectors(h,e);b.subVectors(f,e);c.subVectors(d,e);var d=a.dot(a),e=a.dot(b),f=a.dot(c),i=b.dot(b),h=b.dot(c),k=d*i-e*e,g=g||new THREE.Vector3;if(0==k)return g.set(-2,-1,-1);k=1/k;i=(i*f-e*h)*k;d=(d*h-e*f)*k;return g.set(1-i-d,d,i)}}(); +b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start);a=this.distanceToPoint(a.end);return 0>b&&0<a||0>a&&0<b},intersectLine:function(){var a=new THREE.Vector3;return function(b,c){var d=c||new THREE.Vector3,e=b.delta(a),f=this.normal.dot(e);if(0==f){if(0==this.distanceToPoint(b.start))return d.copy(b.start)}else return f=-(b.start.dot(this.normal)+this.constant)/f,0>f||1<f?void 0:d.copy(e).multiplyScalar(f).add(b.start)}}(), +coplanarPoint:function(a){return(a||new THREE.Vector3).copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Matrix3;return function(d,e){var f=e||c.getNormalMatrix(d),f=a.copy(this.normal).applyMatrix3(f),g=this.coplanarPoint(b);g.applyMatrix4(d);this.setFromNormalAndCoplanarPoint(f,g);return this}}(),translate:function(a){this.constant-=a.dot(this.normal);return this},equals:function(a){return a.normal.equals(this.normal)&& +a.constant==this.constant},clone:function(){return(new THREE.Plane).copy(this)}}; +THREE.Math={generateUUID:function(){var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),b=Array(36),c=0,d;return function(){for(var e=0;36>e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return a<b?b:a>c?c:a},clampBottom:function(a,b){return a<b?b:a},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},smoothstep:function(a,b,c){if(a<= +b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return Math.floor(this.randFloat(a,b))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(){var a=Math.PI/180;return function(b){return b*a}}(),radToDeg:function(){var a= +180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},nextPowerOfTwo:function(a){a--;a|=a>>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}}; +THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,l,p,q,n;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);g=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+ +2;l=this.points[c[0]];p=this.points[c[1]];q=this.points[c[2]];n=this.points[c[3]];h=g*g;k=g*h;d.x=b(l.x,p.x,q.x,n.x,g,h,k);d.y=b(l.y,p.y,q.y,n.y,g,h,k);d.z=b(l.z,p.z,q.z,n.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,g=new THREE.Vector3,h=[],k=0;h[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b= +a/c,d=this.getPoint(b),g.copy(d),k+=g.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!=e&&(h[b]=k,e=b);h[h.length]=k;return{chunks:h,total:k}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,g,h=[],k=new THREE.Vector3,n=this.getLength();h.push(k.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=n.chunks[b]-n.chunks[b-1];g=Math.ceil(a*c/n.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<g-1;c++)d=e+1/g*c*(f-e),d=this.getPoint(d),h.push(k.copy(d).clone()); +h.push(k.copy(this.points[b]).clone())}this.points=h}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}(); +THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g,h){a.subVectors(g,e);b.subVectors(f,e);c.subVectors(d,e);d=a.dot(a);e=a.dot(b);f=a.dot(c);var k=b.dot(b);g=b.dot(c);var l=d*k-e*e;h=h||new THREE.Vector3;if(0==l)return h.set(-2,-1,-1);l=1/l;k=(k*f-e*g)*l;d=(d*g-e*f)*l;return h.set(1-k-d,d,k)}}(); THREE.Triangle.containsPoint=function(){var a=new THREE.Vector3;return function(b,c,d,e){b=THREE.Triangle.barycoordFromPoint(b,c,d,e,a);return 0<=b.x&&0<=b.y&&1>=b.x+b.y}}(); -THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return 0.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| +THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}, -clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Vertex=function(a){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.");return a};THREE.UV=function(a,b){console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.");return new THREE.Vector2(a,b)};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; +clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; THREE.Clock.prototype={constructor:THREE.Clock,start:function(){this.oldTime=this.startTime=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now(), -a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){}; +a=.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){}; THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a].indexOf(b)&& -c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners,d=c[a].indexOf(b);-1!==d&&c[a].splice(d,1)}},dispatchEvent:function(){var a=[];return function(b){if(void 0!==this._listeners){var c=this._listeners[b.type];if(void 0!==c){b.target=this;for(var d=c.length,e=0;e<d;e++)a[e]=c[e];for(e=0;e<d;e++)a[e].call(this,b)}}}}()};(function(a){a.Raycaster=function(b,c,d,e){this.ray=new a.Ray(b,c);this.near=d||0;this.far=e||Infinity};var b=new a.Sphere,c=new a.Ray;new a.Plane;new a.Vector3;var d=new a.Vector3,e=new a.Matrix4,f=function(a,b){return a.distance-b.distance},h=new a.Vector3,g=new a.Vector3,i=new a.Vector3,k=function(f,m,s){if(f instanceof a.Sprite){d.getPositionFromMatrix(f.matrixWorld);var t=m.ray.distanceToPoint(d);if(t>f.scale.x)return s;s.push({distance:t,point:f.position,face:null,object:f})}else if(f instanceof -a.LOD)d.getPositionFromMatrix(f.matrixWorld),t=m.ray.origin.distanceTo(d),k(f.getObjectForDistance(t),m,s);else if(f instanceof a.Mesh){var n=f.geometry;null===n.boundingSphere&&n.computeBoundingSphere();b.copy(n.boundingSphere);b.applyMatrix4(f.matrixWorld);if(!1===m.ray.isIntersectionSphere(b))return s;e.getInverse(f.matrixWorld);c.copy(m.ray).applyMatrix4(e);if(null!==n.boundingBox&&!1===c.isIntersectionBox(n.boundingBox))return s;if(n instanceof a.BufferGeometry){var r=f.material;if(void 0=== -r||!1===n.dynamic)return s;var q,u,w=m.precision;if(void 0!==n.attributes.index)for(var z=n.offsets,B=n.attributes.index.array,D=n.attributes.position.array,x=n.offsets.length,F=n.attributes.index.array.length/3,F=0;F<x;++F)for(var t=z[F].start,A=z[F].index,n=t,O=t+z[F].count;n<O;n+=3)t=A+B[n],q=A+B[n+1],u=A+B[n+2],h.set(D[3*t],D[3*t+1],D[3*t+2]),g.set(D[3*q],D[3*q+1],D[3*q+2]),i.set(D[3*u],D[3*u+1],D[3*u+2]),q=r.side===a.BackSide?c.intersectTriangle(i,g,h,!0):c.intersectTriangle(h,g,i,r.side!==a.DoubleSide), -null!==q&&(q.applyMatrix4(f.matrixWorld),t=m.ray.origin.distanceTo(q),t<w||(t<m.near||t>m.far)||s.push({distance:t,point:q,face:null,faceIndex:null,object:f}));else{D=n.attributes.position.array;F=n.attributes.position.array.length;for(n=0;n<F;n+=3)t=n,q=n+1,u=n+2,h.set(D[3*t],D[3*t+1],D[3*t+2]),g.set(D[3*q],D[3*q+1],D[3*q+2]),i.set(D[3*u],D[3*u+1],D[3*u+2]),q=r.side===a.BackSide?c.intersectTriangle(i,g,h,!0):c.intersectTriangle(h,g,i,r.side!==a.DoubleSide),null!==q&&(q.applyMatrix4(f.matrixWorld), -t=m.ray.origin.distanceTo(q),t<w||(t<m.near||t>m.far)||s.push({distance:t,point:q,face:null,faceIndex:null,object:f}))}}else if(n instanceof a.Geometry){B=f.material instanceof a.MeshFaceMaterial;D=!0===B?f.material.materials:null;w=m.precision;z=n.vertices;x=0;for(F=n.faces.length;x<F;x++)A=n.faces[x],r=!0===B?D[A.materialIndex]:f.material,void 0!==r&&(t=z[A.a],q=z[A.b],u=z[A.c],q=r.side===a.BackSide?c.intersectTriangle(u,q,t,!0):c.intersectTriangle(t,q,u,r.side!==a.DoubleSide),null!==q&&(q.applyMatrix4(f.matrixWorld), -t=m.ray.origin.distanceTo(q),t<w||(t<m.near||t>m.far)||s.push({distance:t,point:q,face:A,faceIndex:x,object:f})))}}else if(f instanceof a.Line){w=m.linePrecision;r=w*w;n=f.geometry;null===n.boundingSphere&&n.computeBoundingSphere();b.copy(n.boundingSphere);b.applyMatrix4(f.matrixWorld);if(!1===m.ray.isIntersectionSphere(b))return s;e.getInverse(f.matrixWorld);c.copy(m.ray).applyMatrix4(e);if(n instanceof a.Geometry){z=n.vertices;w=z.length;q=new a.Vector3;u=new a.Vector3;F=f.type===a.LineStrip?1: -2;for(n=0;n<w-1;n+=F)c.distanceSqToSegment(z[n],z[n+1],u,q)>r||(t=c.origin.distanceTo(u),t<m.near||t>m.far||s.push({distance:t,point:q.clone().applyMatrix4(f.matrixWorld),face:null,faceIndex:null,object:f}))}}},m=function(a,b,c){for(var a=a.getDescendants(),d=0,e=a.length;d<e;d++)k(a[d],b,c)};a.Raycaster.prototype.precision=1E-4;a.Raycaster.prototype.linePrecision=1;a.Raycaster.prototype.set=function(a,b){this.ray.set(a,b)};a.Raycaster.prototype.intersectObject=function(a,b){var c=[];!0===b&&m(a, -this,c);k(a,this,c);c.sort(f);return c};a.Raycaster.prototype.intersectObjects=function(a,b){for(var c=[],d=0,e=a.length;d<e;d++)k(a[d],this,c),!0===b&&m(a[d],this,c);c.sort(f);return c}})(THREE);THREE.Object3D=function(){this.id=THREE.Object3DIdCount++;this.uuid=THREE.Math.generateUUID();this.name="";this.parent=void 0;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Euler;this.quaternion=new THREE.Quaternion;this.scale=new THREE.Vector3(1,1,1);this.rotation._quaternion=this.quaternion;this.quaternion._euler=this.rotation;this.renderDepth=null;this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4; -this.visible=this.matrixWorldNeedsUpdate=this.matrixAutoUpdate=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this.userData={}}; -THREE.Object3D.prototype={constructor:THREE.Object3D,get eulerOrder(){console.warn("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order.");return this.rotation.order},set eulerOrder(a){console.warn("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order.");this.rotation.order=a},get useQuaternion(){console.warn("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")},set useQuaternion(a){console.warn("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")}, -applyMatrix:function(){var a=new THREE.Matrix4;return function(b){this.matrix.multiplyMatrices(b,this.matrix);this.position.getPositionFromMatrix(this.matrix);this.scale.getScaleFromMatrix(this.matrix);a.extractRotation(this.matrix);this.quaternion.setFromRotationMatrix(a)}}(),setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a,!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)}, -setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new THREE.Quaternion;return function(b,c){a.setFromAxisAngle(b,c);this.quaternion.multiply(a);return this}}(),rotateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a=new THREE.Vector3(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.rotateOnAxis(a, -b)}}(),translateOnAxis:function(){var a=new THREE.Vector3;return function(b,c){a.copy(b);a.applyQuaternion(this.quaternion);this.position.add(a.multiplyScalar(c));return this}}(),translate:function(a,b){console.warn("DEPRECATED: Object3D's .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.");return this.translateOnAxis(b,a)},translateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a= -new THREE.Vector3(0,1,0);return function(b){return this.translateOnAxis(a,b)}}(),translateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.translateOnAxis(a,b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new THREE.Matrix4;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new THREE.Matrix4;return function(b){a.lookAt(b,this.position,this.up);this.quaternion.setFromRotationMatrix(a)}}(), -add:function(a){if(a===this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");else if(a instanceof THREE.Object3D){void 0!==a.parent&&a.parent.remove(a);a.parent=this;a.dispatchEvent({type:"added"});this.children.push(a);for(var b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(-1!==b){a.parent=void 0;a.dispatchEvent({type:"removed"});this.children.splice(b,1);for(b=this;void 0!== -b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__removeObject(a)}},traverse:function(a){a(this);for(var b=0,c=this.children.length;b<c;b++)this.children[b].traverse(a)},getObjectById:function(a,b){for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c];if(e.id===a||!0===b&&(e=e.getObjectById(a,b),void 0!==e))return e}},getObjectByName:function(a,b){for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c];if(e.name===a||!0===b&&(e=e.getObjectByName(a,b),void 0!== -e))return e}},getChildByName:function(a,b){console.warn("DEPRECATED: Object3D's .getChildByName() has been renamed to .getObjectByName().");return this.getObjectByName(a,b)},getDescendants:function(a){void 0===a&&(a=[]);Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;b<c;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale);this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){!0=== -this.matrixAutoUpdate&&this.updateMatrix();if(!0===this.matrixWorldNeedsUpdate||!0===a)void 0===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)},clone:function(a,b){void 0===a&&(a=new THREE.Object3D);void 0===b&&(b=!0);a.name=this.name;a.up.copy(this.up);a.position.copy(this.position);a.quaternion.copy(this.quaternion); -a.scale.copy(this.scale);a.renderDepth=this.renderDepth;a.rotationAutoUpdate=this.rotationAutoUpdate;a.matrix.copy(this.matrix);a.matrixWorld.copy(this.matrixWorld);a.matrixAutoUpdate=this.matrixAutoUpdate;a.matrixWorldNeedsUpdate=this.matrixWorldNeedsUpdate;a.visible=this.visible;a.castShadow=this.castShadow;a.receiveShadow=this.receiveShadow;a.frustumCulled=this.frustumCulled;a.userData=JSON.parse(JSON.stringify(this.userData));if(!0===b)for(var c=0;c<this.children.length;c++)a.add(this.children[c].clone()); -return a}};THREE.EventDispatcher.prototype.apply(THREE.Object3D.prototype);THREE.Object3DIdCount=0;THREE.Projector=function(){function a(){if(i===m){var a=new THREE.RenderableVertex;k.push(a);m++;i++;return a}return k[i++]}function b(a,b){return a.z!==b.z?b.z-a.z:a.id!==b.id?a.id-b.id:0}function c(a,b){var c=0,d=1,e=a.z+a.w,f=b.z+b.w,h=-a.z+a.w,g=-b.z+b.w;if(0<=e&&0<=f&&0<=h&&0<=g)return!0;if(0>e&&0>f||0>h&&0>g)return!1;0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f)));0>h?c=Math.max(c,h/(h-g)):0>g&&(d=Math.min(d,h/(h-g)));if(d<c)return!1;a.lerp(b,c);b.lerp(a,1-d);return!0}var d,e,f=[],h= -0,g,i,k=[],m=0,l,p,s=[],t=0,n,r,q=[],u=0,w,z,B=[],D=0,x={objects:[],sprites:[],lights:[],elements:[]},F=new THREE.Vector3,A=new THREE.Vector4,O=new THREE.Box3(new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,1,1)),C=new THREE.Box3,E=Array(3),I=new THREE.Matrix4,y=new THREE.Matrix4,v,G=new THREE.Matrix4,R=new THREE.Matrix3,J=new THREE.Matrix3,ba=new THREE.Vector3,oa=new THREE.Frustum,pa=new THREE.Vector4,N=new THREE.Vector4;this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld); -y.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);return a.applyProjection(y)};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);y.multiplyMatrices(b.matrixWorld,b.projectionMatrixInverse);return a.applyProjection(y)};this.pickingRay=function(a,b){a.z=-1;var c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.sub(a).normalize();return new THREE.Raycaster(a,c)};var M=function(a){if(e===h){var b=new THREE.RenderableObject; -f.push(b);h++;e++;d=b}else d=f[e++];d.id=a.id;d.object=a;null!==a.renderDepth?d.z=a.renderDepth:(F.getPositionFromMatrix(a.matrixWorld),F.applyProjection(y),d.z=F.z);return d},Q=function(a){if(!1!==a.visible){a instanceof THREE.Light?x.lights.push(a):a instanceof THREE.Mesh||a instanceof THREE.Line?(!1===a.frustumCulled||!0===oa.intersectsObject(a))&&x.objects.push(M(a)):a instanceof THREE.Sprite&&x.sprites.push(M(a));for(var b=0,c=a.children.length;b<c;b++)Q(a.children[b])}};this.projectScene=function(d, -f,h,m){var da=!1,F,M,ea,V,P,Z,U,ka,ta,ia,La,Ga;z=r=p=0;x.elements.length=0;!0===d.autoUpdate&&d.updateMatrixWorld();void 0===f.parent&&f.updateMatrixWorld();I.copy(f.matrixWorldInverse.getInverse(f.matrixWorld));y.multiplyMatrices(f.projectionMatrix,I);J.getNormalMatrix(I);oa.setFromMatrix(y);e=0;x.objects.length=0;x.sprites.length=0;x.lights.length=0;Q(d);!0===h&&x.objects.sort(b);d=0;for(h=x.objects.length;d<h;d++)if(U=x.objects[d].object,v=U.matrixWorld,i=0,U instanceof THREE.Mesh){ka=U.geometry; -ea=ka.vertices;ta=ka.faces;ka=ka.faceVertexUvs;R.getNormalMatrix(v);La=U.material instanceof THREE.MeshFaceMaterial;Ga=!0===La?U.material:null;F=0;for(M=ea.length;F<M;F++){g=a();g.positionWorld.copy(ea[F]).applyMatrix4(v);g.positionScreen.copy(g.positionWorld).applyMatrix4(y);var fa=1/g.positionScreen.w;g.positionScreen.x*=fa;g.positionScreen.y*=fa;g.positionScreen.z*=fa;g.visible=!(-1>g.positionScreen.x||1<g.positionScreen.x||-1>g.positionScreen.y||1<g.positionScreen.y||-1>g.positionScreen.z||1< -g.positionScreen.z)}ea=0;for(F=ta.length;ea<F;ea++)if(M=ta[ea],fa=!0===La?Ga.materials[M.materialIndex]:U.material,void 0!==fa&&(Z=fa.side,V=k[M.a],P=k[M.b],ia=k[M.c],E[0]=V.positionScreen,E[1]=P.positionScreen,E[2]=ia.positionScreen,!0===V.visible||!0===P.visible||!0===ia.visible||O.isIntersectionBox(C.setFromPoints(E))))if(da=0>(ia.positionScreen.x-V.positionScreen.x)*(P.positionScreen.y-V.positionScreen.y)-(ia.positionScreen.y-V.positionScreen.y)*(P.positionScreen.x-V.positionScreen.x),Z===THREE.DoubleSide|| -da===(Z===THREE.FrontSide)){if(p===t){var Da=new THREE.RenderableFace3;s.push(Da);t++;p++;l=Da}else l=s[p++];l.id=U.id;l.v1.copy(V);l.v2.copy(P);l.v3.copy(ia);l.normalModel.copy(M.normal);!1===da&&(Z===THREE.BackSide||Z===THREE.DoubleSide)&&l.normalModel.negate();l.normalModel.applyMatrix3(R).normalize();l.normalModelView.copy(l.normalModel).applyMatrix3(J);l.centroidModel.copy(M.centroid).applyMatrix4(v);ia=M.vertexNormals;V=0;for(P=Math.min(ia.length,3);V<P;V++)Da=l.vertexNormalsModel[V],Da.copy(ia[V]), -!1===da&&(Z===THREE.BackSide||Z===THREE.DoubleSide)&&Da.negate(),Da.applyMatrix3(R).normalize(),l.vertexNormalsModelView[V].copy(Da).applyMatrix3(J);l.vertexNormalsLength=ia.length;da=0;for(V=Math.min(ka.length,3);da<V;da++)if(ia=ka[da][ea],void 0!==ia){P=0;for(Z=ia.length;P<Z;P++)l.uvs[da][P]=ia[P]}l.color=M.color;l.material=fa;ba.copy(l.centroidModel).applyProjection(y);l.z=ba.z;x.elements.push(l)}}else if(U instanceof THREE.Line){G.multiplyMatrices(y,v);ea=U.geometry.vertices;V=a();V.positionScreen.copy(ea[0]).applyMatrix4(G); -ta=U.type===THREE.LinePieces?2:1;F=1;for(M=ea.length;F<M;F++)V=a(),V.positionScreen.copy(ea[F]).applyMatrix4(G),0<(F+1)%ta||(P=k[i-2],pa.copy(V.positionScreen),N.copy(P.positionScreen),!0===c(pa,N)&&(pa.multiplyScalar(1/pa.w),N.multiplyScalar(1/N.w),r===u?(ka=new THREE.RenderableLine,q.push(ka),u++,r++,n=ka):n=q[r++],n.id=U.id,n.v1.positionScreen.copy(pa),n.v2.positionScreen.copy(N),n.z=Math.max(pa.z,N.z),n.material=U.material,U.material.vertexColors===THREE.VertexColors&&(n.vertexColors[0].copy(U.geometry.colors[F]), -n.vertexColors[1].copy(U.geometry.colors[F-1])),x.elements.push(n)))}d=0;for(h=x.sprites.length;d<h;d++)U=x.sprites[d].object,v=U.matrixWorld,U instanceof THREE.Sprite&&(A.set(v.elements[12],v.elements[13],v.elements[14],1),A.applyMatrix4(y),fa=1/A.w,A.z*=fa,-1<A.z&&1>A.z&&(z===D?(ta=new THREE.RenderableSprite,B.push(ta),D++,z++,w=ta):w=B[z++],w.id=U.id,w.x=A.x*fa,w.y=A.y*fa,w.z=A.z,w.object=U,w.rotation=U.rotation,w.scale.x=U.scale.x*Math.abs(w.x-(A.x+f.projectionMatrix.elements[0])/(A.w+f.projectionMatrix.elements[12])), -w.scale.y=U.scale.y*Math.abs(w.y-(A.y+f.projectionMatrix.elements[5])/(A.w+f.projectionMatrix.elements[13])),w.material=U.material,x.elements.push(w)));!0===m&&x.elements.sort(b);return x}};THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0;this.centroid=new THREE.Vector3}; -THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();b=0;for(c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();b=0;for(c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone(); -return a}};THREE.Face4=function(a,b,c,d,e,f,h){console.warn("THREE.Face4 has been removed. A THREE.Face3 will be created instead.");return new THREE.Face3(a,b,c,e,f,h)};THREE.Geometry=function(){this.id=THREE.GeometryIdCount++;this.uuid=THREE.Math.generateUUID();this.name="";this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.dynamic=!0;this.buffersNeedUpdate=this.lineDistancesNeedUpdate=this.colorsNeedUpdate=this.tangentsNeedUpdate=this.normalsNeedUpdate=this.uvsNeedUpdate= -this.elementsNeedUpdate=this.verticesNeedUpdate=!1}; -THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){var e=this.faces[c];e.normal.applyMatrix3(b).normalize();for(var f=0,h=e.vertexNormals.length;f<h;f++)e.vertexNormals[f].applyMatrix3(b).normalize();e.centroid.applyMatrix4(a)}this.boundingBox instanceof THREE.Box3&&this.computeBoundingBox();this.boundingSphere instanceof -THREE.Sphere&&this.computeBoundingSphere()},computeCentroids:function(){var a,b,c;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],c.centroid.set(0,0,0),c.centroid.add(this.vertices[c.a]),c.centroid.add(this.vertices[c.b]),c.centroid.add(this.vertices[c.c]),c.centroid.divideScalar(3)},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],f=this.vertices[e.a],h=this.vertices[e.b];a.subVectors(this.vertices[e.c],h);b.subVectors(f, -h);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d,e;if(void 0===this.__tmpVertices){e=this.__tmpVertices=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)e[b]=new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]}else{e=this.__tmpVertices;b=0;for(c=this.vertices.length;b<c;b++)e[b].set(0,0,0)}if(a){var f,h,g=new THREE.Vector3,i=new THREE.Vector3;new THREE.Vector3; -new THREE.Vector3;new THREE.Vector3;b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],a=this.vertices[d.a],f=this.vertices[d.b],h=this.vertices[d.c],g.subVectors(h,f),i.subVectors(a,f),g.cross(i),e[d.a].add(g),e[d.b].add(g),e[d.c].add(g)}else{b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],e[d.a].add(d.normal),e[d.b].add(d.normal),e[d.c].add(d.normal)}b=0;for(c=this.vertices.length;b<c;b++)e[b].normalize();b=0;for(c=this.faces.length;b<c;b++)d=this.faces[b],d.vertexNormals[0].copy(e[d.a]),d.vertexNormals[1].copy(e[d.b]), -d.vertexNormals[2].copy(e[d.c])},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++){e=this.faces[c];e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone();e.__originalVertexNormals||(e.__originalVertexNormals=[]);a=0;for(b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=e.vertexNormals[a].clone()}var f=new THREE.Geometry;f.faces= -this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];e=this.morphNormals[a].faceNormals;var h=this.morphNormals[a].vertexNormals,g,i;c=0;for(d=this.faces.length;c<d;c++)g=new THREE.Vector3,i={a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3},e.push(g),h.push(i)}h=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;f.computeFaceNormals();f.computeVertexNormals(); -c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],g=h.faceNormals[c],i=h.vertexNormals[c],g.copy(e.normal),i.a.copy(e.vertexNormals[0]),i.b.copy(e.vertexNormals[1]),i.c.copy(e.vertexNormals[2])}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){var a,b,c,d,e,f,h,g,i,k,m,l,p,s,t,n,r,q=[],u=[];c=new THREE.Vector3;var w=new THREE.Vector3,z=new THREE.Vector3,B=new THREE.Vector3,D=new THREE.Vector3; -a=0;for(b=this.vertices.length;a<b;a++)q[a]=new THREE.Vector3,u[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)e=this.faces[a],f=this.faceVertexUvs[0][a],d=e.a,r=e.b,e=e.c,h=this.vertices[d],g=this.vertices[r],i=this.vertices[e],k=f[0],m=f[1],l=f[2],f=g.x-h.x,p=i.x-h.x,s=g.y-h.y,t=i.y-h.y,g=g.z-h.z,h=i.z-h.z,i=m.x-k.x,n=l.x-k.x,m=m.y-k.y,k=l.y-k.y,l=1/(i*k-n*m),c.set((k*f-m*p)*l,(k*s-m*t)*l,(k*g-m*h)*l),w.set((i*p-n*f)*l,(i*t-n*s)*l,(i*h-n*g)*l),q[d].add(c),q[r].add(c),q[e].add(c),u[d].add(w), -u[r].add(w),u[e].add(w);w=["a","b","c","d"];a=0;for(b=this.faces.length;a<b;a++){e=this.faces[a];for(c=0;c<Math.min(e.vertexNormals.length,3);c++)D.copy(e.vertexNormals[c]),d=e[w[c]],r=q[d],z.copy(r),z.sub(D.multiplyScalar(D.dot(r))).normalize(),B.crossVectors(e.vertexNormals[c],r),d=B.dot(u[d]),d=0>d?-1:1,e.vertexTangents[c]=new THREE.Vector4(z.x,z.y,z.z,d)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]= -a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);this.boundingSphere.setFromPoints(this.vertices)},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,h;this.__tmpVertices=void 0;f=0;for(h=this.vertices.length;f<h;f++)d=this.vertices[f],d=Math.round(d.x*e)+"_"+Math.round(d.y*e)+"_"+Math.round(d.z* -e),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];a=[];f=0;for(h=this.faces.length;f<h;f++){e=this.faces[f];e.a=c[e.a];e.b=c[e.b];e.c=c[e.c];e=[e.a,e.b,e.c];for(d=0;3>d;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}}for(f=a.length-1;0<=f;f--){e=a[f];this.faces.splice(e,1);c=0;for(h=this.faceVertexUvs.length;c<h;c++)this.faceVertexUvs[c].splice(e,1)}f=this.vertices.length-b.length;this.vertices=b;return f},clone:function(){for(var a=new THREE.Geometry,b=this.vertices,c=0,d= -b.length;c<d;c++)a.vertices.push(b[c].clone());b=this.faces;c=0;for(d=b.length;c<d;c++)a.faces.push(b[c].clone());b=this.faceVertexUvs[0];c=0;for(d=b.length;c<d;c++){for(var e=b[c],f=[],h=0,g=e.length;h<g;h++)f.push(new THREE.Vector2(e[h].x,e[h].y));a.faceVertexUvs[0].push(f)}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype);THREE.GeometryIdCount=0;THREE.BufferGeometry=function(){this.id=THREE.GeometryIdCount++;this.uuid=THREE.Math.generateUUID();this.name="";this.attributes={};this.dynamic=!0;this.offsets=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.morphTargets=[]}; -THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,addAttribute:function(a,b,c,d){this.attributes[a]={itemSize:d,array:new b(c*d)}},applyMatrix:function(a){var b,c;this.attributes.position&&(b=this.attributes.position.array);this.attributes.normal&&(c=this.attributes.normal.array);void 0!==b&&(a.multiplyVector3Array(b),this.verticesNeedUpdate=!0);void 0!==c&&((new THREE.Matrix3).getNormalMatrix(a).multiplyVector3Array(c),this.normalizeNormals(),this.normalsNeedUpdate=!0)},computeBoundingBox:function(){null=== -this.boundingBox&&(this.boundingBox=new THREE.Box3);var a=this.attributes.position.array;if(a){var b=this.boundingBox,c,d,e;3<=a.length&&(b.min.x=b.max.x=a[0],b.min.y=b.max.y=a[1],b.min.z=b.max.z=a[2]);for(var f=3,h=a.length;f<h;f+=3)c=a[f],d=a[f+1],e=a[f+2],c<b.min.x?b.min.x=c:c>b.max.x&&(b.max.x=c),d<b.min.y?b.min.y=d:d>b.max.y&&(b.max.y=d),e<b.min.z?b.min.z=e:e>b.max.z&&(b.max.z=e)}if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){var a= -new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){for(var d=this.boundingSphere.center,e=0,f=c.length;e<f;e+=3)b.set(c[e],c[e+1],c[e+2]),a.addPoint(b);a.center(d);for(var h=0,e=0,f=c.length;e<f;e+=3)b.set(c[e],c[e+1],c[e+2]),h=Math.max(h,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(h)}}}(),computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d;a=this.attributes.position.array.length; -if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a)};else{a=0;for(b=this.attributes.normal.array.length;a<b;a++)this.attributes.normal.array[a]=0}var e=this.attributes.position.array,f=this.attributes.normal.array,h,g,i,k,m,l,p=new THREE.Vector3,s=new THREE.Vector3,t=new THREE.Vector3,n=new THREE.Vector3,r=new THREE.Vector3;if(this.attributes.index){var q=this.attributes.index.array,u=this.offsets;c=0;for(d=u.length;c<d;++c){b=u[c].start;h=u[c].count;var w= -u[c].index;a=b;for(b+=h;a<b;a+=3)h=w+q[a],g=w+q[a+1],i=w+q[a+2],k=e[3*h],m=e[3*h+1],l=e[3*h+2],p.set(k,m,l),k=e[3*g],m=e[3*g+1],l=e[3*g+2],s.set(k,m,l),k=e[3*i],m=e[3*i+1],l=e[3*i+2],t.set(k,m,l),n.subVectors(t,s),r.subVectors(p,s),n.cross(r),f[3*h]+=n.x,f[3*h+1]+=n.y,f[3*h+2]+=n.z,f[3*g]+=n.x,f[3*g+1]+=n.y,f[3*g+2]+=n.z,f[3*i]+=n.x,f[3*i+1]+=n.y,f[3*i+2]+=n.z}}else{a=0;for(b=e.length;a<b;a+=9)k=e[a],m=e[a+1],l=e[a+2],p.set(k,m,l),k=e[a+3],m=e[a+4],l=e[a+5],s.set(k,m,l),k=e[a+6],m=e[a+7],l=e[a+8], -t.set(k,m,l),n.subVectors(t,s),r.subVectors(p,s),n.cross(r),f[a]=n.x,f[a+1]=n.y,f[a+2]=n.z,f[a+3]=n.x,f[a+4]=n.y,f[a+5]=n.z,f[a+6]=n.x,f[a+7]=n.y,f[a+8]=n.z}this.normalizeNormals();this.normalsNeedUpdate=!0}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},computeTangents:function(){function a(a){oa.x=d[3*a];oa.y=d[3*a+1];oa.z=d[3*a+2];pa.copy(oa);M=g[a];J.copy(M);J.sub(oa.multiplyScalar(oa.dot(M))).normalize(); -ba.crossVectors(pa,M);Q=ba.dot(i[a]);N=0>Q?-1:1;h[4*a]=J.x;h[4*a+1]=J.y;h[4*a+2]=J.z;h[4*a+3]=N}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;void 0===this.attributes.tangent&& -(this.attributes.tangent={itemSize:4,array:new Float32Array(4*f)});for(var h=this.attributes.tangent.array,g=[],i=[],k=0;k<f;k++)g[k]=new THREE.Vector3,i[k]=new THREE.Vector3;var m,l,p,s,t,n,r,q,u,w,z,B,D,x,F,f=new THREE.Vector3,k=new THREE.Vector3,A,O,C,E,I,y,v,G=this.offsets;C=0;for(E=G.length;C<E;++C){O=G[C].start;I=G[C].count;var R=G[C].index;A=O;for(O+=I;A<O;A+=3)I=R+b[A],y=R+b[A+1],v=R+b[A+2],m=c[3*I],l=c[3*I+1],p=c[3*I+2],s=c[3*y],t=c[3*y+1],n=c[3*y+2],r=c[3*v],q=c[3*v+1],u=c[3*v+2],w=e[2* -I],z=e[2*I+1],B=e[2*y],D=e[2*y+1],x=e[2*v],F=e[2*v+1],s-=m,m=r-m,t-=l,l=q-l,n-=p,p=u-p,B-=w,w=x-w,D-=z,z=F-z,F=1/(B*z-w*D),f.set((z*s-D*m)*F,(z*t-D*l)*F,(z*n-D*p)*F),k.set((B*m-w*s)*F,(B*l-w*t)*F,(B*p-w*n)*F),g[I].add(f),g[y].add(f),g[v].add(f),i[I].add(k),i[y].add(k),i[v].add(k)}var J=new THREE.Vector3,ba=new THREE.Vector3,oa=new THREE.Vector3,pa=new THREE.Vector3,N,M,Q;C=0;for(E=G.length;C<E;++C){O=G[C].start;I=G[C].count;R=G[C].index;A=O;for(O+=I;A<O;A+=3)I=R+b[A],y=R+b[A+1],v=R+b[A+2],a(I),a(y), -a(v)}this.tangentsNeedUpdate=this.hasTangents=!0}},clone:function(){var a=new THREE.BufferGeometry,b=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array],c;for(c in this.attributes){for(var d=this.attributes[c],e=d.array,f={itemSize:d.itemSize,numItems:d.numItems,array:null},d=0,h=b.length;d<h;d++){var g=b[d];if(e instanceof g){f.array=new g(e);break}}a.attributes[c]=f}d=0;for(h=this.offsets.length;d<h;d++)b=this.offsets[d],a.offsets.push({start:b.start, -index:b.index,count:b.count});return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype);THREE.Camera=function(){THREE.Object3D.call(this);this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4;this.projectionMatrixInverse=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.lookAt=function(){var a=new THREE.Matrix4;return function(b){a.lookAt(this.position,b,this.up);this.quaternion.setFromRotationMatrix(a)}}(); -THREE.Camera.prototype.clone=function(a){void 0===a&&(a=new THREE.Camera);THREE.Object3D.prototype.clone.call(this,a);a.matrixWorldInverse.copy(this.matrixWorldInverse);a.projectionMatrix.copy(this.projectionMatrix);a.projectionMatrixInverse.copy(this.projectionMatrixInverse);return a};THREE.OrthographicCamera=function(a,b,c,d,e,f){THREE.Camera.call(this);this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:0.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=Object.create(THREE.Camera.prototype);THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix.makeOrthographic(this.left,this.right,this.top,this.bottom,this.near,this.far)}; -THREE.OrthographicCamera.prototype.clone=function(){var a=new THREE.OrthographicCamera;THREE.Camera.prototype.clone.call(this,a);a.left=this.left;a.right=this.right;a.top=this.top;a.bottom=this.bottom;a.near=this.near;a.far=this.far;return a};THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:0.1;this.far=void 0!==d?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=Object.create(THREE.Camera.prototype);THREE.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);this.fov=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.updateProjectionMatrix()}; -THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=e;this.height=f;this.updateProjectionMatrix()}; -THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(THREE.Math.degToRad(0.5*this.fov))*this.near,c=-b,d=a*c,a=Math.abs(a*b-d),c=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*a/this.fullWidth,d+(this.x+this.width)*a/this.fullWidth,b-(this.y+this.height)*c/this.fullHeight,b-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far)}; -THREE.PerspectiveCamera.prototype.clone=function(){var a=new THREE.PerspectiveCamera;THREE.Camera.prototype.clone.call(this,a);a.fov=this.fov;a.aspect=this.aspect;a.near=this.near;a.far=this.far;return a};THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.Light.prototype.clone=function(a){void 0===a&&(a=new THREE.Light);THREE.Object3D.prototype.clone.call(this,a);a.color.copy(this.color);return a};THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.AmbientLight.prototype.clone=function(){var a=new THREE.AmbientLight;THREE.Light.prototype.clone.call(this,a);return a};THREE.AreaLight=function(a,b){THREE.Light.call(this,a);this.normal=new THREE.Vector3(0,-1,0);this.right=new THREE.Vector3(1,0,0);this.intensity=void 0!==b?b:1;this.height=this.width=1;this.constantAttenuation=1.5;this.linearAttenuation=0.5;this.quadraticAttenuation=0.1};THREE.AreaLight.prototype=Object.create(THREE.Light.prototype);THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.position.set(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=!1;this.shadowCascadeOffset=new THREE.Vector3(0, -0,-1E3);this.shadowCascadeCount=2;this.shadowCascadeBias=[0,0,0];this.shadowCascadeWidth=[512,512,512];this.shadowCascadeHeight=[512,512,512];this.shadowCascadeNearZ=[-1,0.99,0.998];this.shadowCascadeFarZ=[0.99,0.998,1];this.shadowCascadeArray=[];this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.DirectionalLight.prototype=Object.create(THREE.Light.prototype); -THREE.DirectionalLight.prototype.clone=function(){var a=new THREE.DirectionalLight;THREE.Light.prototype.clone.call(this,a);a.target=this.target.clone();a.intensity=this.intensity;a.castShadow=this.castShadow;a.onlyShadow=this.onlyShadow;return a};THREE.HemisphereLight=function(a,b,c){THREE.Light.call(this,a);this.position.set(0,100,0);this.groundColor=new THREE.Color(b);this.intensity=void 0!==c?c:1};THREE.HemisphereLight.prototype=Object.create(THREE.Light.prototype);THREE.HemisphereLight.prototype.clone=function(){var a=new THREE.HemisphereLight;THREE.Light.prototype.clone.call(this,a);a.groundColor.copy(this.groundColor);a.intensity=this.intensity;return a};THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0};THREE.PointLight.prototype=Object.create(THREE.Light.prototype);THREE.PointLight.prototype.clone=function(){var a=new THREE.PointLight;THREE.Light.prototype.clone.call(this,a);a.intensity=this.intensity;a.distance=this.distance;return a};THREE.SpotLight=function(a,b,c,d,e){THREE.Light.call(this,a);this.position.set(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/3;this.exponent=void 0!==e?e:10;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowMatrix=this.shadowCamera=this.shadowMapSize= -this.shadowMap=null};THREE.SpotLight.prototype=Object.create(THREE.Light.prototype);THREE.SpotLight.prototype.clone=function(){var a=new THREE.SpotLight;THREE.Light.prototype.clone.call(this,a);a.target=this.target.clone();a.intensity=this.intensity;a.distance=this.distance;a.angle=this.angle;a.exponent=this.exponent;a.castShadow=this.castShadow;a.onlyShadow=this.onlyShadow;return a};THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}; -THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:"anonymous",addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/ -a.total).toFixed(0)+"%"):b+((a.loaded/1E3).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");a.pop();return(1>a.length?".":a.join("/"))+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<a.length;++d)c[d]=THREE.Loader.prototype.createMaterial(a[d],b);return c},needsTangents:function(a){for(var b=0,c=a.length;b<c;b++)if(a[b]instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=Math.log(a)/Math.LN2;return Math.floor(a)== -a}function d(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function e(a,e,f,g,i,k,r){var q=/\.dds$/i.test(f),u=b+"/"+f;if(q){var w=THREE.ImageUtils.loadCompressedTexture(u);a[e]=w}else w=document.createElement("canvas"),a[e]=new THREE.Texture(w);a[e].sourceFile=f;g&&(a[e].repeat.set(g[0],g[1]),1!==g[0]&&(a[e].wrapS=THREE.RepeatWrapping),1!==g[1]&&(a[e].wrapT=THREE.RepeatWrapping));i&&a[e].offset.set(i[0],i[1]);k&&(f={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!== -f[k[0]]&&(a[e].wrapS=f[k[0]]),void 0!==f[k[1]]&&(a[e].wrapT=f[k[1]]));r&&(a[e].anisotropy=r);if(!q){var z=a[e],a=new Image;a.onload=function(){if(!c(this.width)||!c(this.height)){var a=d(this.width),b=d(this.height);z.image.width=a;z.image.height=b;z.image.getContext("2d").drawImage(this,0,0,a,b)}else z.image=this;z.needsUpdate=!0};a.crossOrigin=h.crossOrigin;a.src=u}}function f(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var h=this,g="MeshLambertMaterial",i={color:15658734,opacity:1,map:null, -lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?g="MeshPhongMaterial":"basic"===k&&(g="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(i.blending=THREE[a.blending]);if(void 0!==a.transparent||1>a.opacity)i.transparent=a.transparent;void 0!==a.depthTest&&(i.depthTest=a.depthTest);void 0!==a.depthWrite&&(i.depthWrite=a.depthWrite);void 0!==a.visible&&(i.visible=a.visible);void 0!==a.flipSided&&(i.side=THREE.BackSide); -void 0!==a.doubleSided&&(i.side=THREE.DoubleSide);void 0!==a.wireframe&&(i.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"===a.vertexColors?i.vertexColors=THREE.FaceColors:a.vertexColors&&(i.vertexColors=THREE.VertexColors));a.colorDiffuse?i.color=f(a.colorDiffuse):a.DbgColor&&(i.color=a.DbgColor);a.colorSpecular&&(i.specular=f(a.colorSpecular));a.colorAmbient&&(i.ambient=f(a.colorAmbient));a.transparency&&(i.opacity=a.transparency);a.specularCoef&&(i.shininess=a.specularCoef);a.mapDiffuse&& -b&&e(i,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&e(i,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&e(i,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&e(i,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&e(i,"specularMap",a.mapSpecular,a.mapSpecularRepeat, -a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapBumpScale&&(i.bumpScale=a.mapBumpScale);a.mapNormal?(g=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(g.uniforms),k.tNormal.value=i.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),i.map&&(k.tDiffuse.value=i.map,k.enableDiffuse.value=!0),i.specularMap&&(k.tSpecular.value=i.specularMap,k.enableSpecular.value=!0),i.lightMap&&(k.tAO.value=i.lightMap,k.enableAO.value=!0),k.uDiffuseColor.value.setHex(i.color), -k.uSpecularColor.value.setHex(i.specular),k.uAmbientColor.value.setHex(i.ambient),k.uShininess.value=i.shininess,void 0!==i.opacity&&(k.uOpacity.value=i.opacity),g=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:k,lights:!0,fog:!0}),i.transparent&&(g.transparent=!0)):g=new THREE[g](i);void 0!==a.DbgName&&(g.name=a.DbgName);return g}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; -THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,f=new XMLHttpRequest;void 0!==b&&f.addEventListener("load",function(c){b(c.target.responseText);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);f.open("GET",a,!0);f.send(null);e.manager.itemStart(a)},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; -THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,f=document.createElement("img");void 0!==b&&f.addEventListener("load",function(){e.manager.itemEnd(a);b(this)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);f.src=a;e.manager.itemStart(a);return f},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; -THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,h=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var g=JSON.parse(f.responseText),g=a.parse(g,d);c(g.geometry,g.materials)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+f.status+"]");else f.readyState===f.LOADING?e&&(0===h&& -(h=f.getResponseHeader("Content-Length")),e({total:h,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(h=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; -THREE.JSONLoader.prototype.parse=function(a,b){var c=new THREE.Geometry,d=void 0!==a.scale?1/a.scale:1,e,f,h,g,i,k,m,l,p,s,t,n,r,q,u=a.faces;p=a.vertices;var w=a.normals,z=a.colors,B=0;if(void 0!==a.uvs){for(e=0;e<a.uvs.length;e++)a.uvs[e].length&&B++;for(e=0;e<B;e++)c.faceVertexUvs[e]=[]}g=0;for(i=p.length;g<i;)k=new THREE.Vector3,k.x=p[g++]*d,k.y=p[g++]*d,k.z=p[g++]*d,c.vertices.push(k);g=0;for(i=u.length;g<i;)if(p=u[g++],s=p&1,h=p&2,e=p&8,m=p&16,t=p&32,k=p&64,p&=128,s){s=new THREE.Face3;s.a=u[g]; -s.b=u[g+1];s.c=u[g+3];n=new THREE.Face3;n.a=u[g+1];n.b=u[g+2];n.c=u[g+3];g+=4;h&&(h=u[g++],s.materialIndex=h,n.materialIndex=h);h=c.faces.length;if(e)for(e=0;e<B;e++){r=a.uvs[e];c.faceVertexUvs[e][h]=[];c.faceVertexUvs[e][h+1]=[];for(f=0;4>f;f++)l=u[g++],q=r[2*l],l=r[2*l+1],q=new THREE.Vector2(q,l),2!==f&&c.faceVertexUvs[e][h].push(q),0!==f&&c.faceVertexUvs[e][h+1].push(q)}m&&(m=3*u[g++],s.normal.set(w[m++],w[m++],w[m]),n.normal.copy(s.normal));if(t)for(e=0;4>e;e++)m=3*u[g++],t=new THREE.Vector3(w[m++], -w[m++],w[m]),2!==e&&s.vertexNormals.push(t),0!==e&&n.vertexNormals.push(t);k&&(k=u[g++],k=z[k],s.color.setHex(k),n.color.setHex(k));if(p)for(e=0;4>e;e++)k=u[g++],k=z[k],2!==e&&s.vertexColors.push(new THREE.Color(k)),0!==e&&n.vertexColors.push(new THREE.Color(k));c.faces.push(s);c.faces.push(n)}else{s=new THREE.Face3;s.a=u[g++];s.b=u[g++];s.c=u[g++];h&&(h=u[g++],s.materialIndex=h);h=c.faces.length;if(e)for(e=0;e<B;e++){r=a.uvs[e];c.faceVertexUvs[e][h]=[];for(f=0;3>f;f++)l=u[g++],q=r[2*l],l=r[2*l+1], -q=new THREE.Vector2(q,l),c.faceVertexUvs[e][h].push(q)}m&&(m=3*u[g++],s.normal.set(w[m++],w[m++],w[m]));if(t)for(e=0;3>e;e++)m=3*u[g++],t=new THREE.Vector3(w[m++],w[m++],w[m]),s.vertexNormals.push(t);k&&(k=u[g++],s.color.setHex(z[k]));if(p)for(e=0;3>e;e++)k=u[g++],s.vertexColors.push(new THREE.Color(z[k]));c.faces.push(s)}if(a.skinWeights){g=0;for(i=a.skinWeights.length;g<i;g+=2)u=a.skinWeights[g],w=a.skinWeights[g+1],c.skinWeights.push(new THREE.Vector4(u,w,0,0))}if(a.skinIndices){g=0;for(i=a.skinIndices.length;g< -i;g+=2)u=a.skinIndices[g],w=a.skinIndices[g+1],c.skinIndices.push(new THREE.Vector4(u,w,0,0))}c.bones=a.bones;c.animation=a.animation;c.animations=a.animations;if(void 0!==a.morphTargets){g=0;for(i=a.morphTargets.length;g<i;g++){c.morphTargets[g]={};c.morphTargets[g].name=a.morphTargets[g].name;c.morphTargets[g].vertices=[];z=c.morphTargets[g].vertices;B=a.morphTargets[g].vertices;u=0;for(w=B.length;u<w;u+=3)p=new THREE.Vector3,p.x=B[u]*d,p.y=B[u+1]*d,p.z=B[u+2]*d,z.push(p)}}if(void 0!==a.morphColors){g= -0;for(i=a.morphColors.length;g<i;g++){c.morphColors[g]={};c.morphColors[g].name=a.morphColors[g].name;c.morphColors[g].colors=[];w=c.morphColors[g].colors;z=a.morphColors[g].colors;d=0;for(u=z.length;d<u;d+=3)B=new THREE.Color(16755200),B.setRGB(z[d],z[d+1],z[d+2]),w.push(B)}}c.computeCentroids();c.computeFaceNormals();c.computeBoundingSphere();if(void 0===a.materials)return{geometry:c};d=this.initMaterials(a.materials,b);this.needsTangents(d)&&c.computeTangents();return{geometry:c,materials:d}};THREE.LoadingManager=function(a,b,c){var d=this,e=0,f=0;this.onLoad=a;this.onProgress=b;this.onError=c;this.itemStart=function(){f++};this.itemEnd=function(a){e++;if(void 0!==d.onProgress)d.onProgress(a,e,f);if(e===f&&void 0!==d.onLoad)d.onLoad()}};THREE.DefaultLoadingManager=new THREE.LoadingManager;THREE.BufferGeometryLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; -THREE.BufferGeometryLoader.prototype={constructor:THREE.BufferGeometryLoader,load:function(a,b){var c=this,d=new THREE.XHRLoader;d.setCrossOrigin(this.crossOrigin);d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new THREE.BufferGeometry,c=a.attributes,d=a.offsets,a=a.boundingSphere,e;for(e in c){var f=c[e];b.attributes[e]={itemSize:f.itemSize,array:new self[f.type](f.array)}}void 0!==d&&(b.offsets=JSON.parse(JSON.stringify(d))); -void 0!==a&&(b.boundingSphere=new THREE.Sphere((new THREE.Vector3).fromArray(void 0!==a.center?a.center:[0,0,0]),a.radius));return b}};THREE.GeometryLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};THREE.GeometryLoader.prototype={constructor:THREE.GeometryLoader,load:function(a,b){var c=this,d=new THREE.XHRLoader;d.setCrossOrigin(this.crossOrigin);d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(){}};THREE.MaterialLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; -THREE.MaterialLoader.prototype={constructor:THREE.MaterialLoader,load:function(a,b){var c=this,d=new THREE.XHRLoader;d.setCrossOrigin(this.crossOrigin);d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new THREE[a.type];void 0!==a.color&&b.color.setHex(a.color);void 0!==a.ambient&&b.ambient.setHex(a.ambient);void 0!==a.emissive&&b.emissive.setHex(a.emissive);void 0!==a.specular&&b.specular.setHex(a.specular);void 0!==a.shininess&& -(b.shininess=a.shininess);void 0!==a.vertexColors&&(b.vertexColors=a.vertexColors);void 0!==a.blending&&(b.blending=a.blending);void 0!==a.opacity&&(b.opacity=a.opacity);void 0!==a.transparent&&(b.transparent=a.transparent);void 0!==a.wireframe&&(b.wireframe=a.wireframe);if(void 0!==a.materials)for(var c=0,d=a.materials.length;c<d;c++)b.materials.push(this.parse(a.materials[c]));return b}};THREE.ObjectLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; -THREE.ObjectLoader.prototype={constructor:THREE.ObjectLoader,load:function(a,b){var c=this,d=new THREE.XHRLoader(c.manager);d.setCrossOrigin(this.crossOrigin);d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=this.parseGeometries(a.geometries),c=this.parseMaterials(a.materials);return this.parseObject(a.object,b,c)},parseGeometries:function(a){var b={};if(void 0!==a)for(var c=new THREE.JSONLoader,d=new THREE.BufferGeometryLoader, -e=0,f=a.length;e<f;e++){var h,g=a[e];switch(g.type){case "PlaneGeometry":h=new THREE.PlaneGeometry(g.width,g.height,g.widthSegments,g.heightSegments);break;case "CircleGeometry":h=new THREE.CircleGeometry(g.radius,g.segments);break;case "CubeGeometry":h=new THREE.CubeGeometry(g.width,g.height,g.depth,g.widthSegments,g.heightSegments,g.depthSegments);break;case "CylinderGeometry":h=new THREE.CylinderGeometry(g.radiusTop,g.radiusBottom,g.height,g.radiusSegments,g.heightSegments,g.openEnded);break;case "SphereGeometry":h= -new THREE.SphereGeometry(g.radius,g.widthSegments,g.heightSegments,g.phiStart,g.phiLength,g.thetaStart,g.thetaLength);break;case "IcosahedronGeometry":h=new THREE.IcosahedronGeometry(g.radius,g.detail);break;case "TorusGeometry":h=new THREE.TorusGeometry(g.radius,g.tube,g.radialSegments,g.tubularSegments,g.arc);break;case "TorusKnotGeometry":h=new THREE.TorusKnotGeometry(g.radius,g.tube,g.radialSegments,g.tubularSegments,g.p,g.q,g.heightScale);break;case "BufferGeometry":h=d.parse(g.data);break;case "Geometry":h= -c.parse(g.data).geometry}h.uuid=g.uuid;void 0!==g.name&&(h.name=g.name);b[g.uuid]=h}return b},parseMaterials:function(a){var b={};if(void 0!==a)for(var c=new THREE.MaterialLoader,d=0,e=a.length;d<e;d++){var f=a[d],h=c.parse(f);h.uuid=f.uuid;void 0!==f.name&&(h.name=f.name);b[f.uuid]=h}return b},parseObject:function(){var a=new THREE.Matrix4;return function(b,c,d){var e;switch(b.type){case "Scene":e=new THREE.Scene;break;case "PerspectiveCamera":e=new THREE.PerspectiveCamera(b.fov,b.aspect,b.near, -b.far);break;case "OrthographicCamera":e=new THREE.OrthographicCamera(b.left,b.right,b.top,b.bottom,b.near,b.far);break;case "AmbientLight":e=new THREE.AmbientLight(b.color);break;case "DirectionalLight":e=new THREE.DirectionalLight(b.color,b.intensity);break;case "PointLight":e=new THREE.PointLight(b.color,b.intensity,b.distance);break;case "SpotLight":e=new THREE.SpotLight(b.color,b.intensity,b.distance,b.angle,b.exponent);break;case "HemisphereLight":e=new THREE.HemisphereLight(b.color,b.groundColor, -b.intensity);break;case "Mesh":e=c[b.geometry];var f=d[b.material];void 0===e&&console.error("THREE.ObjectLoader: Undefined geometry "+b.geometry);void 0===f&&console.error("THREE.ObjectLoader: Undefined material "+b.material);e=new THREE.Mesh(e,f);break;default:e=new THREE.Object3D}e.uuid=b.uuid;void 0!==b.name&&(e.name=b.name);void 0!==b.matrix?(a.fromArray(b.matrix),a.decompose(e.position,e.quaternion,e.scale)):(void 0!==b.position&&e.position.fromArray(b.position),void 0!==b.rotation&&e.rotation.fromArray(b.rotation), -void 0!==b.scale&&e.scale.fromArray(b.scale));void 0!==b.visible&&(e.visible=b.visible);void 0!==b.userData&&(e.userData=b.userData);if(void 0!==b.children)for(var h in b.children)e.add(this.parseObject(b.children[h],c,d));return e}}()};THREE.SceneLoader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){};this.callbackSync=function(){};this.callbackProgress=function(){};this.geometryHandlers={};this.hierarchyHandlers={};this.addGeometryHandler("ascii",THREE.JSONLoader)}; -THREE.SceneLoader.prototype={constructor:THREE.SceneLoader,load:function(a,b){var c=this,d=new THREE.XHRLoader(c.manager);d.setCrossOrigin(this.crossOrigin);d.load(a,function(d){c.parse(JSON.parse(d),b,a)})},setCrossOrigin:function(a){this.crossOrigin=a},addGeometryHandler:function(a,b){this.geometryHandlers[a]={loaderClass:b}},addHierarchyHandler:function(a,b){this.hierarchyHandlers[a]={loaderClass:b}},parse:function(a,b,c){function d(a,b){return"relativeToHTML"==b?a:p+"/"+a}function e(){f(A.scene, -C.objects)}function f(a,b){var c,e,h,i,k,m,p;for(p in b){var r=A.objects[p],q=b[p];if(void 0===r){if(q.type&&q.type in l.hierarchyHandlers){if(void 0===q.loading){e={type:1,url:1,material:1,position:1,rotation:1,scale:1,visible:1,children:1,userData:1,skin:1,morph:1,mirroredLoop:1,duration:1};h={};for(var B in q)B in e||(h[B]=q[B]);t=A.materials[q.material];q.loading=!0;e=l.hierarchyHandlers[q.type].loaderObject;e.options?e.load(d(q.url,C.urlBaseType),g(p,a,t,q)):e.load(d(q.url,C.urlBaseType),g(p, -a,t,q),h)}}else if(void 0!==q.geometry){if(s=A.geometries[q.geometry]){r=!1;t=A.materials[q.material];r=t instanceof THREE.ShaderMaterial;h=q.position;i=q.rotation;k=q.scale;c=q.matrix;m=q.quaternion;q.material||(t=new THREE.MeshFaceMaterial(A.face_materials[q.geometry]));t instanceof THREE.MeshFaceMaterial&&0===t.materials.length&&(t=new THREE.MeshFaceMaterial(A.face_materials[q.geometry]));if(t instanceof THREE.MeshFaceMaterial)for(e=0;e<t.materials.length;e++)r=r||t.materials[e]instanceof THREE.ShaderMaterial; -r&&s.computeTangents();q.skin?r=new THREE.SkinnedMesh(s,t):q.morph?(r=new THREE.MorphAnimMesh(s,t),void 0!==q.duration&&(r.duration=q.duration),void 0!==q.time&&(r.time=q.time),void 0!==q.mirroredLoop&&(r.mirroredLoop=q.mirroredLoop),t.morphNormals&&s.computeMorphNormals()):r=new THREE.Mesh(s,t);r.name=p;c?(r.matrixAutoUpdate=!1,r.matrix.set(c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11],c[12],c[13],c[14],c[15])):(r.position.fromArray(h),m?r.quaternion.fromArray(m):r.rotation.fromArray(i), -r.scale.fromArray(k));r.visible=q.visible;r.castShadow=q.castShadow;r.receiveShadow=q.receiveShadow;a.add(r);A.objects[p]=r}}else"DirectionalLight"===q.type||"PointLight"===q.type||"AmbientLight"===q.type?(w=void 0!==q.color?q.color:16777215,z=void 0!==q.intensity?q.intensity:1,"DirectionalLight"===q.type?(h=q.direction,u=new THREE.DirectionalLight(w,z),u.position.fromArray(h),q.target&&(O.push({object:u,targetName:q.target}),u.target=null)):"PointLight"===q.type?(h=q.position,e=q.distance,u=new THREE.PointLight(w, -z,e),u.position.fromArray(h)):"AmbientLight"===q.type&&(u=new THREE.AmbientLight(w)),a.add(u),u.name=p,A.lights[p]=u,A.objects[p]=u):"PerspectiveCamera"===q.type||"OrthographicCamera"===q.type?(h=q.position,i=q.rotation,m=q.quaternion,"PerspectiveCamera"===q.type?n=new THREE.PerspectiveCamera(q.fov,q.aspect,q.near,q.far):"OrthographicCamera"===q.type&&(n=new THREE.OrthographicCamera(q.left,q.right,q.top,q.bottom,q.near,q.far)),n.name=p,n.position.fromArray(h),void 0!==m?n.quaternion.fromArray(m): -void 0!==i&&n.rotation.fromArray(i),a.add(n),A.cameras[p]=n,A.objects[p]=n):(h=q.position,i=q.rotation,k=q.scale,m=q.quaternion,r=new THREE.Object3D,r.name=p,r.position.fromArray(h),m?r.quaternion.fromArray(m):r.rotation.fromArray(i),r.scale.fromArray(k),r.visible=void 0!==q.visible?q.visible:!1,a.add(r),A.objects[p]=r,A.empties[p]=r);if(r){if(void 0!==q.userData)for(var D in q.userData)r.userData[D]=q.userData[D];if(void 0!==q.groups)for(e=0;e<q.groups.length;e++)h=q.groups[e],void 0===A.groups[h]&& -(A.groups[h]=[]),A.groups[h].push(p)}}void 0!==r&&void 0!==q.children&&f(r,q.children)}}function h(a){return function(b,c){b.name=a;A.geometries[a]=b;A.face_materials[a]=c;e();B-=1;l.onLoadComplete();k()}}function g(a,b,c,d){return function(f){var f=f.content?f.content:f.dae?f.scene:f,h=d.rotation,g=d.quaternion,i=d.scale;f.position.fromArray(d.position);g?f.quaternion.fromArray(g):f.rotation.fromArray(h);f.scale.fromArray(i);c&&f.traverse(function(a){a.material=c});var m=void 0!==d.visible?d.visible: -!0;f.traverse(function(a){a.visible=m});b.add(f);f.name=a;A.objects[a]=f;e();B-=1;l.onLoadComplete();k()}}function i(a){return function(b,c){b.name=a;A.geometries[a]=b;A.face_materials[a]=c}}function k(){l.callbackProgress({totalModels:x,totalTextures:F,loadedModels:x-B,loadedTextures:F-D},A);l.onLoadProgress();if(0===B&&0===D){for(var a=0;a<O.length;a++){var c=O[a],d=A.objects[c.targetName];d?c.object.target=d:(c.object.target=new THREE.Object3D,A.scene.add(c.object.target));c.object.target.userData.targetInverse= -c.object}b(A)}}function m(a,b){b(a);if(void 0!==a.children)for(var c in a.children)m(a.children[c],b)}var l=this,p=THREE.Loader.prototype.extractUrlBase(c),s,t,n,r,q,u,w,z,B,D,x,F,A,O=[],C=a,E;for(E in this.geometryHandlers)a=this.geometryHandlers[E].loaderClass,this.geometryHandlers[E].loaderObject=new a;for(E in this.hierarchyHandlers)a=this.hierarchyHandlers[E].loaderClass,this.hierarchyHandlers[E].loaderObject=new a;D=B=0;A={scene:new THREE.Scene,geometries:{},face_materials:{},materials:{},textures:{}, -objects:{},cameras:{},lights:{},fogs:{},empties:{},groups:{}};if(C.transform&&(E=C.transform.position,a=C.transform.rotation,c=C.transform.scale,E&&A.scene.position.fromArray(E),a&&A.scene.rotation.fromArray(a),c&&A.scene.scale.fromArray(c),E||a||c))A.scene.updateMatrix(),A.scene.updateMatrixWorld();E=function(a){return function(){D-=a;k();l.onLoadComplete()}};for(var I in C.fogs)a=C.fogs[I],"linear"===a.type?r=new THREE.Fog(0,a.near,a.far):"exp2"===a.type&&(r=new THREE.FogExp2(0,a.density)),a=a.color, -r.color.setRGB(a[0],a[1],a[2]),A.fogs[I]=r;for(var y in C.geometries)r=C.geometries[y],r.type in this.geometryHandlers&&(B+=1,l.onLoadStart());for(var v in C.objects)m(C.objects[v],function(a){a.type&&a.type in l.hierarchyHandlers&&(B+=1,l.onLoadStart())});x=B;for(y in C.geometries)if(r=C.geometries[y],"cube"===r.type)s=new THREE.CubeGeometry(r.width,r.height,r.depth,r.widthSegments,r.heightSegments,r.depthSegments),s.name=y,A.geometries[y]=s;else if("plane"===r.type)s=new THREE.PlaneGeometry(r.width, -r.height,r.widthSegments,r.heightSegments),s.name=y,A.geometries[y]=s;else if("sphere"===r.type)s=new THREE.SphereGeometry(r.radius,r.widthSegments,r.heightSegments),s.name=y,A.geometries[y]=s;else if("cylinder"===r.type)s=new THREE.CylinderGeometry(r.topRad,r.botRad,r.height,r.radSegs,r.heightSegs),s.name=y,A.geometries[y]=s;else if("torus"===r.type)s=new THREE.TorusGeometry(r.radius,r.tube,r.segmentsR,r.segmentsT),s.name=y,A.geometries[y]=s;else if("icosahedron"===r.type)s=new THREE.IcosahedronGeometry(r.radius, -r.subdivisions),s.name=y,A.geometries[y]=s;else if(r.type in this.geometryHandlers){v={};for(q in r)"type"!==q&&"url"!==q&&(v[q]=r[q]);this.geometryHandlers[r.type].loaderObject.load(d(r.url,C.urlBaseType),h(y),v)}else"embedded"===r.type&&(v=C.embeds[r.id],v.metadata=C.metadata,v&&(v=this.geometryHandlers.ascii.loaderObject.parse(v,""),i(y)(v.geometry,v.materials)));for(var G in C.textures)if(y=C.textures[G],y.url instanceof Array){D+=y.url.length;for(q=0;q<y.url.length;q++)l.onLoadStart()}else D+= -1,l.onLoadStart();F=D;for(G in C.textures){y=C.textures[G];void 0!==y.mapping&&void 0!==THREE[y.mapping]&&(y.mapping=new THREE[y.mapping]);if(y.url instanceof Array){v=y.url.length;r=[];for(q=0;q<v;q++)r[q]=d(y.url[q],C.urlBaseType);q=(q=/\.dds$/i.test(r[0]))?THREE.ImageUtils.loadCompressedTextureCube(r,y.mapping,E(v)):THREE.ImageUtils.loadTextureCube(r,y.mapping,E(v))}else q=/\.dds$/i.test(y.url),v=d(y.url,C.urlBaseType),r=E(1),q=q?THREE.ImageUtils.loadCompressedTexture(v,y.mapping,r):THREE.ImageUtils.loadTexture(v, -y.mapping,r),void 0!==THREE[y.minFilter]&&(q.minFilter=THREE[y.minFilter]),void 0!==THREE[y.magFilter]&&(q.magFilter=THREE[y.magFilter]),y.anisotropy&&(q.anisotropy=y.anisotropy),y.repeat&&(q.repeat.set(y.repeat[0],y.repeat[1]),1!==y.repeat[0]&&(q.wrapS=THREE.RepeatWrapping),1!==y.repeat[1]&&(q.wrapT=THREE.RepeatWrapping)),y.offset&&q.offset.set(y.offset[0],y.offset[1]),y.wrap&&(v={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==v[y.wrap[0]]&&(q.wrapS=v[y.wrap[0]]),void 0!== -v[y.wrap[1]]&&(q.wrapT=v[y.wrap[1]]));A.textures[G]=q}var R,J;for(R in C.materials){G=C.materials[R];for(J in G.parameters)"envMap"===J||"map"===J||"lightMap"===J||"bumpMap"===J?G.parameters[J]=A.textures[G.parameters[J]]:"shading"===J?G.parameters[J]="flat"===G.parameters[J]?THREE.FlatShading:THREE.SmoothShading:"side"===J?G.parameters[J]="double"==G.parameters[J]?THREE.DoubleSide:"back"==G.parameters[J]?THREE.BackSide:THREE.FrontSide:"blending"===J?G.parameters[J]=G.parameters[J]in THREE?THREE[G.parameters[J]]: -THREE.NormalBlending:"combine"===J?G.parameters[J]=G.parameters[J]in THREE?THREE[G.parameters[J]]:THREE.MultiplyOperation:"vertexColors"===J?"face"==G.parameters[J]?G.parameters[J]=THREE.FaceColors:G.parameters[J]&&(G.parameters[J]=THREE.VertexColors):"wrapRGB"===J&&(E=G.parameters[J],G.parameters[J]=new THREE.Vector3(E[0],E[1],E[2]));void 0!==G.parameters.opacity&&1>G.parameters.opacity&&(G.parameters.transparent=!0);G.parameters.normalMap?(E=THREE.ShaderLib.normalmap,y=THREE.UniformsUtils.clone(E.uniforms), -q=G.parameters.color,v=G.parameters.specular,r=G.parameters.ambient,I=G.parameters.shininess,y.tNormal.value=A.textures[G.parameters.normalMap],G.parameters.normalScale&&y.uNormalScale.value.set(G.parameters.normalScale[0],G.parameters.normalScale[1]),G.parameters.map&&(y.tDiffuse.value=G.parameters.map,y.enableDiffuse.value=!0),G.parameters.envMap&&(y.tCube.value=G.parameters.envMap,y.enableReflection.value=!0,y.uReflectivity.value=G.parameters.reflectivity),G.parameters.lightMap&&(y.tAO.value=G.parameters.lightMap, -y.enableAO.value=!0),G.parameters.specularMap&&(y.tSpecular.value=A.textures[G.parameters.specularMap],y.enableSpecular.value=!0),G.parameters.displacementMap&&(y.tDisplacement.value=A.textures[G.parameters.displacementMap],y.enableDisplacement.value=!0,y.uDisplacementBias.value=G.parameters.displacementBias,y.uDisplacementScale.value=G.parameters.displacementScale),y.uDiffuseColor.value.setHex(q),y.uSpecularColor.value.setHex(v),y.uAmbientColor.value.setHex(r),y.uShininess.value=I,G.parameters.opacity&& -(y.uOpacity.value=G.parameters.opacity),t=new THREE.ShaderMaterial({fragmentShader:E.fragmentShader,vertexShader:E.vertexShader,uniforms:y,lights:!0,fog:!0})):t=new THREE[G.type](G.parameters);t.name=R;A.materials[R]=t}for(R in C.materials)if(G=C.materials[R],G.parameters.materials){J=[];for(q=0;q<G.parameters.materials.length;q++)J.push(A.materials[G.parameters.materials[q]]);A.materials[R].materials=J}e();A.cameras&&C.defaults.camera&&(A.currentCamera=A.cameras[C.defaults.camera]);A.fogs&&C.defaults.fog&& -(A.scene.fog=A.fogs[C.defaults.fog]);l.callbackSync(A);k()}};THREE.TextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};THREE.TextureLoader.prototype={constructor:THREE.TextureLoader,load:function(a,b){var c=new THREE.ImageLoader(this.manager);c.setCrossOrigin(this.crossOrigin);c.load(a,function(a){a=new THREE.Texture(a);a.needsUpdate=!0;void 0!==b&&b(a)})},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.Material=function(){this.id=THREE.MaterialIdCount++;this.uuid=THREE.Math.generateUUID();this.name="";this.side=THREE.FrontSide;this.opacity=1;this.transparent=!1;this.blending=THREE.NormalBlending;this.blendSrc=THREE.SrcAlphaFactor;this.blendDst=THREE.OneMinusSrcAlphaFactor;this.blendEquation=THREE.AddEquation;this.depthWrite=this.depthTest=!0;this.polygonOffset=!1;this.overdraw=this.alphaTest=this.polygonOffsetUnits=this.polygonOffsetFactor=0;this.needsUpdate=this.visible=!0}; -THREE.Material.prototype={constructor:THREE.Material,setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+b+"' parameter is undefined.");else if(b in this){var d=this[b];d instanceof THREE.Color?d.set(c):d instanceof THREE.Vector3&&c instanceof THREE.Vector3?d.copy(c):this[b]="overdraw"==b?Number(c):c}}},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent; -a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor=this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype); -THREE.MaterialIdCount=0;THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.LineDashedMaterial.prototype.clone=function(){var a=new THREE.LineDashedMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.scale=this.scale;a.dashSize=this.dashSize;a.gapSize=this.gapSize;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.envMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphTargets=this.skinning=!1;this.setValues(a)}; -THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.MeshBasicMaterial.prototype.clone=function(){var a=new THREE.MeshBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin= -this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;return a};THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap= -"round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading; -a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.metal=!1;this.perPixel=!0;this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.envMap=this.specularMap=null;this.combine=THREE.MultiplyOperation; -this.reflectivity=1;this.refractionRatio=0.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.ambient.copy(this.ambient);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.perPixel=this.perPixel;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale); -a.specularMap=this.specularMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.wireframe=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.shading=THREE.FlatShading;this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.materials=a instanceof Array?a:[]};THREE.MeshFaceMaterial.prototype.clone=function(){for(var a=new THREE.MeshFaceMaterial,b=0;b<this.materials.length;b++)a.materials.push(this.materials[b].clone());return a};THREE.ParticleSystemMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=!0;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.ParticleSystemMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.ParticleSystemMaterial.prototype.clone=function(){var a=new THREE.ParticleSystemMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.size=this.size;a.sizeAttenuation=this.sizeAttenuation;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.ParticleBasicMaterial=THREE.ParticleSystemMaterial;THREE.ShaderMaterial=function(a){THREE.Material.call(this);this.vertexShader=this.fragmentShader="void main() {}";this.uniforms={};this.defines={};this.attributes=null;this.shading=THREE.SmoothShading;this.linewidth=1;this.wireframe=!1;this.wireframeLinewidth=1;this.lights=this.fog=!1;this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv2:[0,0]};this.index0AttributeName="position";this.setValues(a)}; -THREE.ShaderMaterial.prototype=Object.create(THREE.Material.prototype); +c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners[a];if(void 0!==c){var d=c.indexOf(b);-1!==d&&c.splice(d,1)}}},dispatchEvent:function(a){if(void 0!==this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;for(var c=[],d=b.length,e=0;e<d;e++)c[e]=b[e];for(e=0;e<d;e++)c[e].call(this,a)}}}}; +(function(a){a.Raycaster=function(b,c,f,g){this.ray=new a.Ray(b,c);this.near=f||0;this.far=g||Infinity;this.params={Sprite:{},Mesh:{},PointCloud:{threshold:1},LOD:{},Line:{}}};var b=function(a,b){return a.distance-b.distance},c=function(a,b,f,g){a.raycast(b,f);if(!0===g){a=a.children;g=0;for(var h=a.length;g<h;g++)c(a[g],b,f,!0)}};a.Raycaster.prototype={constructor:a.Raycaster,precision:1E-4,linePrecision:1,set:function(a,b){this.ray.set(a,b)},setFromCamera:function(b,c){c instanceof a.PerspectiveCamera? +(this.ray.origin.copy(c.position),this.ray.direction.set(b.x,b.y,.5).unproject(c).sub(c.position).normalize()):c instanceof a.OrthographicCamera?(this.ray.origin.set(b.x,b.y,-1).unproject(c),this.ray.direction.set(0,0,-1).transformDirection(c.matrixWorld)):a.error("THREE.Raycaster: Unsupported camera type.")},intersectObject:function(a,e){var f=[];c(a,this,f,e);f.sort(b);return f},intersectObjects:function(d,e){var f=[];if(!1===d instanceof Array)return a.warn("THREE.Raycaster.intersectObjects: objects is not an Array."), +f;for(var g=0,h=d.length;g<h;g++)c(d[g],this,f,e);f.sort(b);return f}}})(THREE); +THREE.Object3D=function(){Object.defineProperty(this,"id",{value:THREE.Object3DIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Object3D";this.parent=void 0;this.children=[];this.up=THREE.Object3D.DefaultUp.clone();var a=new THREE.Vector3,b=new THREE.Euler,c=new THREE.Quaternion,d=new THREE.Vector3(1,1,1);b.onChange(function(){c.setFromEuler(b,!1)});c.onChange(function(){b.setFromQuaternion(c,void 0,!1)});Object.defineProperties(this,{position:{enumerable:!0,value:a},rotation:{enumerable:!0, +value:b},quaternion:{enumerable:!0,value:c},scale:{enumerable:!0,value:d}});this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixAutoUpdate=!0;this.matrixWorldNeedsUpdate=!1;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this.renderOrder=0;this.userData={}};THREE.Object3D.DefaultUp=new THREE.Vector3(0,1,0); +THREE.Object3D.prototype={constructor:THREE.Object3D,get eulerOrder(){THREE.warn("THREE.Object3D: .eulerOrder has been moved to .rotation.order.");return this.rotation.order},set eulerOrder(a){THREE.warn("THREE.Object3D: .eulerOrder has been moved to .rotation.order.");this.rotation.order=a},get useQuaternion(){THREE.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")},set useQuaternion(a){THREE.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")}, +applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix);this.matrix.decompose(this.position,this.quaternion,this.scale)},setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a,!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)},setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new THREE.Quaternion;return function(b,c){a.setFromAxisAngle(b, +c);this.quaternion.multiply(a);return this}}(),rotateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a=new THREE.Vector3(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.rotateOnAxis(a,b)}}(),translateOnAxis:function(){var a=new THREE.Vector3;return function(b,c){a.copy(b).applyQuaternion(this.quaternion);this.position.add(a.multiplyScalar(c)); +return this}}(),translate:function(a,b){THREE.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.");return this.translateOnAxis(b,a)},translateX:function(){var a=new THREE.Vector3(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a=new THREE.Vector3(0,1,0);return function(b){return this.translateOnAxis(a,b)}}(),translateZ:function(){var a=new THREE.Vector3(0,0,1);return function(b){return this.translateOnAxis(a, +b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new THREE.Matrix4;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new THREE.Matrix4;return function(b){a.lookAt(b,this.position,this.up);this.quaternion.setFromRotationMatrix(a)}}(),add:function(a){if(1<arguments.length){for(var b=0;b<arguments.length;b++)this.add(arguments[b]);return this}if(a===this)return THREE.error("THREE.Object3D.add: object can't be added as a child of itself.", +a),this;a instanceof THREE.Object3D?(void 0!==a.parent&&a.parent.remove(a),a.parent=this,a.dispatchEvent({type:"added"}),this.children.push(a)):THREE.error("THREE.Object3D.add: object not an instance of THREE.Object3D.",a);return this},remove:function(a){if(1<arguments.length)for(var b=0;b<arguments.length;b++)this.remove(arguments[b]);b=this.children.indexOf(a);-1!==b&&(a.parent=void 0,a.dispatchEvent({type:"removed"}),this.children.splice(b,1))},getChildByName:function(a){THREE.warn("THREE.Object3D: .getChildByName() has been renamed to .getObjectByName()."); +return this.getObjectByName(a)},getObjectById:function(a){return this.getObjectByProperty("id",a)},getObjectByName:function(a){return this.getObjectByProperty("name",a)},getObjectByProperty:function(a,b){if(this[a]===b)return this;for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c].getObjectByProperty(a,b);if(void 0!==e)return e}},getWorldPosition:function(a){a=a||new THREE.Vector3;this.updateMatrixWorld(!0);return a.setFromMatrixPosition(this.matrixWorld)},getWorldQuaternion:function(){var a= +new THREE.Vector3,b=new THREE.Vector3;return function(c){c=c||new THREE.Quaternion;this.updateMatrixWorld(!0);this.matrixWorld.decompose(a,c,b);return c}}(),getWorldRotation:function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Euler;this.getWorldQuaternion(a);return b.setFromQuaternion(a,this.rotation.order,!1)}}(),getWorldScale:function(){var a=new THREE.Vector3,b=new THREE.Quaternion;return function(c){c=c||new THREE.Vector3;this.updateMatrixWorld(!0);this.matrixWorld.decompose(a, +b,c);return c}}(),getWorldDirection:function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,1).applyQuaternion(a)}}(),raycast:function(){},traverse:function(a){a(this);for(var b=0,c=this.children.length;b<c;b++)this.children[b].traverse(a)},traverseVisible:function(a){if(!1!==this.visible){a(this);for(var b=0,c=this.children.length;b<c;b++)this.children[b].traverseVisible(a)}},traverseAncestors:function(a){this.parent&&(a(this.parent), +this.parent.traverseAncestors(a))},updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale);this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){!0===this.matrixAutoUpdate&&this.updateMatrix();if(!0===this.matrixWorldNeedsUpdate||!0===a)void 0===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)}, +toJSON:function(){var a={metadata:{version:4.3,type:"Object",generator:"ObjectExporter"}},b={},c={},d=function(b){void 0===a.materials&&(a.materials=[]);if(void 0===c[b.uuid]){var d=b.toJSON();delete d.metadata;c[b.uuid]=d;a.materials.push(d)}return b.uuid},e=function(c){var g={};g.uuid=c.uuid;g.type=c.type;""!==c.name&&(g.name=c.name);"{}"!==JSON.stringify(c.userData)&&(g.userData=c.userData);!0!==c.visible&&(g.visible=c.visible);if(c instanceof THREE.PerspectiveCamera)g.fov=c.fov,g.aspect=c.aspect, +g.near=c.near,g.far=c.far;else if(c instanceof THREE.OrthographicCamera)g.left=c.left,g.right=c.right,g.top=c.top,g.bottom=c.bottom,g.near=c.near,g.far=c.far;else if(c instanceof THREE.AmbientLight)g.color=c.color.getHex();else if(c instanceof THREE.DirectionalLight)g.color=c.color.getHex(),g.intensity=c.intensity;else if(c instanceof THREE.PointLight)g.color=c.color.getHex(),g.intensity=c.intensity,g.distance=c.distance,g.decay=c.decay;else if(c instanceof THREE.SpotLight)g.color=c.color.getHex(), +g.intensity=c.intensity,g.distance=c.distance,g.angle=c.angle,g.exponent=c.exponent,g.decay=c.decay;else if(c instanceof THREE.HemisphereLight)g.color=c.color.getHex(),g.groundColor=c.groundColor.getHex();else if(c instanceof THREE.Mesh||c instanceof THREE.Line||c instanceof THREE.PointCloud){var h=c.geometry;void 0===a.geometries&&(a.geometries=[]);if(void 0===b[h.uuid]){var k=h.toJSON();delete k.metadata;b[h.uuid]=k;a.geometries.push(k)}g.geometry=h.uuid;g.material=d(c.material);c instanceof THREE.Line&& +(g.mode=c.mode)}else c instanceof THREE.Sprite&&(g.material=d(c.material));g.matrix=c.matrix.toArray();if(0<c.children.length)for(g.children=[],h=0;h<c.children.length;h++)g.children.push(e(c.children[h]));return g};a.object=e(this);return a},clone:function(a,b){void 0===a&&(a=new THREE.Object3D);void 0===b&&(b=!0);a.name=this.name;a.up.copy(this.up);a.position.copy(this.position);a.quaternion.copy(this.quaternion);a.scale.copy(this.scale);a.rotationAutoUpdate=this.rotationAutoUpdate;a.matrix.copy(this.matrix); +a.matrixWorld.copy(this.matrixWorld);a.matrixAutoUpdate=this.matrixAutoUpdate;a.matrixWorldNeedsUpdate=this.matrixWorldNeedsUpdate;a.visible=this.visible;a.castShadow=this.castShadow;a.receiveShadow=this.receiveShadow;a.frustumCulled=this.frustumCulled;a.userData=JSON.parse(JSON.stringify(this.userData));if(!0===b)for(var c=0;c<this.children.length;c++)a.add(this.children[c].clone());return a}};THREE.EventDispatcher.prototype.apply(THREE.Object3D.prototype);THREE.Object3DIdCount=0; +THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0}; +THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.materialIndex=this.materialIndex;for(var b=0,c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();b=0;for(c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();b=0;for(c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone();return a}}; +THREE.Face4=function(a,b,c,d,e,f,g){THREE.warn("THREE.Face4 has been removed. A THREE.Face3 will be created instead.");return new THREE.Face3(a,b,c,e,f,g)};THREE.BufferAttribute=function(a,b){this.array=a;this.itemSize=b;this.needsUpdate=!1}; +THREE.BufferAttribute.prototype={constructor:THREE.BufferAttribute,get length(){return this.array.length},copyAt:function(a,b,c){a*=this.itemSize;c*=b.itemSize;for(var d=0,e=this.itemSize;d<e;d++)this.array[a+d]=b.array[c+d];return this},set:function(a,b){void 0===b&&(b=0);this.array.set(a,b);return this},setX:function(a,b){this.array[a*this.itemSize]=b;return this},setY:function(a,b){this.array[a*this.itemSize+1]=b;return this},setZ:function(a,b){this.array[a*this.itemSize+2]=b;return this},setXY:function(a, +b,c){a*=this.itemSize;this.array[a]=b;this.array[a+1]=c;return this},setXYZ:function(a,b,c,d){a*=this.itemSize;this.array[a]=b;this.array[a+1]=c;this.array[a+2]=d;return this},setXYZW:function(a,b,c,d,e){a*=this.itemSize;this.array[a]=b;this.array[a+1]=c;this.array[a+2]=d;this.array[a+3]=e;return this},clone:function(){return new THREE.BufferAttribute(new this.array.constructor(this.array),this.itemSize)}}; +THREE.Int8Attribute=function(a,b){THREE.warn("THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)};THREE.Uint8Attribute=function(a,b){THREE.warn("THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)}; +THREE.Uint8ClampedAttribute=function(a,b){THREE.warn("THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)};THREE.Int16Attribute=function(a,b){THREE.warn("THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)}; +THREE.Uint16Attribute=function(a,b){THREE.warn("THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)};THREE.Int32Attribute=function(a,b){THREE.warn("THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)}; +THREE.Uint32Attribute=function(a,b){THREE.warn("THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)};THREE.Float32Attribute=function(a,b){THREE.warn("THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)}; +THREE.Float64Attribute=function(a,b){THREE.warn("THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.");return new THREE.BufferAttribute(a,b)};THREE.DynamicBufferAttribute=function(a,b){THREE.BufferAttribute.call(this,a,b);this.updateRange={offset:0,count:-1}};THREE.DynamicBufferAttribute.prototype=Object.create(THREE.BufferAttribute.prototype);THREE.DynamicBufferAttribute.prototype.constructor=THREE.DynamicBufferAttribute; +THREE.DynamicBufferAttribute.prototype.clone=function(){return new THREE.DynamicBufferAttribute(new this.array.constructor(this.array),this.itemSize)};THREE.BufferGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="BufferGeometry";this.attributes={};this.attributesKeys=[];this.offsets=this.drawcalls=[];this.boundingSphere=this.boundingBox=null}; +THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,addAttribute:function(a,b,c){!1===b instanceof THREE.BufferAttribute?(THREE.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.attributes[a]={array:b,itemSize:c}):(this.attributes[a]=b,this.attributesKeys=Object.keys(this.attributes))},getAttribute:function(a){return this.attributes[a]},addDrawCall:function(a,b,c){this.drawcalls.push({start:a,count:b,index:void 0!==c?c:0})},applyMatrix:function(a){var b= +this.attributes.position;void 0!==b&&(a.applyToVector3Array(b.array),b.needsUpdate=!0);b=this.attributes.normal;void 0!==b&&((new THREE.Matrix3).getNormalMatrix(a).applyToVector3Array(b.array),b.needsUpdate=!0);null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere()},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},fromGeometry:function(a,b){b=b||{vertexColors:THREE.NoColors}; +var c=a.vertices,d=a.faces,e=a.faceVertexUvs,f=b.vertexColors,g=0<e[0].length,h=3==d[0].vertexNormals.length,k=new Float32Array(9*d.length);this.addAttribute("position",new THREE.BufferAttribute(k,3));var l=new Float32Array(9*d.length);this.addAttribute("normal",new THREE.BufferAttribute(l,3));if(f!==THREE.NoColors){var p=new Float32Array(9*d.length);this.addAttribute("color",new THREE.BufferAttribute(p,3))}if(!0===g){var q=new Float32Array(6*d.length);this.addAttribute("uv",new THREE.BufferAttribute(q, +2))}for(var n=0,t=0,r=0;n<d.length;n++,t+=6,r+=9){var s=d[n],u=c[s.a],v=c[s.b],x=c[s.c];k[r]=u.x;k[r+1]=u.y;k[r+2]=u.z;k[r+3]=v.x;k[r+4]=v.y;k[r+5]=v.z;k[r+6]=x.x;k[r+7]=x.y;k[r+8]=x.z;!0===h?(u=s.vertexNormals[0],v=s.vertexNormals[1],x=s.vertexNormals[2],l[r]=u.x,l[r+1]=u.y,l[r+2]=u.z,l[r+3]=v.x,l[r+4]=v.y,l[r+5]=v.z,l[r+6]=x.x,l[r+7]=x.y,l[r+8]=x.z):(u=s.normal,l[r]=u.x,l[r+1]=u.y,l[r+2]=u.z,l[r+3]=u.x,l[r+4]=u.y,l[r+5]=u.z,l[r+6]=u.x,l[r+7]=u.y,l[r+8]=u.z);f===THREE.FaceColors?(s=s.color,p[r]= +s.r,p[r+1]=s.g,p[r+2]=s.b,p[r+3]=s.r,p[r+4]=s.g,p[r+5]=s.b,p[r+6]=s.r,p[r+7]=s.g,p[r+8]=s.b):f===THREE.VertexColors&&(u=s.vertexColors[0],v=s.vertexColors[1],s=s.vertexColors[2],p[r]=u.r,p[r+1]=u.g,p[r+2]=u.b,p[r+3]=v.r,p[r+4]=v.g,p[r+5]=v.b,p[r+6]=s.r,p[r+7]=s.g,p[r+8]=s.b);!0===g&&(s=e[0][n][0],u=e[0][n][1],v=e[0][n][2],q[t]=s.x,q[t+1]=s.y,q[t+2]=u.x,q[t+3]=u.y,q[t+4]=v.x,q[t+5]=v.y)}this.computeBoundingSphere();return this},computeBoundingBox:function(){var a=new THREE.Vector3;return function(){null=== +this.boundingBox&&(this.boundingBox=new THREE.Box3);var b=this.attributes.position.array;if(b){var c=this.boundingBox;c.makeEmpty();for(var d=0,e=b.length;d<e;d+=3)a.set(b[d],b[d+1],b[d+2]),c.expandByPoint(a)}if(void 0===b||0===b.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0);(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&THREE.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.')}}(), +computeBoundingSphere:function(){var a=new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,e=0,f=c.length;e<f;e+=3)b.set(c[e],c[e+1],c[e+2]),a.expandByPoint(b);a.center(d);for(var g=0,e=0,f=c.length;e<f;e+=3)b.set(c[e],c[e+1],c[e+2]),g=Math.max(g,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(g);isNaN(this.boundingSphere.radius)&& +THREE.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.')}}}(),computeFaceNormals:function(){},computeVertexNormals:function(){var a=this.attributes;if(a.position){var b=a.position.array;if(void 0===a.normal)this.addAttribute("normal",new THREE.BufferAttribute(new Float32Array(b.length),3));else for(var c=a.normal.array,d=0,e=c.length;d<e;d++)c[d]=0;var c=a.normal.array,f,g,h,k=new THREE.Vector3,l=new THREE.Vector3, +p=new THREE.Vector3,q=new THREE.Vector3,n=new THREE.Vector3;if(a.index)for(var t=a.index.array,r=0<this.offsets.length?this.offsets:[{start:0,count:t.length,index:0}],s=0,u=r.length;s<u;++s){e=r[s].start;f=r[s].count;for(var v=r[s].index,d=e,e=e+f;d<e;d+=3)f=3*(v+t[d]),g=3*(v+t[d+1]),h=3*(v+t[d+2]),k.fromArray(b,f),l.fromArray(b,g),p.fromArray(b,h),q.subVectors(p,l),n.subVectors(k,l),q.cross(n),c[f]+=q.x,c[f+1]+=q.y,c[f+2]+=q.z,c[g]+=q.x,c[g+1]+=q.y,c[g+2]+=q.z,c[h]+=q.x,c[h+1]+=q.y,c[h+2]+=q.z}else for(d= +0,e=b.length;d<e;d+=9)k.fromArray(b,d),l.fromArray(b,d+3),p.fromArray(b,d+6),q.subVectors(p,l),n.subVectors(k,l),q.cross(n),c[d]=q.x,c[d+1]=q.y,c[d+2]=q.z,c[d+3]=q.x,c[d+4]=q.y,c[d+5]=q.z,c[d+6]=q.x,c[d+7]=q.y,c[d+8]=q.z;this.normalizeNormals();a.normal.needsUpdate=!0}},computeTangents:function(){function a(a,b,c){q.fromArray(d,3*a);n.fromArray(d,3*b);t.fromArray(d,3*c);r.fromArray(f,2*a);s.fromArray(f,2*b);u.fromArray(f,2*c);v=n.x-q.x;x=t.x-q.x;D=n.y-q.y;w=t.y-q.y;y=n.z-q.z;A=t.z-q.z;E=s.x-r.x;G= +u.x-r.x;F=s.y-r.y;z=u.y-r.y;I=1/(E*z-G*F);U.set((z*v-F*x)*I,(z*D-F*w)*I,(z*y-F*A)*I);M.set((E*x-G*v)*I,(E*w-G*D)*I,(E*A-G*y)*I);k[a].add(U);k[b].add(U);k[c].add(U);l[a].add(M);l[b].add(M);l[c].add(M)}function b(a){ha.fromArray(e,3*a);O.copy(ha);ba=k[a];oa.copy(ba);oa.sub(ha.multiplyScalar(ha.dot(ba))).normalize();ja.crossVectors(O,ba);qa=ja.dot(l[a]);ca=0>qa?-1:1;h[4*a]=oa.x;h[4*a+1]=oa.y;h[4*a+2]=oa.z;h[4*a+3]=ca}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal|| +void 0===this.attributes.uv)THREE.warn("THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array,e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],l=[],p=0;p<g;p++)k[p]=new THREE.Vector3, +l[p]=new THREE.Vector3;var q=new THREE.Vector3,n=new THREE.Vector3,t=new THREE.Vector3,r=new THREE.Vector2,s=new THREE.Vector2,u=new THREE.Vector2,v,x,D,w,y,A,E,G,F,z,I,U=new THREE.Vector3,M=new THREE.Vector3,H,L,P,N,R;0===this.drawcalls.length&&this.addDrawCall(0,c.length,0);var V=this.drawcalls,p=0;for(L=V.length;p<L;++p){H=V[p].start;P=V[p].count;var J=V[p].index,g=H;for(H+=P;g<H;g+=3)P=J+c[g],N=J+c[g+1],R=J+c[g+2],a(P,N,R)}var oa=new THREE.Vector3,ja=new THREE.Vector3,ha=new THREE.Vector3,O=new THREE.Vector3, +ca,ba,qa,p=0;for(L=V.length;p<L;++p)for(H=V[p].start,P=V[p].count,J=V[p].index,g=H,H+=P;g<H;g+=3)P=J+c[g],N=J+c[g+1],R=J+c[g+2],b(P),b(N),b(R)}},computeOffsets:function(a){void 0===a&&(a=65535);for(var b=this.attributes.index.array,c=this.attributes.position.array,d=b.length/3,e=new Uint16Array(b.length),f=0,g=0,h=[{start:0,count:0,index:0}],k=h[0],l=0,p=0,q=new Int32Array(6),n=new Int32Array(c.length),t=new Int32Array(c.length),r=0;r<c.length;r++)n[r]=-1,t[r]=-1;for(c=0;c<d;c++){for(var s=p=0;3> +s;s++)r=b[3*c+s],-1==n[r]?(q[2*s]=r,q[2*s+1]=-1,p++):n[r]<k.index?(q[2*s]=r,q[2*s+1]=-1,l++):(q[2*s]=r,q[2*s+1]=n[r]);if(g+p>k.index+a)for(k={start:f,count:0,index:g},h.push(k),p=0;6>p;p+=2)s=q[p+1],-1<s&&s<k.index&&(q[p+1]=-1);for(p=0;6>p;p+=2)r=q[p],s=q[p+1],-1===s&&(s=g++),n[r]=s,t[s]=r,e[f++]=s-k.index,k.count++}this.reorderBuffers(e,t,g);return this.drawcalls=this.offsets=h},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)THREE.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.", +a);else{void 0===b&&(b=0);var c=this.attributes,d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,f=a.attributes[d],g=f.array,h=0,f=f.itemSize*b;h<g.length;h++,f++)e[f]=g[h];return this}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},reorderBuffers:function(a,b,c){var d={},e;for(e in this.attributes)"index"!=e&&(d[e]=new this.attributes[e].array.constructor(this.attributes[e].itemSize* +c));for(var f=0;f<c;f++){var g=b[f];for(e in this.attributes)if("index"!=e)for(var h=this.attributes[e].array,k=this.attributes[e].itemSize,l=d[e],p=0;p<k;p++)l[f*k+p]=h[g*k+p]}this.attributes.index.array=a;for(e in this.attributes)"index"!=e&&(this.attributes[e].array=d[e],this.attributes[e].numItems=this.attributes[e].itemSize*c)},toJSON:function(){var a={metadata:{version:4,type:"BufferGeometry",generator:"BufferGeometryExporter"},uuid:this.uuid,type:this.type,data:{attributes:{}}},b=this.attributes, +c=this.offsets,d=this.boundingSphere,e;for(e in b){var f=b[e],g=Array.prototype.slice.call(f.array);a.data.attributes[e]={itemSize:f.itemSize,type:f.array.constructor.name,array:g}}0<c.length&&(a.data.offsets=JSON.parse(JSON.stringify(c)));null!==d&&(a.data.boundingSphere={center:d.center.toArray(),radius:d.radius});return a},clone:function(){var a=new THREE.BufferGeometry,b;for(b in this.attributes)a.addAttribute(b,this.attributes[b].clone());b=0;for(var c=this.offsets.length;b<c;b++){var d=this.offsets[b]; +a.offsets.push({start:d.start,index:d.index,count:d.count})}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype); +THREE.Geometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Geometry";this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.hasTangents=!1;this.dynamic=!0;this.groupsNeedUpdate=this.lineDistancesNeedUpdate=this.colorsNeedUpdate= +this.tangentsNeedUpdate=this.normalsNeedUpdate=this.uvsNeedUpdate=this.elementsNeedUpdate=this.verticesNeedUpdate=!1}; +THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){a=this.faces[c];a.normal.applyMatrix3(b).normalize();for(var e=0,f=a.vertexNormals.length;e<f;e++)a.vertexNormals[e].applyMatrix3(b).normalize()}null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();this.normalsNeedUpdate= +this.verticesNeedUpdate=!0},fromBufferGeometry:function(a){for(var b=this,c=a.attributes,d=c.position.array,e=void 0!==c.index?c.index.array:void 0,f=void 0!==c.normal?c.normal.array:void 0,g=void 0!==c.color?c.color.array:void 0,h=void 0!==c.uv?c.uv.array:void 0,k=[],l=[],p=c=0;c<d.length;c+=3,p+=2)b.vertices.push(new THREE.Vector3(d[c],d[c+1],d[c+2])),void 0!==f&&k.push(new THREE.Vector3(f[c],f[c+1],f[c+2])),void 0!==g&&b.colors.push(new THREE.Color(g[c],g[c+1],g[c+2])),void 0!==h&&l.push(new THREE.Vector2(h[p], +h[p+1]));var q=function(a,c,d){var e=void 0!==f?[k[a].clone(),k[c].clone(),k[d].clone()]:[],n=void 0!==g?[b.colors[a].clone(),b.colors[c].clone(),b.colors[d].clone()]:[];b.faces.push(new THREE.Face3(a,c,d,e,n));void 0!==h&&b.faceVertexUvs[0].push([l[a].clone(),l[c].clone(),l[d].clone()])};if(void 0!==e)if(d=a.drawcalls,0<d.length)for(c=0;c<d.length;c++)for(var p=d[c],n=p.start,t=p.count,r=p.index,p=n,n=n+t;p<n;p+=3)q(r+e[p],r+e[p+1],r+e[p+2]);else for(c=0;c<e.length;c+=3)q(e[c],e[c+1],e[c+2]);else for(c= +0;c<d.length/3;c+=3)q(c,c+1,c+2);this.computeFaceNormals();null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],f=this.vertices[e.a], +g=this.vertices[e.b];a.subVectors(this.vertices[e.c],g);b.subVectors(f,g);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d;d=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)d[b]=new THREE.Vector3;if(a){var e,f,g,h=new THREE.Vector3,k=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=this.vertices[c.a],f=this.vertices[c.b],g=this.vertices[c.c],h.subVectors(g,f),k.subVectors(e,f),h.cross(k),d[c.a].add(h),d[c.b].add(h),d[c.c].add(h)}else for(a= +0,b=this.faces.length;a<b;a++)c=this.faces[a],d[c.a].add(c.normal),d[c.b].add(c.normal),d[c.c].add(c.normal);b=0;for(c=this.vertices.length;b<c;b++)d[b].normalize();a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],c.vertexNormals[0]=d[c.a].clone(),c.vertexNormals[1]=d[c.b].clone(),c.vertexNormals[2]=d[c.c].clone()},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++)for(e=this.faces[c],e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal= +e.normal.clone(),e.__originalVertexNormals||(e.__originalVertexNormals=[]),a=0,b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=e.vertexNormals[a].clone();var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];e=this.morphNormals[a].faceNormals;var g= +this.morphNormals[a].vertexNormals,h,k;c=0;for(d=this.faces.length;c<d;c++)h=new THREE.Vector3,k={a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3},e.push(h),g.push(k)}g=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;f.computeFaceNormals();f.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],h=g.faceNormals[c],k=g.vertexNormals[c],h.copy(e.normal),k.a.copy(e.vertexNormals[0]),k.b.copy(e.vertexNormals[1]),k.c.copy(e.vertexNormals[2])}c=0;for(d=this.faces.length;c< +d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){var a,b,c,d,e,f,g,h,k,l,p,q,n,t,r,s,u,v=[],x=[];c=new THREE.Vector3;var D=new THREE.Vector3,w=new THREE.Vector3,y=new THREE.Vector3,A=new THREE.Vector3;a=0;for(b=this.vertices.length;a<b;a++)v[a]=new THREE.Vector3,x[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)e=this.faces[a],f=this.faceVertexUvs[0][a],d=e.a,u=e.b,e=e.c,g=this.vertices[d],h=this.vertices[u],k=this.vertices[e], +l=f[0],p=f[1],q=f[2],f=h.x-g.x,n=k.x-g.x,t=h.y-g.y,r=k.y-g.y,h=h.z-g.z,g=k.z-g.z,k=p.x-l.x,s=q.x-l.x,p=p.y-l.y,l=q.y-l.y,q=1/(k*l-s*p),c.set((l*f-p*n)*q,(l*t-p*r)*q,(l*h-p*g)*q),D.set((k*n-s*f)*q,(k*r-s*t)*q,(k*g-s*h)*q),v[d].add(c),v[u].add(c),v[e].add(c),x[d].add(D),x[u].add(D),x[e].add(D);D=["a","b","c","d"];a=0;for(b=this.faces.length;a<b;a++)for(e=this.faces[a],c=0;c<Math.min(e.vertexNormals.length,3);c++)A.copy(e.vertexNormals[c]),d=e[D[c]],u=v[d],w.copy(u),w.sub(A.multiplyScalar(A.dot(u))).normalize(), +y.crossVectors(e.vertexNormals[c],u),d=y.dot(x[d]),d=0>d?-1:1,e.vertexTangents[c]=new THREE.Vector4(w.x,w.y,w.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere); +this.boundingSphere.setFromPoints(this.vertices)},merge:function(a,b,c){if(!1===a instanceof THREE.Geometry)THREE.error("THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.",a);else{var d,e=this.vertices.length,f=this.vertices,g=a.vertices,h=this.faces,k=a.faces,l=this.faceVertexUvs[0];a=a.faceVertexUvs[0];void 0===c&&(c=0);void 0!==b&&(d=(new THREE.Matrix3).getNormalMatrix(b));for(var p=0,q=g.length;p<q;p++){var n=g[p].clone();void 0!==b&&n.applyMatrix4(b);f.push(n)}p=0;for(q=k.length;p< +q;p++){var g=k[p],t,r=g.vertexNormals,s=g.vertexColors,n=new THREE.Face3(g.a+e,g.b+e,g.c+e);n.normal.copy(g.normal);void 0!==d&&n.normal.applyMatrix3(d).normalize();b=0;for(f=r.length;b<f;b++)t=r[b].clone(),void 0!==d&&t.applyMatrix3(d).normalize(),n.vertexNormals.push(t);n.color.copy(g.color);b=0;for(f=s.length;b<f;b++)t=s[b],n.vertexColors.push(t.clone());n.materialIndex=g.materialIndex+c;h.push(n)}p=0;for(q=a.length;p<q;p++)if(c=a[p],d=[],void 0!==c){b=0;for(f=c.length;b<f;b++)d.push(c[b].clone()); +l.push(d)}}},mergeMesh:function(a){!1===a instanceof THREE.Mesh?THREE.error("THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.",a):(a.matrixAutoUpdate&&a.updateMatrix(),this.merge(a.geometry,a.matrix))},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,4),f,g;f=0;for(g=this.vertices.length;f<g;f++)d=this.vertices[f],d=Math.round(d.x*e)+"_"+Math.round(d.y*e)+"_"+Math.round(d.z*e),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];a=[];f=0;for(g=this.faces.length;f< +g;f++)for(e=this.faces[f],e.a=c[e.a],e.b=c[e.b],e.c=c[e.c],e=[e.a,e.b,e.c],d=0;3>d;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;c<g;c++)this.faceVertexUvs[c].splice(e,1);f=this.vertices.length-b.length;this.vertices=b;return f},toJSON:function(){function a(a,b,c){return c?a|1<<b:a&~(1<<b)}function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void 0!==l[b])return l[b];l[b]=k.length/3;k.push(a.x,a.y, +a.z);return l[b]}function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void 0!==q[b])return q[b];q[b]=p.length;p.push(a.getHex());return q[b]}function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==t[b])return t[b];t[b]=n.length/2;n.push(a.x,a.y);return t[b]}var e={metadata:{version:4,type:"BufferGeometry",generator:"BufferGeometryExporter"},uuid:this.uuid,type:this.type};""!==this.name&&(e.name=this.name);if(void 0!==this.parameters){var f=this.parameters,g;for(g in f)void 0!== +f[g]&&(e[g]=f[g]);return e}f=[];for(g=0;g<this.vertices.length;g++){var h=this.vertices[g];f.push(h.x,h.y,h.z)}var h=[],k=[],l={},p=[],q={},n=[],t={};for(g=0;g<this.faces.length;g++){var r=this.faces[g],s=void 0!==this.faceVertexUvs[0][g],u=0<r.normal.length(),v=0<r.vertexNormals.length,x=1!==r.color.r||1!==r.color.g||1!==r.color.b,D=0<r.vertexColors.length,w=0,w=a(w,0,0),w=a(w,1,!1),w=a(w,2,!1),w=a(w,3,s),w=a(w,4,u),w=a(w,5,v),w=a(w,6,x),w=a(w,7,D);h.push(w);h.push(r.a,r.b,r.c);s&&(s=this.faceVertexUvs[0][g], +h.push(d(s[0]),d(s[1]),d(s[2])));u&&h.push(b(r.normal));v&&(u=r.vertexNormals,h.push(b(u[0]),b(u[1]),b(u[2])));x&&h.push(c(r.color));D&&(r=r.vertexColors,h.push(c(r[0]),c(r[1]),c(r[2])))}e.data={};e.data.vertices=f;e.data.normals=k;0<p.length&&(e.data.colors=p);0<n.length&&(e.data.uvs=[n]);e.data.faces=h;return e},clone:function(){for(var a=new THREE.Geometry,b=this.vertices,c=0,d=b.length;c<d;c++)a.vertices.push(b[c].clone());b=this.faces;c=0;for(d=b.length;c<d;c++)a.faces.push(b[c].clone());c=0; +for(d=this.faceVertexUvs.length;c<d;c++){b=this.faceVertexUvs[c];void 0===a.faceVertexUvs[c]&&(a.faceVertexUvs[c]=[]);for(var e=0,f=b.length;e<f;e++){for(var g=b[e],h=[],k=0,l=g.length;k<l;k++)h.push(g[k].clone());a.faceVertexUvs[c].push(h)}}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype);THREE.GeometryIdCount=0; +THREE.Camera=function(){THREE.Object3D.call(this);this.type="Camera";this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.constructor=THREE.Camera;THREE.Camera.prototype.getWorldDirection=function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,-1).applyQuaternion(a)}}(); +THREE.Camera.prototype.lookAt=function(){var a=new THREE.Matrix4;return function(b){a.lookAt(this.position,b,this.up);this.quaternion.setFromRotationMatrix(a)}}();THREE.Camera.prototype.clone=function(a){void 0===a&&(a=new THREE.Camera);THREE.Object3D.prototype.clone.call(this,a);a.matrixWorldInverse.copy(this.matrixWorldInverse);a.projectionMatrix.copy(this.projectionMatrix);return a}; +THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);this.type="CubeCamera";var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,1);f.lookAt(new THREE.Vector3(0,1,0));this.add(f);var g=new THREE.PerspectiveCamera(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new THREE.Vector3(0,-1,0)); +this.add(g);var h=new THREE.PerspectiveCamera(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new THREE.Vector3(0,0,1));this.add(h);var k=new THREE.PerspectiveCamera(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new THREE.Vector3(0,0,-1));this.add(k);this.renderTarget=new THREE.WebGLRenderTargetCube(c,c,{format:THREE.RGBFormat,magFilter:THREE.LinearFilter,minFilter:THREE.LinearFilter});this.updateCubeMap=function(a,b){var c=this.renderTarget,n=c.generateMipmaps;c.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace= +1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.generateMipmaps=n;c.activeCubeFace=5;a.render(b,k,c)}};THREE.CubeCamera.prototype=Object.create(THREE.Object3D.prototype);THREE.CubeCamera.prototype.constructor=THREE.CubeCamera; +THREE.OrthographicCamera=function(a,b,c,d,e,f){THREE.Camera.call(this);this.type="OrthographicCamera";this.zoom=1;this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=Object.create(THREE.Camera.prototype);THREE.OrthographicCamera.prototype.constructor=THREE.OrthographicCamera; +THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){var a=(this.right-this.left)/(2*this.zoom),b=(this.top-this.bottom)/(2*this.zoom),c=(this.right+this.left)/2,d=(this.top+this.bottom)/2;this.projectionMatrix.makeOrthographic(c-a,c+a,d+b,d-b,this.near,this.far)}; +THREE.OrthographicCamera.prototype.clone=function(){var a=new THREE.OrthographicCamera;THREE.Camera.prototype.clone.call(this,a);a.zoom=this.zoom;a.left=this.left;a.right=this.right;a.top=this.top;a.bottom=this.bottom;a.near=this.near;a.far=this.far;a.projectionMatrix.copy(this.projectionMatrix);return a}; +THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.type="PerspectiveCamera";this.zoom=1;this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:.1;this.far=void 0!==d?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=Object.create(THREE.Camera.prototype);THREE.PerspectiveCamera.prototype.constructor=THREE.PerspectiveCamera; +THREE.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);this.fov=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=e;this.height=f;this.updateProjectionMatrix()}; +THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){var a=THREE.Math.radToDeg(2*Math.atan(Math.tan(.5*THREE.Math.degToRad(this.fov))/this.zoom));if(this.fullWidth){var b=this.fullWidth/this.fullHeight,a=Math.tan(THREE.Math.degToRad(.5*a))*this.near,c=-a,d=b*c,b=Math.abs(b*a-d),c=Math.abs(a-c);this.projectionMatrix.makeFrustum(d+this.x*b/this.fullWidth,d+(this.x+this.width)*b/this.fullWidth,a-(this.y+this.height)*c/this.fullHeight,a-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(a, +this.aspect,this.near,this.far)};THREE.PerspectiveCamera.prototype.clone=function(){var a=new THREE.PerspectiveCamera;THREE.Camera.prototype.clone.call(this,a);a.zoom=this.zoom;a.fov=this.fov;a.aspect=this.aspect;a.near=this.near;a.far=this.far;a.projectionMatrix.copy(this.projectionMatrix);return a};THREE.Light=function(a){THREE.Object3D.call(this);this.type="Light";this.color=new THREE.Color(a)};THREE.Light.prototype=Object.create(THREE.Object3D.prototype);THREE.Light.prototype.constructor=THREE.Light; +THREE.Light.prototype.clone=function(a){void 0===a&&(a=new THREE.Light);THREE.Object3D.prototype.clone.call(this,a);a.color.copy(this.color);return a};THREE.AmbientLight=function(a){THREE.Light.call(this,a);this.type="AmbientLight"};THREE.AmbientLight.prototype=Object.create(THREE.Light.prototype);THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.AmbientLight.prototype.clone=function(){var a=new THREE.AmbientLight;THREE.Light.prototype.clone.call(this,a);return a}; +THREE.AreaLight=function(a,b){THREE.Light.call(this,a);this.type="AreaLight";this.normal=new THREE.Vector3(0,-1,0);this.right=new THREE.Vector3(1,0,0);this.intensity=void 0!==b?b:1;this.height=this.width=1;this.constantAttenuation=1.5;this.linearAttenuation=.5;this.quadraticAttenuation=.1};THREE.AreaLight.prototype=Object.create(THREE.Light.prototype);THREE.AreaLight.prototype.constructor=THREE.AreaLight; +THREE.DirectionalLight=function(a,b){THREE.Light.call(this,a);this.type="DirectionalLight";this.position.set(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=!1; +this.shadowCascadeOffset=new THREE.Vector3(0,0,-1E3);this.shadowCascadeCount=2;this.shadowCascadeBias=[0,0,0];this.shadowCascadeWidth=[512,512,512];this.shadowCascadeHeight=[512,512,512];this.shadowCascadeNearZ=[-1,.99,.998];this.shadowCascadeFarZ=[.99,.998,1];this.shadowCascadeArray=[];this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.DirectionalLight.prototype=Object.create(THREE.Light.prototype);THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight; +THREE.DirectionalLight.prototype.clone=function(){var a=new THREE.DirectionalLight;THREE.Light.prototype.clone.call(this,a);a.target=this.target.clone();a.intensity=this.intensity;a.castShadow=this.castShadow;a.onlyShadow=this.onlyShadow;a.shadowCameraNear=this.shadowCameraNear;a.shadowCameraFar=this.shadowCameraFar;a.shadowCameraLeft=this.shadowCameraLeft;a.shadowCameraRight=this.shadowCameraRight;a.shadowCameraTop=this.shadowCameraTop;a.shadowCameraBottom=this.shadowCameraBottom;a.shadowCameraVisible= +this.shadowCameraVisible;a.shadowBias=this.shadowBias;a.shadowDarkness=this.shadowDarkness;a.shadowMapWidth=this.shadowMapWidth;a.shadowMapHeight=this.shadowMapHeight;a.shadowCascade=this.shadowCascade;a.shadowCascadeOffset.copy(this.shadowCascadeOffset);a.shadowCascadeCount=this.shadowCascadeCount;a.shadowCascadeBias=this.shadowCascadeBias.slice(0);a.shadowCascadeWidth=this.shadowCascadeWidth.slice(0);a.shadowCascadeHeight=this.shadowCascadeHeight.slice(0);a.shadowCascadeNearZ=this.shadowCascadeNearZ.slice(0); +a.shadowCascadeFarZ=this.shadowCascadeFarZ.slice(0);return a};THREE.HemisphereLight=function(a,b,c){THREE.Light.call(this,a);this.type="HemisphereLight";this.position.set(0,100,0);this.groundColor=new THREE.Color(b);this.intensity=void 0!==c?c:1};THREE.HemisphereLight.prototype=Object.create(THREE.Light.prototype);THREE.HemisphereLight.prototype.constructor=THREE.HemisphereLight; +THREE.HemisphereLight.prototype.clone=function(){var a=new THREE.HemisphereLight;THREE.Light.prototype.clone.call(this,a);a.groundColor.copy(this.groundColor);a.intensity=this.intensity;return a};THREE.PointLight=function(a,b,c,d){THREE.Light.call(this,a);this.type="PointLight";this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.decay=void 0!==d?d:1};THREE.PointLight.prototype=Object.create(THREE.Light.prototype);THREE.PointLight.prototype.constructor=THREE.PointLight; +THREE.PointLight.prototype.clone=function(){var a=new THREE.PointLight;THREE.Light.prototype.clone.call(this,a);a.intensity=this.intensity;a.distance=this.distance;a.decay=this.decay;return a}; +THREE.SpotLight=function(a,b,c,d,e,f){THREE.Light.call(this,a);this.type="SpotLight";this.position.set(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/3;this.exponent=void 0!==e?e:10;this.decay=void 0!==f?f:1;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=.5;this.shadowMapHeight=this.shadowMapWidth= +512;this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.SpotLight.prototype=Object.create(THREE.Light.prototype);THREE.SpotLight.prototype.constructor=THREE.SpotLight; +THREE.SpotLight.prototype.clone=function(){var a=new THREE.SpotLight;THREE.Light.prototype.clone.call(this,a);a.target=this.target.clone();a.intensity=this.intensity;a.distance=this.distance;a.angle=this.angle;a.exponent=this.exponent;a.decay=this.decay;a.castShadow=this.castShadow;a.onlyShadow=this.onlyShadow;a.shadowCameraNear=this.shadowCameraNear;a.shadowCameraFar=this.shadowCameraFar;a.shadowCameraFov=this.shadowCameraFov;a.shadowCameraVisible=this.shadowCameraVisible;a.shadowBias=this.shadowBias; +a.shadowDarkness=this.shadowDarkness;a.shadowMapWidth=this.shadowMapWidth;a.shadowMapHeight=this.shadowMapHeight;return a};THREE.Cache={files:{},add:function(a,b){this.files[a]=b},get:function(a){return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}}; +THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.imageLoader=new THREE.ImageLoader;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}; +THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:void 0,addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/a.total).toFixed(0)+ +"%"):b+((a.loaded/1024).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");if(1===a.length)return"./";a.pop();return a.join("/")+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<a.length;++d)c[d]=this.createMaterial(a[d],b);return c},needsTangents:function(a){for(var b=0,c=a.length;b<c;b++)if(a[b]instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function d(a, +d,e,g,h,k,s){var u=b+e,v,x=THREE.Loader.Handlers.get(u);null!==x?v=x.load(u):(v=new THREE.Texture,x=f.imageLoader,x.crossOrigin=f.crossOrigin,x.load(u,function(a){if(!1===THREE.Math.isPowerOfTwo(a.width)||!1===THREE.Math.isPowerOfTwo(a.height)){var b=c(a.width),d=c(a.height),e=document.createElement("canvas");e.width=b;e.height=d;e.getContext("2d").drawImage(a,0,0,b,d);v.image=e}else v.image=a;v.needsUpdate=!0}));v.sourceFile=e;g&&(v.repeat.set(g[0],g[1]),1!==g[0]&&(v.wrapS=THREE.RepeatWrapping), +1!==g[1]&&(v.wrapT=THREE.RepeatWrapping));h&&v.offset.set(h[0],h[1]);k&&(e={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==e[k[0]]&&(v.wrapS=e[k[0]]),void 0!==e[k[1]]&&(v.wrapT=e[k[1]]));s&&(v.anisotropy=s);a[d]=v}function e(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var f=this,g="MeshLambertMaterial",h={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?g="MeshPhongMaterial": +"basic"===k&&(g="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(h.blending=THREE[a.blending]);void 0!==a.transparent&&(h.transparent=a.transparent);void 0!==a.opacity&&1>a.opacity&&(h.transparent=!0);void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe); +void 0!==a.vertexColors&&("face"===a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorEmissive&&(h.emissive=e(a.colorEmissive));void 0!==a.transparency&&(console.warn("THREE.Loader: transparency has been renamed to opacity"),a.opacity=a.transparency);void 0!==a.opacity&&(h.opacity=a.opacity);a.specularCoef&&(h.shininess= +a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap", +a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&&b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormalFactor&&(h.normalScale=new THREE.Vector2(a.mapNormalFactor,a.mapNormalFactor));g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}}; +THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;b<c;b+=2){var d=this.handlers[b+1];if(this.handlers[b].test(a))return d}return null}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; +THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);void 0!==f?b&&b(f):(f=new XMLHttpRequest,f.open("GET",a,!0),f.addEventListener("load",function(c){THREE.Cache.add(a,this.response);b&&b(this.response);e.manager.itemEnd(a)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),void 0!==this.responseType&&(f.responseType= +this.responseType),f.send(null),e.manager.itemStart(a))},setResponseType:function(a){this.responseType=a},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; +THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);if(void 0!==f)b(f);else return f=document.createElement("img"),f.addEventListener("load",function(c){THREE.Cache.add(a,this);b&&b(this);e.manager.itemEnd(a)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),f.src=a,e.manager.itemStart(a),f},setCrossOrigin:function(a){this.crossOrigin= +a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; +THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText),k=h.metadata;if(void 0!==k){if("object"===k.type){THREE.error("THREE.JSONLoader: "+b+" should be loaded with THREE.ObjectLoader instead.");return}if("scene"===k.type){THREE.error("THREE.JSONLoader: "+b+" seems to be a Scene. Use THREE.SceneLoader instead.");return}}h=a.parse(h, +d);c(h.geometry,h.materials)}else THREE.error("THREE.JSONLoader: "+b+" seems to be unreachable or the file is empty.");a.onLoadComplete()}else THREE.error("THREE.JSONLoader: Couldn't load "+b+" ("+f.status+")");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")),e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; +THREE.JSONLoader.prototype.parse=function(a,b){var c=new THREE.Geometry,d=void 0!==a.scale?1/a.scale:1;(function(b){var d,g,h,k,l,p,q,n,t,r,s,u,v,x=a.faces;p=a.vertices;var D=a.normals,w=a.colors,y=0;if(void 0!==a.uvs){for(d=0;d<a.uvs.length;d++)a.uvs[d].length&&y++;for(d=0;d<y;d++)c.faceVertexUvs[d]=[]}k=0;for(l=p.length;k<l;)d=new THREE.Vector3,d.x=p[k++]*b,d.y=p[k++]*b,d.z=p[k++]*b,c.vertices.push(d);k=0;for(l=x.length;k<l;)if(b=x[k++],t=b&1,h=b&2,d=b&8,q=b&16,r=b&32,p=b&64,b&=128,t){t=new THREE.Face3; +t.a=x[k];t.b=x[k+1];t.c=x[k+3];s=new THREE.Face3;s.a=x[k+1];s.b=x[k+2];s.c=x[k+3];k+=4;h&&(h=x[k++],t.materialIndex=h,s.materialIndex=h);h=c.faces.length;if(d)for(d=0;d<y;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],c.faceVertexUvs[d][h+1]=[],g=0;4>g;g++)n=x[k++],v=u[2*n],n=u[2*n+1],v=new THREE.Vector2(v,n),2!==g&&c.faceVertexUvs[d][h].push(v),0!==g&&c.faceVertexUvs[d][h+1].push(v);q&&(q=3*x[k++],t.normal.set(D[q++],D[q++],D[q]),s.normal.copy(t.normal));if(r)for(d=0;4>d;d++)q=3*x[k++],r=new THREE.Vector3(D[q++], +D[q++],D[q]),2!==d&&t.vertexNormals.push(r),0!==d&&s.vertexNormals.push(r);p&&(p=x[k++],p=w[p],t.color.setHex(p),s.color.setHex(p));if(b)for(d=0;4>d;d++)p=x[k++],p=w[p],2!==d&&t.vertexColors.push(new THREE.Color(p)),0!==d&&s.vertexColors.push(new THREE.Color(p));c.faces.push(t);c.faces.push(s)}else{t=new THREE.Face3;t.a=x[k++];t.b=x[k++];t.c=x[k++];h&&(h=x[k++],t.materialIndex=h);h=c.faces.length;if(d)for(d=0;d<y;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],g=0;3>g;g++)n=x[k++],v=u[2*n],n=u[2*n+1], +v=new THREE.Vector2(v,n),c.faceVertexUvs[d][h].push(v);q&&(q=3*x[k++],t.normal.set(D[q++],D[q++],D[q]));if(r)for(d=0;3>d;d++)q=3*x[k++],r=new THREE.Vector3(D[q++],D[q++],D[q]),t.vertexNormals.push(r);p&&(p=x[k++],t.color.setHex(w[p]));if(b)for(d=0;3>d;d++)p=x[k++],t.vertexColors.push(new THREE.Color(w[p]));c.faces.push(t)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;d<g;d+=b)c.skinWeights.push(new THREE.Vector4(a.skinWeights[d], +1<b?a.skinWeights[d+1]:0,2<b?a.skinWeights[d+2]:0,3<b?a.skinWeights[d+3]:0));if(a.skinIndices)for(d=0,g=a.skinIndices.length;d<g;d+=b)c.skinIndices.push(new THREE.Vector4(a.skinIndices[d],1<b?a.skinIndices[d+1]:0,2<b?a.skinIndices[d+2]:0,3<b?a.skinIndices[d+3]:0));c.bones=a.bones;c.bones&&0<c.bones.length&&(c.skinWeights.length!==c.skinIndices.length||c.skinIndices.length!==c.vertices.length)&&THREE.warn("THREE.JSONLoader: When skinning, number of vertices ("+c.vertices.length+"), skinIndices ("+ +c.skinIndices.length+"), and skinWeights ("+c.skinWeights.length+") should match.");c.animation=a.animation;c.animations=a.animations})();(function(b){if(void 0!==a.morphTargets){var d,g,h,k,l,p;d=0;for(g=a.morphTargets.length;d<g;d++)for(c.morphTargets[d]={},c.morphTargets[d].name=a.morphTargets[d].name,c.morphTargets[d].vertices=[],l=c.morphTargets[d].vertices,p=a.morphTargets[d].vertices,h=0,k=p.length;h<k;h+=3){var q=new THREE.Vector3;q.x=p[h]*b;q.y=p[h+1]*b;q.z=p[h+2]*b;l.push(q)}}if(void 0!== +a.morphColors)for(d=0,g=a.morphColors.length;d<g;d++)for(c.morphColors[d]={},c.morphColors[d].name=a.morphColors[d].name,c.morphColors[d].colors=[],k=c.morphColors[d].colors,l=a.morphColors[d].colors,b=0,h=l.length;b<h;b+=3)p=new THREE.Color(16755200),p.setRGB(l[b],l[b+1],l[b+2]),k.push(p)})(d);c.computeFaceNormals();c.computeBoundingSphere();if(void 0===a.materials||0===a.materials.length)return{geometry:c};d=this.initMaterials(a.materials,b);this.needsTangents(d)&&c.computeTangents();return{geometry:c, +materials:d}};THREE.LoadingManager=function(a,b,c){var d=this,e=0,f=0;this.onLoad=a;this.onProgress=b;this.onError=c;this.itemStart=function(a){f++};this.itemEnd=function(a){e++;if(void 0!==d.onProgress)d.onProgress(a,e,f);if(e===f&&void 0!==d.onLoad)d.onLoad()}};THREE.DefaultLoadingManager=new THREE.LoadingManager;THREE.BufferGeometryLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; +THREE.BufferGeometryLoader.prototype={constructor:THREE.BufferGeometryLoader,load:function(a,b,c,d){var e=this,f=new THREE.XHRLoader(e.manager);f.setCrossOrigin(this.crossOrigin);f.load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new THREE.BufferGeometry,c=a.data.attributes,d;for(d in c){var e=c[d],f=new self[e.type](e.array);b.addAttribute(d,new THREE.BufferAttribute(f,e.itemSize))}c=a.data.offsets;void 0!==c&&(b.offsets=JSON.parse(JSON.stringify(c))); +a=a.data.boundingSphere;void 0!==a&&(c=new THREE.Vector3,void 0!==a.center&&c.fromArray(a.center),b.boundingSphere=new THREE.Sphere(c,a.radius));return b}};THREE.MaterialLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; +THREE.MaterialLoader.prototype={constructor:THREE.MaterialLoader,load:function(a,b,c,d){var e=this,f=new THREE.XHRLoader(e.manager);f.setCrossOrigin(this.crossOrigin);f.load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new THREE[a.type];void 0!==a.color&&b.color.setHex(a.color);void 0!==a.emissive&&b.emissive.setHex(a.emissive);void 0!==a.specular&&b.specular.setHex(a.specular);void 0!==a.shininess&&(b.shininess=a.shininess); +void 0!==a.uniforms&&(b.uniforms=a.uniforms);void 0!==a.vertexShader&&(b.vertexShader=a.vertexShader);void 0!==a.fragmentShader&&(b.fragmentShader=a.fragmentShader);void 0!==a.vertexColors&&(b.vertexColors=a.vertexColors);void 0!==a.shading&&(b.shading=a.shading);void 0!==a.blending&&(b.blending=a.blending);void 0!==a.side&&(b.side=a.side);void 0!==a.opacity&&(b.opacity=a.opacity);void 0!==a.transparent&&(b.transparent=a.transparent);void 0!==a.wireframe&&(b.wireframe=a.wireframe);void 0!==a.size&& +(b.size=a.size);void 0!==a.sizeAttenuation&&(b.sizeAttenuation=a.sizeAttenuation);if(void 0!==a.materials)for(var c=0,d=a.materials.length;c<d;c++)b.materials.push(this.parse(a.materials[c]));return b}};THREE.ObjectLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager;this.texturePath=""}; +THREE.ObjectLoader.prototype={constructor:THREE.ObjectLoader,load:function(a,b,c,d){""===this.texturePath&&(this.texturePath=a.substring(0,a.lastIndexOf("/")+1));var e=this,f=new THREE.XHRLoader(e.manager);f.setCrossOrigin(this.crossOrigin);f.load(a,function(a){e.parse(JSON.parse(a),b)},c,d)},setTexturePath:function(a){this.texturePath=a},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a,b){var c=this.parseGeometries(a.geometries),d=this.parseImages(a.images,function(){void 0!==b&&b(e)}), +d=this.parseTextures(a.textures,d),d=this.parseMaterials(a.materials,d),e=this.parseObject(a.object,c,d);void 0!==a.images&&0!==a.images.length||void 0===b||b(e);return e},parseGeometries:function(a){var b={};if(void 0!==a)for(var c=new THREE.JSONLoader,d=new THREE.BufferGeometryLoader,e=0,f=a.length;e<f;e++){var g,h=a[e];switch(h.type){case "PlaneGeometry":case "PlaneBufferGeometry":g=new THREE[h.type](h.width,h.height,h.widthSegments,h.heightSegments);break;case "BoxGeometry":case "CubeGeometry":g= +new THREE.BoxGeometry(h.width,h.height,h.depth,h.widthSegments,h.heightSegments,h.depthSegments);break;case "CircleGeometry":g=new THREE.CircleGeometry(h.radius,h.segments);break;case "CylinderGeometry":g=new THREE.CylinderGeometry(h.radiusTop,h.radiusBottom,h.height,h.radialSegments,h.heightSegments,h.openEnded);break;case "SphereGeometry":g=new THREE.SphereGeometry(h.radius,h.widthSegments,h.heightSegments,h.phiStart,h.phiLength,h.thetaStart,h.thetaLength);break;case "IcosahedronGeometry":g=new THREE.IcosahedronGeometry(h.radius, +h.detail);break;case "TorusGeometry":g=new THREE.TorusGeometry(h.radius,h.tube,h.radialSegments,h.tubularSegments,h.arc);break;case "TorusKnotGeometry":g=new THREE.TorusKnotGeometry(h.radius,h.tube,h.radialSegments,h.tubularSegments,h.p,h.q,h.heightScale);break;case "BufferGeometry":g=d.parse(h);break;case "Geometry":g=c.parse(h.data).geometry}g.uuid=h.uuid;void 0!==h.name&&(g.name=h.name);b[h.uuid]=g}return b},parseMaterials:function(a,b){var c={};if(void 0!==a)for(var d=function(a){void 0===b[a]&& +THREE.warn("THREE.ObjectLoader: Undefined texture",a);return b[a]},e=new THREE.MaterialLoader,f=0,g=a.length;f<g;f++){var h=a[f],k=e.parse(h);k.uuid=h.uuid;void 0!==h.name&&(k.name=h.name);void 0!==h.map&&(k.map=d(h.map));void 0!==h.bumpMap&&(k.bumpMap=d(h.bumpMap),h.bumpScale&&(k.bumpScale=new THREE.Vector2(h.bumpScale,h.bumpScale)));void 0!==h.alphaMap&&(k.alphaMap=d(h.alphaMap));void 0!==h.envMap&&(k.envMap=d(h.envMap));void 0!==h.normalMap&&(k.normalMap=d(h.normalMap),h.normalScale&&(k.normalScale= +new THREE.Vector2(h.normalScale,h.normalScale)));void 0!==h.lightMap&&(k.lightMap=d(h.lightMap));void 0!==h.specularMap&&(k.specularMap=d(h.specularMap));c[h.uuid]=k}return c},parseImages:function(a,b){var c=this,d={};if(void 0!==a&&0<a.length){var e=new THREE.LoadingManager(b),f=new THREE.ImageLoader(e);f.setCrossOrigin(this.crossOrigin);for(var e=function(a){c.manager.itemStart(a);return f.load(a,function(){c.manager.itemEnd(a)})},g=0,h=a.length;g<h;g++){var k=a[g],l=/^(\/\/)|([a-z]+:(\/\/)?)/i.test(k.url)? +k.url:c.texturePath+k.url;d[k.uuid]=e(l)}}return d},parseTextures:function(a,b){var c={};if(void 0!==a)for(var d=0,e=a.length;d<e;d++){var f=a[d];void 0===f.image&&THREE.warn('THREE.ObjectLoader: No "image" speficied for',f.uuid);void 0===b[f.image]&&THREE.warn("THREE.ObjectLoader: Undefined image",f.image);var g=new THREE.Texture(b[f.image]);g.needsUpdate=!0;g.uuid=f.uuid;void 0!==f.name&&(g.name=f.name);void 0!==f.repeat&&(g.repeat=new THREE.Vector2(f.repeat[0],f.repeat[1]));void 0!==f.minFilter&& +(g.minFilter=THREE[f.minFilter]);void 0!==f.magFilter&&(g.magFilter=THREE[f.magFilter]);void 0!==f.anisotropy&&(g.anisotropy=f.anisotropy);f.wrap instanceof Array&&(g.wrapS=THREE[f.wrap[0]],g.wrapT=THREE[f.wrap[1]]);c[f.uuid]=g}return c},parseObject:function(){var a=new THREE.Matrix4;return function(b,c,d){var e;e=function(a){void 0===c[a]&&THREE.warn("THREE.ObjectLoader: Undefined geometry",a);return c[a]};var f=function(a){void 0===d[a]&&THREE.warn("THREE.ObjectLoader: Undefined material",a);return d[a]}; +switch(b.type){case "Scene":e=new THREE.Scene;break;case "PerspectiveCamera":e=new THREE.PerspectiveCamera(b.fov,b.aspect,b.near,b.far);break;case "OrthographicCamera":e=new THREE.OrthographicCamera(b.left,b.right,b.top,b.bottom,b.near,b.far);break;case "AmbientLight":e=new THREE.AmbientLight(b.color);break;case "DirectionalLight":e=new THREE.DirectionalLight(b.color,b.intensity);break;case "PointLight":e=new THREE.PointLight(b.color,b.intensity,b.distance,b.decay);break;case "SpotLight":e=new THREE.SpotLight(b.color, +b.intensity,b.distance,b.angle,b.exponent,b.decay);break;case "HemisphereLight":e=new THREE.HemisphereLight(b.color,b.groundColor,b.intensity);break;case "Mesh":e=new THREE.Mesh(e(b.geometry),f(b.material));break;case "Line":e=new THREE.Line(e(b.geometry),f(b.material),b.mode);break;case "PointCloud":e=new THREE.PointCloud(e(b.geometry),f(b.material));break;case "Sprite":e=new THREE.Sprite(f(b.material));break;case "Group":e=new THREE.Group;break;default:e=new THREE.Object3D}e.uuid=b.uuid;void 0!== +b.name&&(e.name=b.name);void 0!==b.matrix?(a.fromArray(b.matrix),a.decompose(e.position,e.quaternion,e.scale)):(void 0!==b.position&&e.position.fromArray(b.position),void 0!==b.rotation&&e.rotation.fromArray(b.rotation),void 0!==b.scale&&e.scale.fromArray(b.scale));void 0!==b.visible&&(e.visible=b.visible);void 0!==b.userData&&(e.userData=b.userData);if(void 0!==b.children)for(var g in b.children)e.add(this.parseObject(b.children[g],c,d));return e}}()}; +THREE.TextureLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};THREE.TextureLoader.prototype={constructor:THREE.TextureLoader,load:function(a,b,c,d){var e=new THREE.ImageLoader(this.manager);e.setCrossOrigin(this.crossOrigin);e.load(a,function(a){a=new THREE.Texture(a);a.needsUpdate=!0;void 0!==b&&b(a)},c,d)},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.DataTextureLoader=THREE.BinaryTextureLoader=function(){this._parser=null}; +THREE.BinaryTextureLoader.prototype={constructor:THREE.BinaryTextureLoader,load:function(a,b,c,d){var e=this,f=new THREE.DataTexture,g=new THREE.XHRLoader;g.setResponseType("arraybuffer");g.load(a,function(a){if(a=e._parser(a))void 0!==a.image?f.image=a.image:void 0!==a.data&&(f.image.width=a.width,f.image.height=a.height,f.image.data=a.data),f.wrapS=void 0!==a.wrapS?a.wrapS:THREE.ClampToEdgeWrapping,f.wrapT=void 0!==a.wrapT?a.wrapT:THREE.ClampToEdgeWrapping,f.magFilter=void 0!==a.magFilter?a.magFilter: +THREE.LinearFilter,f.minFilter=void 0!==a.minFilter?a.minFilter:THREE.LinearMipMapLinearFilter,f.anisotropy=void 0!==a.anisotropy?a.anisotropy:1,void 0!==a.format&&(f.format=a.format),void 0!==a.type&&(f.type=a.type),void 0!==a.mipmaps&&(f.mipmaps=a.mipmaps),1===a.mipmapCount&&(f.minFilter=THREE.LinearFilter),f.needsUpdate=!0,b&&b(f,a)},c,d);return f}};THREE.CompressedTextureLoader=function(){this._parser=null}; +THREE.CompressedTextureLoader.prototype={constructor:THREE.CompressedTextureLoader,load:function(a,b,c){var d=this,e=[],f=new THREE.CompressedTexture;f.image=e;var g=new THREE.XHRLoader;g.setResponseType("arraybuffer");if(a instanceof Array){var h=0;c=function(c){g.load(a[c],function(a){a=d._parser(a,!0);e[c]={width:a.width,height:a.height,format:a.format,mipmaps:a.mipmaps};h+=1;6===h&&(1==a.mipmapCount&&(f.minFilter=THREE.LinearFilter),f.format=a.format,f.needsUpdate=!0,b&&b(f))})};for(var k=0,l= +a.length;k<l;++k)c(k)}else g.load(a,function(a){a=d._parser(a,!0);if(a.isCubemap)for(var c=a.mipmaps.length/a.mipmapCount,g=0;g<c;g++){e[g]={mipmaps:[]};for(var h=0;h<a.mipmapCount;h++)e[g].mipmaps.push(a.mipmaps[g*a.mipmapCount+h]),e[g].format=a.format,e[g].width=a.width,e[g].height=a.height}else f.image.width=a.width,f.image.height=a.height,f.mipmaps=a.mipmaps;1===a.mipmapCount&&(f.minFilter=THREE.LinearFilter);f.format=a.format;f.needsUpdate=!0;b&&b(f)});return f}}; +THREE.Material=function(){Object.defineProperty(this,"id",{value:THREE.MaterialIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="Material";this.side=THREE.FrontSide;this.opacity=1;this.transparent=!1;this.blending=THREE.NormalBlending;this.blendSrc=THREE.SrcAlphaFactor;this.blendDst=THREE.OneMinusSrcAlphaFactor;this.blendEquation=THREE.AddEquation;this.blendEquationAlpha=this.blendDstAlpha=this.blendSrcAlpha=null;this.colorWrite=this.depthWrite=this.depthTest=!0;this.polygonOffset= +!1;this.overdraw=this.alphaTest=this.polygonOffsetUnits=this.polygonOffsetFactor=0;this._needsUpdate=this.visible=!0}; +THREE.Material.prototype={constructor:THREE.Material,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)THREE.warn("THREE.Material: '"+b+"' parameter is undefined.");else if(b in this){var d=this[b];d instanceof THREE.Color?d.set(c):d instanceof THREE.Vector3&&c instanceof THREE.Vector3?d.copy(c):this[b]="overdraw"==b?Number(c):c}}},toJSON:function(){var a={metadata:{version:4.2, +type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type};""!==this.name&&(a.name=this.name);this instanceof THREE.MeshBasicMaterial?(a.color=this.color.getHex(),this.vertexColors!==THREE.NoColors&&(a.vertexColors=this.vertexColors),this.blending!==THREE.NormalBlending&&(a.blending=this.blending),this.side!==THREE.FrontSide&&(a.side=this.side)):this instanceof THREE.MeshLambertMaterial?(a.color=this.color.getHex(),a.emissive=this.emissive.getHex(),this.vertexColors!==THREE.NoColors&& +(a.vertexColors=this.vertexColors),this.shading!==THREE.SmoothShading&&(a.shading=this.shading),this.blending!==THREE.NormalBlending&&(a.blending=this.blending),this.side!==THREE.FrontSide&&(a.side=this.side)):this instanceof THREE.MeshPhongMaterial?(a.color=this.color.getHex(),a.emissive=this.emissive.getHex(),a.specular=this.specular.getHex(),a.shininess=this.shininess,this.vertexColors!==THREE.NoColors&&(a.vertexColors=this.vertexColors),this.shading!==THREE.SmoothShading&&(a.shading=this.shading), +this.blending!==THREE.NormalBlending&&(a.blending=this.blending),this.side!==THREE.FrontSide&&(a.side=this.side)):this instanceof THREE.MeshNormalMaterial?(this.blending!==THREE.NormalBlending&&(a.blending=this.blending),this.side!==THREE.FrontSide&&(a.side=this.side)):this instanceof THREE.MeshDepthMaterial?(this.blending!==THREE.NormalBlending&&(a.blending=this.blending),this.side!==THREE.FrontSide&&(a.side=this.side)):this instanceof THREE.PointCloudMaterial?(a.size=this.size,a.sizeAttenuation= +this.sizeAttenuation,a.color=this.color.getHex(),this.vertexColors!==THREE.NoColors&&(a.vertexColors=this.vertexColors),this.blending!==THREE.NormalBlending&&(a.blending=this.blending)):this instanceof THREE.ShaderMaterial?(a.uniforms=this.uniforms,a.vertexShader=this.vertexShader,a.fragmentShader=this.fragmentShader):this instanceof THREE.SpriteMaterial&&(a.color=this.color.getHex());1>this.opacity&&(a.opacity=this.opacity);!1!==this.transparent&&(a.transparent=this.transparent);!1!==this.wireframe&& +(a.wireframe=this.wireframe);return a},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.blendSrcAlpha=this.blendSrcAlpha;a.blendDstAlpha=this.blendDstAlpha;a.blendEquationAlpha=this.blendEquationAlpha;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor= +this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},update:function(){this.dispatchEvent({type:"update"})},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0; +THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.type="LineBasicMaterial";this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype);THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial; +THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.type="LineDashedMaterial";this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype);THREE.LineDashedMaterial.prototype.constructor=THREE.LineDashedMaterial; +THREE.LineDashedMaterial.prototype.clone=function(){var a=new THREE.LineDashedMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.scale=this.scale;a.dashSize=this.dashSize;a.gapSize=this.gapSize;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; +THREE.MeshBasicMaterial=function(a){THREE.Material.call(this);this.type="MeshBasicMaterial";this.color=new THREE.Color(16777215);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphTargets=this.skinning=!1;this.setValues(a)}; +THREE.MeshBasicMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshBasicMaterial.prototype.constructor=THREE.MeshBasicMaterial; +THREE.MeshBasicMaterial.prototype.clone=function(){var a=new THREE.MeshBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap; +a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;return a}; +THREE.MeshLambertMaterial=function(a){THREE.Material.call(this);this.type="MeshLambertMaterial";this.color=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.wrapAround=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.envMap=this.alphaMap=this.specularMap=this.lightMap=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap= +"round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshLambertMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshLambertMaterial.prototype.constructor=THREE.MeshLambertMaterial; +THREE.MeshLambertMaterial.prototype.clone=function(){var a=new THREE.MeshLambertMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.emissive.copy(this.emissive);a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.specularMap=this.specularMap;a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe= +this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.type="MeshPhongMaterial";this.color=new THREE.Color(16777215);this.emissive=new THREE.Color(0);this.specular=new THREE.Color(1118481);this.shininess=30;this.wrapAround=this.metal=!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.bumpMap=this.lightMap=this.map=null;this.bumpScale=1;this.normalMap=null;this.normalScale=new THREE.Vector2(1,1);this.envMap=this.alphaMap=this.specularMap=null;this.combine=THREE.MultiplyOperation;this.reflectivity= +1;this.refractionRatio=.98;this.fog=!0;this.shading=THREE.SmoothShading;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.vertexColors=THREE.NoColors;this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)};THREE.MeshPhongMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshPhongMaterial.prototype.constructor=THREE.MeshPhongMaterial; +THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale);a.specularMap=this.specularMap; +a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; +THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.type="MeshDepthMaterial";this.wireframe=this.morphTargets=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.constructor=THREE.MeshDepthMaterial; +THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshNormalMaterial;THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MeshFaceMaterial";this.materials=a instanceof Array?a:[]}; +THREE.MeshFaceMaterial.prototype={constructor:THREE.MeshFaceMaterial,toJSON:function(){for(var a={metadata:{version:4.2,type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type,materials:[]},b=0,c=this.materials.length;b<c;b++)a.materials.push(this.materials[b].toJSON());return a},clone:function(){for(var a=new THREE.MeshFaceMaterial,b=0;b<this.materials.length;b++)a.materials.push(this.materials[b].clone());return a}}; +THREE.PointCloudMaterial=function(a){THREE.Material.call(this);this.type="PointCloudMaterial";this.color=new THREE.Color(16777215);this.map=null;this.size=1;this.sizeAttenuation=!0;this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.PointCloudMaterial.prototype=Object.create(THREE.Material.prototype);THREE.PointCloudMaterial.prototype.constructor=THREE.PointCloudMaterial; +THREE.PointCloudMaterial.prototype.clone=function(){var a=new THREE.PointCloudMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.size=this.size;a.sizeAttenuation=this.sizeAttenuation;a.vertexColors=this.vertexColors;a.fog=this.fog;return a};THREE.ParticleBasicMaterial=function(a){THREE.warn("THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.");return new THREE.PointCloudMaterial(a)}; +THREE.ParticleSystemMaterial=function(a){THREE.warn("THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.");return new THREE.PointCloudMaterial(a)}; +THREE.ShaderMaterial=function(a){THREE.Material.call(this);this.type="ShaderMaterial";this.defines={};this.uniforms={};this.attributes=null;this.vertexShader="void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";this.fragmentShader="void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";this.shading=THREE.SmoothShading;this.linewidth=1;this.wireframe=!1;this.wireframeLinewidth=1;this.lights=this.fog=!1;this.vertexColors=THREE.NoColors;this.morphNormals= +this.morphTargets=this.skinning=!1;this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv2:[0,0]};this.index0AttributeName=void 0;this.setValues(a)};THREE.ShaderMaterial.prototype=Object.create(THREE.Material.prototype);THREE.ShaderMaterial.prototype.constructor=THREE.ShaderMaterial; THREE.ShaderMaterial.prototype.clone=function(){var a=new THREE.ShaderMaterial;THREE.Material.prototype.clone.call(this,a);a.fragmentShader=this.fragmentShader;a.vertexShader=this.vertexShader;a.uniforms=THREE.UniformsUtils.clone(this.uniforms);a.attributes=this.attributes;a.defines=this.defines;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.fog=this.fog;a.lights=this.lights;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets= -this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.SpriteMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.map=new THREE.Texture;this.useScreenCoordinates=!0;this.depthTest=!this.useScreenCoordinates;this.sizeAttenuation=!this.useScreenCoordinates;this.alignment=THREE.SpriteAlignment.center.clone();this.fog=!1;this.uvOffset=new THREE.Vector2(0,0);this.uvScale=new THREE.Vector2(1,1);this.setValues(a);a=a||{};void 0===a.depthTest&&(this.depthTest=!this.useScreenCoordinates);void 0===a.sizeAttenuation&&(this.sizeAttenuation= -!this.useScreenCoordinates)};THREE.SpriteMaterial.prototype=Object.create(THREE.Material.prototype);THREE.SpriteMaterial.prototype.clone=function(){var a=new THREE.SpriteMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.useScreenCoordinates=this.useScreenCoordinates;a.sizeAttenuation=this.sizeAttenuation;a.alignment.copy(this.alignment);a.uvOffset.copy(this.uvOffset);a.uvScale.copy(this.uvScale);a.fog=this.fog;return a};THREE.SpriteAlignment={}; -THREE.SpriteAlignment.topLeft=new THREE.Vector2(0.5,-0.5);THREE.SpriteAlignment.topCenter=new THREE.Vector2(0,-0.5);THREE.SpriteAlignment.topRight=new THREE.Vector2(-0.5,-0.5);THREE.SpriteAlignment.centerLeft=new THREE.Vector2(0.5,0);THREE.SpriteAlignment.center=new THREE.Vector2(0,0);THREE.SpriteAlignment.centerRight=new THREE.Vector2(-0.5,0);THREE.SpriteAlignment.bottomLeft=new THREE.Vector2(0.5,0.5);THREE.SpriteAlignment.bottomCenter=new THREE.Vector2(0,0.5); -THREE.SpriteAlignment.bottomRight=new THREE.Vector2(-0.5,0.5);THREE.SpriteCanvasMaterial=function(a){THREE.Material.call(this);this.color=new THREE.Color(16777215);this.program=function(){};this.setValues(a)};THREE.SpriteCanvasMaterial.prototype=Object.create(THREE.Material.prototype);THREE.SpriteCanvasMaterial.prototype.clone=function(){var a=new THREE.SpriteCanvasMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.program=this.program;return a};THREE.ParticleCanvasMaterial=THREE.SpriteCanvasMaterial;THREE.Texture=function(a,b,c,d,e,f,h,g,i){this.id=THREE.TextureIdCount++;this.uuid=THREE.Math.generateUUID();this.name="";this.image=a;this.mipmaps=[];this.mapping=void 0!==b?b:new THREE.UVMapping;this.wrapS=void 0!==c?c:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==d?d:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==e?e:THREE.LinearFilter;this.minFilter=void 0!==f?f:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==i?i:1;this.format=void 0!==h?h:THREE.RGBAFormat;this.type=void 0!==g?g:THREE.UnsignedByteType; -this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this.needsUpdate=!1;this.onUpdate=null}; -THREE.Texture.prototype={constructor:THREE.Texture,clone:function(a){void 0===a&&(a=new THREE.Texture);a.image=this.image;a.mipmaps=this.mipmaps.slice(0);a.mapping=this.mapping;a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.format=this.format;a.type=this.type;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.generateMipmaps=this.generateMipmaps;a.premultiplyAlpha=this.premultiplyAlpha;a.flipY=this.flipY;a.unpackAlignment= -this.unpackAlignment;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype);THREE.TextureIdCount=0;THREE.CompressedTexture=function(a,b,c,d,e,f,h,g,i,k,m){THREE.Texture.call(this,null,f,h,g,i,k,d,e,m);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CompressedTexture.prototype.clone=function(){var a=new THREE.CompressedTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.DataTexture=function(a,b,c,d,e,f,h,g,i,k,m){THREE.Texture.call(this,null,f,h,g,i,k,d,e,m);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.ParticleSystem=function(a,b){THREE.Object3D.call(this);this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.ParticleSystemMaterial({color:16777215*Math.random()});this.frustumCulled=this.sortParticles=!1};THREE.ParticleSystem.prototype=Object.create(THREE.Object3D.prototype); -THREE.ParticleSystem.prototype.clone=function(a){void 0===a&&(a=new THREE.ParticleSystem(this.geometry,this.material));a.sortParticles=this.sortParticles;THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Line=function(a,b,c){THREE.Object3D.call(this);this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()});this.type=void 0!==c?c:THREE.LineStrip};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=Object.create(THREE.Object3D.prototype);THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.type));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); -THREE.Mesh.prototype.updateMorphTargets=function(){if(0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}}; -THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};THREE.Mesh.prototype.clone=function(a){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a;this.skinMatrix=new THREE.Matrix4};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b|=this.updateMatrix());if(b||this.matrixWorldNeedsUpdate)a?this.skinMatrix.multiplyMatrices(a,this.matrix):this.skinMatrix.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0;var c,d=this.children.length;for(c=0;c<d;c++)this.children[c].update(this.skinMatrix,b)};THREE.SkinnedMesh=function(a,b,c){THREE.Mesh.call(this,a,b);this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;this.bones=[];this.boneMatrices=[];var d,e,f;if(this.geometry&&void 0!==this.geometry.bones){for(a=0;a<this.geometry.bones.length;a++)c=this.geometry.bones[a],d=c.pos,e=c.rotq,f=c.scl,b=this.addBone(),b.name=c.name,b.position.set(d[0],d[1],d[2]),b.quaternion.set(e[0],e[1],e[2],e[3]),void 0!==f?b.scale.set(f[0],f[1],f[2]):b.scale.set(1,1,1);for(a=0;a<this.bones.length;a++)c= -this.geometry.bones[a],b=this.bones[a],-1===c.parent?this.add(b):this.bones[c.parent].add(b);a=this.bones.length;this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256<a?64:64<a?32:16<a?16:8,this.boneMatrices=new Float32Array(4*this.boneTextureWidth*this.boneTextureHeight),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAFormat,THREE.FloatType),this.boneTexture.minFilter=THREE.NearestFilter,this.boneTexture.magFilter= -THREE.NearestFilter,this.boneTexture.generateMipmaps=!1,this.boneTexture.flipY=!1):this.boneMatrices=new Float32Array(16*a);this.pose()}};THREE.SkinnedMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.SkinnedMesh.prototype.addBone=function(a){void 0===a&&(a=new THREE.Bone(this));this.bones.push(a);return a}; -THREE.SkinnedMesh.prototype.updateMatrixWorld=function(){var a=new THREE.Matrix4;return function(b){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||b)this.parent?this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1;for(var b=0,c=this.children.length;b<c;b++){var d=this.children[b];d instanceof THREE.Bone?d.update(this.identityMatrix,!1):d.updateMatrixWorld(!0)}if(void 0==this.boneInverses){this.boneInverses= -[];b=0;for(c=this.bones.length;b<c;b++)d=new THREE.Matrix4,d.getInverse(this.bones[b].skinMatrix),this.boneInverses.push(d)}b=0;for(c=this.bones.length;b<c;b++)a.multiplyMatrices(this.bones[b].skinMatrix,this.boneInverses[b]),a.flattenToArrayOffset(this.boneMatrices,16*b);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}}();THREE.SkinnedMesh.prototype.pose=function(){this.updateMatrixWorld(!0);this.normalizeSkinWeights()}; -THREE.SkinnedMesh.prototype.normalizeSkinWeights=function(){if(this.geometry instanceof THREE.Geometry)for(var a=0;a<this.geometry.skinIndices.length;a++){var b=this.geometry.skinWeights[a],c=1/b.lengthManhattan();Infinity!==c?b.multiplyScalar(c):b.set(1)}};THREE.SkinnedMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.SkinnedMesh(this.geometry,this.material,this.useVertexTexture));THREE.Mesh.prototype.clone.call(this,a);return a};THREE.MorphAnimMesh=function(a,b){THREE.Mesh.call(this,a,b);this.duration=1E3;this.mirroredLoop=!1;this.currentKeyframe=this.lastKeyframe=this.time=0;this.direction=1;this.directionBackwards=!1;this.setFrameRange(0,this.geometry.morphTargets.length-1)};THREE.MorphAnimMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.MorphAnimMesh.prototype.setFrameRange=function(a,b){this.startKeyframe=a;this.endKeyframe=b;this.length=this.endKeyframe-this.startKeyframe+1}; -THREE.MorphAnimMesh.prototype.setDirectionForward=function(){this.direction=1;this.directionBackwards=!1};THREE.MorphAnimMesh.prototype.setDirectionBackward=function(){this.direction=-1;this.directionBackwards=!0}; -THREE.MorphAnimMesh.prototype.parseAnimations=function(){var a=this.geometry;a.animations||(a.animations={});for(var b,c=a.animations,d=/([a-z]+)(\d+)/,e=0,f=a.morphTargets.length;e<f;e++){var h=a.morphTargets[e].name.match(d);if(h&&1<h.length){h=h[1];c[h]||(c[h]={start:Infinity,end:-Infinity});var g=c[h];e<g.start&&(g.start=e);e>g.end&&(g.end=e);b||(b=h)}}a.firstAnimation=b}; -THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")}; +this.morphTargets;a.morphNormals=this.morphNormals;return a};THREE.RawShaderMaterial=function(a){THREE.ShaderMaterial.call(this,a);this.type="RawShaderMaterial"};THREE.RawShaderMaterial.prototype=Object.create(THREE.ShaderMaterial.prototype);THREE.RawShaderMaterial.prototype.constructor=THREE.RawShaderMaterial;THREE.RawShaderMaterial.prototype.clone=function(){var a=new THREE.RawShaderMaterial;THREE.ShaderMaterial.prototype.clone.call(this,a);return a}; +THREE.SpriteMaterial=function(a){THREE.Material.call(this);this.type="SpriteMaterial";this.color=new THREE.Color(16777215);this.map=null;this.rotation=0;this.fog=!1;this.setValues(a)};THREE.SpriteMaterial.prototype=Object.create(THREE.Material.prototype);THREE.SpriteMaterial.prototype.constructor=THREE.SpriteMaterial; +THREE.SpriteMaterial.prototype.clone=function(){var a=new THREE.SpriteMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.map=this.map;a.rotation=this.rotation;a.fog=this.fog;return a}; +THREE.Texture=function(a,b,c,d,e,f,g,h,k){Object.defineProperty(this,"id",{value:THREE.TextureIdCount++});this.uuid=THREE.Math.generateUUID();this.sourceFile=this.name="";this.image=void 0!==a?a:THREE.Texture.DEFAULT_IMAGE;this.mipmaps=[];this.mapping=void 0!==b?b:THREE.Texture.DEFAULT_MAPPING;this.wrapS=void 0!==c?c:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==d?d:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==e?e:THREE.LinearFilter;this.minFilter=void 0!==f?f:THREE.LinearMipMapLinearFilter; +this.anisotropy=void 0!==k?k:1;this.format=void 0!==g?g:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this._needsUpdate=!1;this.onUpdate=null};THREE.Texture.DEFAULT_IMAGE=void 0;THREE.Texture.DEFAULT_MAPPING=THREE.UVMapping; +THREE.Texture.prototype={constructor:THREE.Texture,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},clone:function(a){void 0===a&&(a=new THREE.Texture);a.image=this.image;a.mipmaps=this.mipmaps.slice(0);a.mapping=this.mapping;a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.format=this.format;a.type=this.type;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.generateMipmaps= +this.generateMipmaps;a.premultiplyAlpha=this.premultiplyAlpha;a.flipY=this.flipY;a.unpackAlignment=this.unpackAlignment;return a},update:function(){this.dispatchEvent({type:"update"})},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype);THREE.TextureIdCount=0;THREE.CubeTexture=function(a,b,c,d,e,f,g,h,k){b=void 0!==b?b:THREE.CubeReflectionMapping;THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.images=a}; +THREE.CubeTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CubeTexture.prototype.constructor=THREE.CubeTexture;THREE.CubeTexture.clone=function(a){void 0===a&&(a=new THREE.CubeTexture);THREE.Texture.prototype.clone.call(this,a);a.images=this.images;return a};THREE.CompressedTexture=function(a,b,c,d,e,f,g,h,k,l,p){THREE.Texture.call(this,null,f,g,h,k,l,d,e,p);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype); +THREE.CompressedTexture.prototype.constructor=THREE.CompressedTexture;THREE.CompressedTexture.prototype.clone=function(){var a=new THREE.CompressedTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.DataTexture=function(a,b,c,d,e,f,g,h,k,l,p){THREE.Texture.call(this,null,f,g,h,k,l,d,e,p);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.constructor=THREE.DataTexture; +THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.VideoTexture=function(a,b,c,d,e,f,g,h,k){THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.generateMipmaps=!1;var l=this,p=function(){requestAnimationFrame(p);a.readyState===a.HAVE_ENOUGH_DATA&&(l.needsUpdate=!0)};p()};THREE.VideoTexture.prototype=Object.create(THREE.Texture.prototype);THREE.VideoTexture.prototype.constructor=THREE.VideoTexture; +THREE.Group=function(){THREE.Object3D.call(this);this.type="Group"};THREE.Group.prototype=Object.create(THREE.Object3D.prototype);THREE.Group.prototype.constructor=THREE.Group;THREE.PointCloud=function(a,b){THREE.Object3D.call(this);this.type="PointCloud";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.PointCloudMaterial({color:16777215*Math.random()})};THREE.PointCloud.prototype=Object.create(THREE.Object3D.prototype);THREE.PointCloud.prototype.constructor=THREE.PointCloud; +THREE.PointCloud.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray;return function(c,d){var e=this,f=e.geometry,g=c.params.PointCloud.threshold;a.getInverse(this.matrixWorld);b.copy(c.ray).applyMatrix4(a);if(null===f.boundingBox||!1!==b.isIntersectionBox(f.boundingBox)){var h=g/((this.scale.x+this.scale.y+this.scale.z)/3),k=new THREE.Vector3,g=function(a,f){var g=b.distanceToPoint(a);if(g<h){var k=b.closestPointToPoint(a);k.applyMatrix4(e.matrixWorld);var n=c.ray.origin.distanceTo(k); +d.push({distance:n,distanceToRay:g,point:k.clone(),index:f,face:null,object:e})}};if(f instanceof THREE.BufferGeometry){var l=f.attributes,p=l.position.array;if(void 0!==l.index){var l=l.index.array,q=f.offsets;0===q.length&&(q=[{start:0,count:l.length,index:0}]);for(var n=0,t=q.length;n<t;++n)for(var r=q[n].start,s=q[n].index,f=r,r=r+q[n].count;f<r;f++){var u=s+l[f];k.fromArray(p,3*u);g(k,u)}}else for(l=p.length/3,f=0;f<l;f++)k.set(p[3*f],p[3*f+1],p[3*f+2]),g(k,f)}else for(k=this.geometry.vertices, +f=0;f<k.length;f++)g(k[f],f)}}}();THREE.PointCloud.prototype.clone=function(a){void 0===a&&(a=new THREE.PointCloud(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.ParticleSystem=function(a,b){THREE.warn("THREE.ParticleSystem has been renamed to THREE.PointCloud.");return new THREE.PointCloud(a,b)}; +THREE.Line=function(a,b,c){THREE.Object3D.call(this);this.type="Line";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()});this.mode=void 0!==c?c:THREE.LineStrip};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=Object.create(THREE.Object3D.prototype);THREE.Line.prototype.constructor=THREE.Line; +THREE.Line.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere;return function(d,e){var f=d.linePrecision,f=f*f,g=this.geometry;null===g.boundingSphere&&g.computeBoundingSphere();c.copy(g.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==d.ray.isIntersectionSphere(c)){a.getInverse(this.matrixWorld);b.copy(d.ray).applyMatrix4(a);var h=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,p=new THREE.Vector3,q=this.mode===THREE.LineStrip?1:2;if(g instanceof +THREE.BufferGeometry){var n=g.attributes;if(void 0!==n.index){var t=n.index.array,n=n.position.array,r=g.offsets;0===r.length&&(r=[{start:0,count:t.length,index:0}]);for(var s=0;s<r.length;s++)for(var u=r[s].start,v=r[s].count,x=r[s].index,g=u;g<u+v-1;g+=q){var D=x+t[g+1];h.fromArray(n,3*(x+t[g]));k.fromArray(n,3*D);D=b.distanceSqToSegment(h,k,p,l);D>f||(D=b.origin.distanceTo(p),D<d.near||D>d.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld),index:g,offsetIndex:s,face:null,faceIndex:null, +object:this}))}}else for(n=n.position.array,g=0;g<n.length/3-1;g+=q)h.fromArray(n,3*g),k.fromArray(n,3*g+3),D=b.distanceSqToSegment(h,k,p,l),D>f||(D=b.origin.distanceTo(p),D<d.near||D>d.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g instanceof THREE.Geometry)for(h=g.vertices,k=h.length,g=0;g<k-1;g+=q)D=b.distanceSqToSegment(h[g],h[g+1],p,l),D>f||(D=b.origin.distanceTo(p),D<d.near||D>d.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld), +index:g,face:null,faceIndex:null,object:this}))}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.mode));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); +THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}}; +THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];THREE.warn("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0}; +THREE.Mesh.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere,d=new THREE.Vector3,e=new THREE.Vector3,f=new THREE.Vector3;return function(g,h){var k=this.geometry;null===k.boundingSphere&&k.computeBoundingSphere();c.copy(k.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==g.ray.isIntersectionSphere(c)&&(a.getInverse(this.matrixWorld),b.copy(g.ray).applyMatrix4(a),null===k.boundingBox||!1!==b.isIntersectionBox(k.boundingBox)))if(k instanceof THREE.BufferGeometry){var l= +this.material;if(void 0!==l){var p=k.attributes,q,n,t=g.precision;if(void 0!==p.index){var r=p.index.array,s=p.position.array,u=k.offsets;0===u.length&&(u=[{start:0,count:r.length,index:0}]);for(var v=0,x=u.length;v<x;++v)for(var p=u[v].start,D=u[v].index,k=p,w=p+u[v].count;k<w;k+=3){p=D+r[k];q=D+r[k+1];n=D+r[k+2];d.fromArray(s,3*p);e.fromArray(s,3*q);f.fromArray(s,3*n);var y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide);if(null!==y){y.applyMatrix4(this.matrixWorld); +var A=g.ray.origin.distanceTo(y);A<t||A<g.near||A>g.far||h.push({distance:A,point:y,face:new THREE.Face3(p,q,n,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(s=p.position.array,r=k=0,w=s.length;k<w;k+=3,r+=9)p=k,q=k+1,n=k+2,d.fromArray(s,r),e.fromArray(s,r+3),f.fromArray(s,r+6),y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide),null!==y&&(y.applyMatrix4(this.matrixWorld),A=g.ray.origin.distanceTo(y),A<t||A<g.near||A> +g.far||h.push({distance:A,point:y,face:new THREE.Face3(p,q,n,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(r=this.material instanceof THREE.MeshFaceMaterial,s=!0===r?this.material.materials:null,t=g.precision,u=k.vertices,v=0,x=k.faces.length;v<x;v++)if(D=k.faces[v],l=!0===r?s[D.materialIndex]:this.material,void 0!==l){p=u[D.a];q=u[D.b];n=u[D.c];if(!0===l.morphTargets){y=k.morphTargets;A=this.morphTargetInfluences;d.set(0,0,0);e.set(0,0,0);f.set(0, +0,0);for(var w=0,E=y.length;w<E;w++){var G=A[w];if(0!==G){var F=y[w].vertices;d.x+=(F[D.a].x-p.x)*G;d.y+=(F[D.a].y-p.y)*G;d.z+=(F[D.a].z-p.z)*G;e.x+=(F[D.b].x-q.x)*G;e.y+=(F[D.b].y-q.y)*G;e.z+=(F[D.b].z-q.z)*G;f.x+=(F[D.c].x-n.x)*G;f.y+=(F[D.c].y-n.y)*G;f.z+=(F[D.c].z-n.z)*G}}d.add(p);e.add(q);f.add(n);p=d;q=e;n=f}y=l.side===THREE.BackSide?b.intersectTriangle(n,q,p,!0):b.intersectTriangle(p,q,n,l.side!==THREE.DoubleSide);null!==y&&(y.applyMatrix4(this.matrixWorld),A=g.ray.origin.distanceTo(y),A<t|| +A<g.near||A>g.far||h.push({distance:A,point:y,face:D,faceIndex:v,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.type="Bone";this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.constructor=THREE.Bone; +THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256<this.bones.length?64:64<this.bones.length?32:16<this.bones.length?16:8,this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAFormat,THREE.FloatType), +this.boneTexture.minFilter=THREE.NearestFilter,this.boneTexture.magFilter=THREE.NearestFilter,this.boneTexture.generateMipmaps=!1,this.boneTexture.flipY=!1):this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(THREE.warn("THREE.Skeleton bonInverses is the wrong length."),this.boneInverses=[],b=0,a=this.bones.length;b<a;b++)this.boneInverses.push(new THREE.Matrix4)}; +THREE.Skeleton.prototype.calculateInverses=function(){this.boneInverses=[];for(var a=0,b=this.bones.length;a<b;a++){var c=new THREE.Matrix4;this.bones[a]&&c.getInverse(this.bones[a].matrixWorld);this.boneInverses.push(c)}}; +THREE.Skeleton.prototype.pose=function(){for(var a,b=0,c=this.bones.length;b<c;b++)(a=this.bones[b])&&a.matrixWorld.getInverse(this.boneInverses[b]);b=0;for(c=this.bones.length;b<c;b++)if(a=this.bones[b])a.parent?(a.matrix.getInverse(a.parent.matrixWorld),a.matrix.multiply(a.matrixWorld)):a.matrix.copy(a.matrixWorld),a.matrix.decompose(a.position,a.quaternion,a.scale)}; +THREE.Skeleton.prototype.update=function(){var a=new THREE.Matrix4;return function(){for(var b=0,c=this.bones.length;b<c;b++)a.multiplyMatrices(this.bones[b]?this.bones[b].matrixWorld:this.identityMatrix,this.boneInverses[b]),a.flattenToArrayOffset(this.boneMatrices,16*b);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}}(); +THREE.SkinnedMesh=function(a,b,c){THREE.Mesh.call(this,a,b);this.type="SkinnedMesh";this.bindMode="attached";this.bindMatrix=new THREE.Matrix4;this.bindMatrixInverse=new THREE.Matrix4;a=[];if(this.geometry&&void 0!==this.geometry.bones){for(var d,e,f,g,h=0,k=this.geometry.bones.length;h<k;++h)d=this.geometry.bones[h],e=d.pos,f=d.rotq,g=d.scl,b=new THREE.Bone(this),a.push(b),b.name=d.name,b.position.set(e[0],e[1],e[2]),b.quaternion.set(f[0],f[1],f[2],f[3]),void 0!==g?b.scale.set(g[0],g[1],g[2]):b.scale.set(1, +1,1);h=0;for(k=this.geometry.bones.length;h<k;++h)d=this.geometry.bones[h],-1!==d.parent?a[d.parent].add(a[h]):this.add(a[h])}this.normalizeSkinWeights();this.updateMatrixWorld(!0);this.bind(new THREE.Skeleton(a,void 0,c))};THREE.SkinnedMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.SkinnedMesh.prototype.constructor=THREE.SkinnedMesh;THREE.SkinnedMesh.prototype.bind=function(a,b){this.skeleton=a;void 0===b&&(this.updateMatrixWorld(!0),b=this.matrixWorld);this.bindMatrix.copy(b);this.bindMatrixInverse.getInverse(b)}; +THREE.SkinnedMesh.prototype.pose=function(){this.skeleton.pose()};THREE.SkinnedMesh.prototype.normalizeSkinWeights=function(){if(this.geometry instanceof THREE.Geometry)for(var a=0;a<this.geometry.skinIndices.length;a++){var b=this.geometry.skinWeights[a],c=1/b.lengthManhattan();Infinity!==c?b.multiplyScalar(c):b.set(1)}}; +THREE.SkinnedMesh.prototype.updateMatrixWorld=function(a){THREE.Mesh.prototype.updateMatrixWorld.call(this,!0);"attached"===this.bindMode?this.bindMatrixInverse.getInverse(this.matrixWorld):"detached"===this.bindMode?this.bindMatrixInverse.getInverse(this.bindMatrix):THREE.warn("THREE.SkinnedMesh unreckognized bindMode: "+this.bindMode)}; +THREE.SkinnedMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.SkinnedMesh(this.geometry,this.material,this.useVertexTexture));THREE.Mesh.prototype.clone.call(this,a);return a};THREE.MorphAnimMesh=function(a,b){THREE.Mesh.call(this,a,b);this.type="MorphAnimMesh";this.duration=1E3;this.mirroredLoop=!1;this.currentKeyframe=this.lastKeyframe=this.time=0;this.direction=1;this.directionBackwards=!1;this.setFrameRange(0,this.geometry.morphTargets.length-1)};THREE.MorphAnimMesh.prototype=Object.create(THREE.Mesh.prototype); +THREE.MorphAnimMesh.prototype.constructor=THREE.MorphAnimMesh;THREE.MorphAnimMesh.prototype.setFrameRange=function(a,b){this.startKeyframe=a;this.endKeyframe=b;this.length=this.endKeyframe-this.startKeyframe+1};THREE.MorphAnimMesh.prototype.setDirectionForward=function(){this.direction=1;this.directionBackwards=!1};THREE.MorphAnimMesh.prototype.setDirectionBackward=function(){this.direction=-1;this.directionBackwards=!0}; +THREE.MorphAnimMesh.prototype.parseAnimations=function(){var a=this.geometry;a.animations||(a.animations={});for(var b,c=a.animations,d=/([a-z]+)_?(\d+)/,e=0,f=a.morphTargets.length;e<f;e++){var g=a.morphTargets[e].name.match(d);if(g&&1<g.length){g=g[1];c[g]||(c[g]={start:Infinity,end:-Infinity});var h=c[g];e<h.start&&(h.start=e);e>h.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=(c.end-c.start)/b*1E3,this.time=0):THREE.warn("THREE.MorphAnimMesh: animation["+a+"] undefined in .playAnimation()")}; THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& (this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; -THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.objects=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c<this.objects.length&&!(b<this.objects[c].distance);c++);this.objects.splice(c,0,{distance:b,object:a});this.add(a)};THREE.LOD.prototype.getObjectForDistance=function(a){for(var b=1,c=this.objects.length;b<c&&!(a<this.objects[b].distance);b++);return this.objects[b-1].object}; -THREE.LOD.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){if(1<this.objects.length){a.getPositionFromMatrix(c.matrixWorld);b.getPositionFromMatrix(this.matrixWorld);c=a.distanceTo(b);this.objects[0].object.visible=!0;for(var d=1,e=this.objects.length;d<e;d++)if(c>=this.objects[d].distance)this.objects[d-1].object.visible=!1,this.objects[d].object.visible=!0;else break;for(;d<e;d++)this.objects[d].object.visible=!1}}}();THREE.LOD.prototype.clone=function(){};THREE.Sprite=function(a){THREE.Object3D.call(this);this.material=void 0!==a?a:new THREE.SpriteMaterial;this.rotation=0};THREE.Sprite.prototype=Object.create(THREE.Object3D.prototype);THREE.Sprite.prototype.updateMatrix=function(){this.matrix.compose(this.position,this.quaternion,this.scale);this.matrixWorldNeedsUpdate=!0};THREE.Sprite.prototype.clone=function(a){void 0===a&&(a=new THREE.Sprite(this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Particle=THREE.Sprite;THREE.Scene=function(){THREE.Object3D.call(this);this.overrideMaterial=this.fog=null;this.autoUpdate=!0;this.matrixAutoUpdate=!1;this.__lights=[];this.__objectsAdded=[];this.__objectsRemoved=[]};THREE.Scene.prototype=Object.create(THREE.Object3D.prototype); -THREE.Scene.prototype.__addObject=function(a){if(a instanceof THREE.Light)-1===this.__lights.indexOf(a)&&this.__lights.push(a),a.target&&void 0===a.target.parent&&this.add(a.target);else if(!(a instanceof THREE.Camera||a instanceof THREE.Bone)){this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);-1!==b&&this.__objectsRemoved.splice(b,1)}for(b=0;b<a.children.length;b++)this.__addObject(a.children[b])}; -THREE.Scene.prototype.__removeObject=function(a){if(a instanceof THREE.Light){var b=this.__lights.indexOf(a);-1!==b&&this.__lights.splice(b,1);if(a.shadowCascadeArray)for(b=0;b<a.shadowCascadeArray.length;b++)this.__removeObject(a.shadowCascadeArray[b])}else a instanceof THREE.Camera||(this.__objectsRemoved.push(a),b=this.__objectsAdded.indexOf(a),-1!==b&&this.__objectsAdded.splice(b,1));for(b=0;b<a.children.length;b++)this.__removeObject(a.children[b])}; -THREE.Scene.prototype.clone=function(a){void 0===a&&(a=new THREE.Scene);THREE.Object3D.prototype.clone.call(this,a);null!==this.fog&&(a.fog=this.fog.clone());null!==this.overrideMaterial&&(a.overrideMaterial=this.overrideMaterial.clone());a.autoUpdate=this.autoUpdate;a.matrixAutoUpdate=this.matrixAutoUpdate;return a};THREE.Fog=function(a,b,c){this.name="";this.color=new THREE.Color(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3};THREE.Fog.prototype.clone=function(){return new THREE.Fog(this.color.getHex(),this.near,this.far)};THREE.FogExp2=function(a,b){this.name="";this.color=new THREE.Color(a);this.density=void 0!==b?b:2.5E-4};THREE.FogExp2.prototype.clone=function(){return new THREE.FogExp2(this.color.getHex(),this.density)};THREE.CanvasRenderer=function(a){function b(a,b,c){for(var d=0,e=z.length;d<e;d++){var f=z[d];La.copy(f.color);if(f instanceof THREE.DirectionalLight){var h=ua.getPositionFromMatrix(f.matrixWorld).normalize(),g=b.dot(h);0>=g||(g*=f.intensity,c.add(La.multiplyScalar(g)))}else f instanceof THREE.PointLight&&(h=ua.getPositionFromMatrix(f.matrixWorld),g=b.dot(ua.subVectors(h,a).normalize()),0>=g||(g*=0==f.distance?1:1-Math.min(a.distanceTo(h)/f.distance,1),0!=g&&(g*=f.intensity,c.add(La.multiplyScalar(g)))))}} -function c(a,b,c,d){m(b);l(c);p(d);s(a.getStyle());C.stroke();ra.expandByScalar(2*b)}function d(a){t(a.getStyle());C.fill()}function e(a,b,c,e,f,h,g,j,i,k,m,l,p){if(!(p instanceof THREE.DataTexture||void 0===p.image||0==p.image.width)){if(!0===p.needsUpdate){var n=p.wrapS==THREE.RepeatWrapping,r=p.wrapT==THREE.RepeatWrapping;Ga[p.id]=C.createPattern(p.image,!0===n&&!0===r?"repeat":!0===n&&!1===r?"repeat-x":!1===n&&!0===r?"repeat-y":"no-repeat");p.needsUpdate=!1}void 0===Ga[p.id]?t("rgba(0,0,0,1)"): -t(Ga[p.id]);var n=p.offset.x/p.repeat.x,r=p.offset.y/p.repeat.y,s=p.image.width*p.repeat.x,q=p.image.height*p.repeat.y,g=(g+n)*s,j=(1-j+r)*q,c=c-a,e=e-b,f=f-a,h=h-b,i=(i+n)*s-g,k=(1-k+r)*q-j,m=(m+n)*s-g,l=(1-l+r)*q-j,n=i*l-m*k;0===n?(void 0===fa[p.id]&&(b=document.createElement("canvas"),b.width=p.image.width,b.height=p.image.height,b=b.getContext("2d"),b.drawImage(p.image,0,0),fa[p.id]=b.getImageData(0,0,p.image.width,p.image.height).data),b=fa[p.id],g=4*(Math.floor(g)+Math.floor(j)*p.image.width), -V.setRGB(b[g]/255,b[g+1]/255,b[g+2]/255),d(V)):(n=1/n,p=(l*c-k*f)*n,k=(l*e-k*h)*n,c=(i*f-m*c)*n,e=(i*h-m*e)*n,a=a-p*g-c*j,g=b-k*g-e*j,C.save(),C.transform(p,k,c,e,a,g),C.fill(),C.restore())}}function f(a,b,c,d,e,f,h,g,j,i,k,m,l){var p,n;p=l.width-1;n=l.height-1;h*=p;g*=n;c-=a;d-=b;e-=a;f-=b;j=j*p-h;i=i*n-g;k=k*p-h;m=m*n-g;n=1/(j*m-k*i);p=(m*c-i*e)*n;i=(m*d-i*f)*n;c=(j*e-k*c)*n;d=(j*f-k*d)*n;a=a-p*h-c*g;b=b-i*h-d*g;C.save();C.transform(p,i,c,d,a,b);C.clip();C.drawImage(l,0,0);C.restore()}function h(a, -b,c,d){va[0]=255*a.r|0;va[1]=255*a.g|0;va[2]=255*a.b|0;va[4]=255*b.r|0;va[5]=255*b.g|0;va[6]=255*b.b|0;va[8]=255*c.r|0;va[9]=255*c.g|0;va[10]=255*c.b|0;va[12]=255*d.r|0;va[13]=255*d.g|0;va[14]=255*d.b|0;j.putImageData(Oa,0,0);Ea.drawImage(Pa,0,0);return wa}function g(a,b,c){var d=b.x-a.x,e=b.y-a.y,f=d*d+e*e;0!==f&&(c/=Math.sqrt(f),d*=c,e*=c,b.x+=d,b.y+=e,a.x-=d,a.y-=e)}function i(a){y!==a&&(y=C.globalAlpha=a)}function k(a){v!==a&&(a===THREE.NormalBlending?C.globalCompositeOperation="source-over": -a===THREE.AdditiveBlending?C.globalCompositeOperation="lighter":a===THREE.SubtractiveBlending&&(C.globalCompositeOperation="darker"),v=a)}function m(a){J!==a&&(J=C.lineWidth=a)}function l(a){ba!==a&&(ba=C.lineCap=a)}function p(a){oa!==a&&(oa=C.lineJoin=a)}function s(a){G!==a&&(G=C.strokeStyle=a)}function t(a){R!==a&&(R=C.fillStyle=a)}function n(a,b){if(pa!==a||N!==b)C.setLineDash([a,b]),pa=a,N=b}console.log("THREE.CanvasRenderer",THREE.REVISION);var r=THREE.Math.smoothstep,a=a||{},q=this,u,w,z,B= -new THREE.Projector,D=void 0!==a.canvas?a.canvas:document.createElement("canvas"),x=D.width,F=D.height,A=Math.floor(x/2),O=Math.floor(F/2),C=D.getContext("2d"),E=new THREE.Color(0),I=0,y=1,v=0,G=null,R=null,J=null,ba=null,oa=null,pa=null,N=0,M,Q,K,ca;new THREE.RenderableVertex;new THREE.RenderableVertex;var Fa,Ba,da,Aa,$,ea,V=new THREE.Color,P=new THREE.Color,Z=new THREE.Color,U=new THREE.Color,ka=new THREE.Color,ta=new THREE.Color,ia=new THREE.Color,La=new THREE.Color,Ga={},fa={},Da,Ua,Qa,xa,bb, -cb,Ma,fb,sb,pb,Ha=new THREE.Box2,la=new THREE.Box2,ra=new THREE.Box2,gb=new THREE.Color,sa=new THREE.Color,ga=new THREE.Color,ua=new THREE.Vector3,Pa,j,Oa,va,wa,Ea,Ra=16;Pa=document.createElement("canvas");Pa.width=Pa.height=2;j=Pa.getContext("2d");j.fillStyle="rgba(0,0,0,1)";j.fillRect(0,0,2,2);Oa=j.getImageData(0,0,2,2);va=Oa.data;wa=document.createElement("canvas");wa.width=wa.height=Ra;Ea=wa.getContext("2d");Ea.translate(-Ra/2,-Ra/2);Ea.scale(Ra,Ra);Ra--;void 0===C.setLineDash&&(C.setLineDash= -void 0!==C.mozDash?function(a){C.mozDash=null!==a[0]?a:null}:function(){});this.domElement=D;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==self.devicePixelRatio?self.devicePixelRatio:1;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,faces:0}};this.supportsVertexTextures=function(){};this.setFaceCulling=function(){};this.setSize=function(a,b,c){x=a*this.devicePixelRatio;F=b*this.devicePixelRatio;A=Math.floor(x/2);O=Math.floor(F/2); -D.width=x;D.height=F;1!==this.devicePixelRatio&&!1!==c&&(D.style.width=a+"px",D.style.height=b+"px");Ha.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O));la.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O));y=1;v=0;oa=ba=J=R=G=null};this.setClearColor=function(a,b){E.set(a);I=void 0!==b?b:1;la.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O))};this.setClearColorHex=function(a,b){console.warn("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.");this.setClearColor(a, -b)};this.getMaxAnisotropy=function(){return 0};this.clear=function(){C.setTransform(1,0,0,-1,A,O);!1===la.empty()&&(la.intersect(Ha),la.expandByScalar(2),1>I&&C.clearRect(la.min.x|0,la.min.y|0,la.max.x-la.min.x|0,la.max.y-la.min.y|0),0<I&&(k(THREE.NormalBlending),i(1),t("rgba("+Math.floor(255*E.r)+","+Math.floor(255*E.g)+","+Math.floor(255*E.b)+","+I+")"),C.fillRect(la.min.x|0,la.min.y|0,la.max.x-la.min.x|0,la.max.y-la.min.y|0)),la.makeEmpty())};this.render=function(a,j){if(!1===j instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera."); -else{!0===this.autoClear&&this.clear();C.setTransform(1,0,0,-1,A,O);q.info.render.vertices=0;q.info.render.faces=0;u=B.projectScene(a,j,this.sortObjects,this.sortElements);w=u.elements;z=u.lights;M=j;gb.setRGB(0,0,0);sa.setRGB(0,0,0);ga.setRGB(0,0,0);for(var D=0,G=z.length;D<G;D++){var y=z[D],F=y.color;y instanceof THREE.AmbientLight?gb.add(F):y instanceof THREE.DirectionalLight?sa.add(F):y instanceof THREE.PointLight&&ga.add(F)}D=0;for(G=w.length;D<G;D++){var x=w[D],v=x.material;if(!(void 0===v|| -!1===v.visible)){ra.makeEmpty();if(x instanceof THREE.RenderableSprite){Q=x;Q.x*=A;Q.y*=O;var y=Q,F=x,J=v;i(J.opacity);k(J.blending);var N=v=x=void 0,E=void 0,I=void 0,R=void 0,ba=void 0;J instanceof THREE.SpriteMaterial||J instanceof THREE.ParticleSystemMaterial?void 0!==J.map.image?(I=J.map.image,R=I.width>>1,ba=I.height>>1,N=F.scale.x*A,E=F.scale.y*O,x=N*R,v=E*ba,ra.min.set(y.x-x,y.y-v),ra.max.set(y.x+x,y.y+v),!1===Ha.isIntersectionBox(ra)?ra.makeEmpty():(C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation), -C.scale(N,-E),C.translate(-R,-ba),C.drawImage(I,0,0),C.restore())):(N=F.object.scale.x,E=F.object.scale.y,N*=F.scale.x*A,E*=F.scale.y*O,ra.min.set(y.x-N,y.y-E),ra.max.set(y.x+N,y.y+E),!1===Ha.isIntersectionBox(ra)?ra.makeEmpty():(t(J.color.getStyle()),C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation),C.scale(N,E),C.fillRect(-1,-1,2,2),C.restore())):J instanceof THREE.SpriteCanvasMaterial&&(x=F.scale.x*A,v=F.scale.y*O,ra.min.set(y.x-x,y.y-v),ra.max.set(y.x+x,y.y+v),!1===Ha.isIntersectionBox(ra)? -ra.makeEmpty():(s(J.color.getStyle()),t(J.color.getStyle()),C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation),C.scale(x,v),J.program(C),C.restore()))}else if(x instanceof THREE.RenderableLine){if(Q=x.v1,K=x.v2,Q.positionScreen.x*=A,Q.positionScreen.y*=O,K.positionScreen.x*=A,K.positionScreen.y*=O,ra.setFromPoints([Q.positionScreen,K.positionScreen]),!0===Ha.isIntersectionBox(ra))if(y=Q,F=K,J=x,x=v,i(x.opacity),k(x.blending),C.beginPath(),C.moveTo(y.positionScreen.x,y.positionScreen.y),C.lineTo(F.positionScreen.x, -F.positionScreen.y),x instanceof THREE.LineBasicMaterial){m(x.linewidth);l(x.linecap);p(x.linejoin);if(x.vertexColors!==THREE.VertexColors)s(x.color.getStyle());else if(v=J.vertexColors[0].getStyle(),J=J.vertexColors[1].getStyle(),v===J)s(v);else{try{var fa=C.createLinearGradient(y.positionScreen.x,y.positionScreen.y,F.positionScreen.x,F.positionScreen.y);fa.addColorStop(0,v);fa.addColorStop(1,J)}catch(oa){fa=v}s(fa)}C.stroke();ra.expandByScalar(2*x.linewidth)}else x instanceof THREE.LineDashedMaterial&& -(m(x.linewidth),l(x.linecap),p(x.linejoin),s(x.color.getStyle()),n(x.dashSize,x.gapSize),C.stroke(),ra.expandByScalar(2*x.linewidth),n(null,null))}else if(x instanceof THREE.RenderableFace3){Q=x.v1;K=x.v2;ca=x.v3;if(-1>Q.positionScreen.z||1<Q.positionScreen.z)continue;if(-1>K.positionScreen.z||1<K.positionScreen.z)continue;if(-1>ca.positionScreen.z||1<ca.positionScreen.z)continue;Q.positionScreen.x*=A;Q.positionScreen.y*=O;K.positionScreen.x*=A;K.positionScreen.y*=O;ca.positionScreen.x*=A;ca.positionScreen.y*= -O;0<v.overdraw&&(g(Q.positionScreen,K.positionScreen,v.overdraw),g(K.positionScreen,ca.positionScreen,v.overdraw),g(ca.positionScreen,Q.positionScreen,v.overdraw));ra.setFromPoints([Q.positionScreen,K.positionScreen,ca.positionScreen]);if(!0===Ha.isIntersectionBox(ra)){y=Q;F=K;J=ca;q.info.render.vertices+=3;q.info.render.faces++;i(v.opacity);k(v.blending);Fa=y.positionScreen.x;Ba=y.positionScreen.y;da=F.positionScreen.x;Aa=F.positionScreen.y;$=J.positionScreen.x;ea=J.positionScreen.y;var N=Fa,E=Ba, -I=da,R=Aa,ba=$,pa=ea;C.beginPath();C.moveTo(N,E);C.lineTo(I,R);C.lineTo(ba,pa);C.closePath();(v instanceof THREE.MeshLambertMaterial||v instanceof THREE.MeshPhongMaterial)&&null===v.map?(ta.copy(v.color),ia.copy(v.emissive),v.vertexColors===THREE.FaceColors&&ta.multiply(x.color),!1===v.wireframe&&v.shading==THREE.SmoothShading&&3==x.vertexNormalsLength?(P.copy(gb),Z.copy(gb),U.copy(gb),b(x.v1.positionWorld,x.vertexNormalsModel[0],P),b(x.v2.positionWorld,x.vertexNormalsModel[1],Z),b(x.v3.positionWorld, -x.vertexNormalsModel[2],U),P.multiply(ta).add(ia),Z.multiply(ta).add(ia),U.multiply(ta).add(ia),ka.addColors(Z,U).multiplyScalar(0.5),Qa=h(P,Z,U,ka),f(Fa,Ba,da,Aa,$,ea,0,0,1,0,0,1,Qa)):(V.copy(gb),b(x.centroidModel,x.normalModel,V),V.multiply(ta).add(ia),!0===v.wireframe?c(V,v.wireframeLinewidth,v.wireframeLinecap,v.wireframeLinejoin):d(V))):v instanceof THREE.MeshBasicMaterial||v instanceof THREE.MeshLambertMaterial||v instanceof THREE.MeshPhongMaterial?null!==v.map?v.map.mapping instanceof THREE.UVMapping&& -(xa=x.uvs[0],e(Fa,Ba,da,Aa,$,ea,xa[0].x,xa[0].y,xa[1].x,xa[1].y,xa[2].x,xa[2].y,v.map)):null!==v.envMap?v.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(ua.copy(x.vertexNormalsModelView[0]),bb=0.5*ua.x+0.5,cb=0.5*ua.y+0.5,ua.copy(x.vertexNormalsModelView[1]),Ma=0.5*ua.x+0.5,fb=0.5*ua.y+0.5,ua.copy(x.vertexNormalsModelView[2]),sb=0.5*ua.x+0.5,pb=0.5*ua.y+0.5,e(Fa,Ba,da,Aa,$,ea,bb,cb,Ma,fb,sb,pb,v.envMap)):(V.copy(v.color),v.vertexColors===THREE.FaceColors&&V.multiply(x.color),!0===v.wireframe? -c(V,v.wireframeLinewidth,v.wireframeLinecap,v.wireframeLinejoin):d(V)):v instanceof THREE.MeshDepthMaterial?(Da=M.near,Ua=M.far,P.r=P.g=P.b=1-r(y.positionScreen.z*y.positionScreen.w,Da,Ua),Z.r=Z.g=Z.b=1-r(F.positionScreen.z*F.positionScreen.w,Da,Ua),U.r=U.g=U.b=1-r(J.positionScreen.z*J.positionScreen.w,Da,Ua),ka.addColors(Z,U).multiplyScalar(0.5),Qa=h(P,Z,U,ka),f(Fa,Ba,da,Aa,$,ea,0,0,1,0,0,1,Qa)):v instanceof THREE.MeshNormalMaterial&&(y=void 0,v.shading==THREE.FlatShading?(y=x.normalModelView,V.setRGB(y.x, -y.y,y.z).multiplyScalar(0.5).addScalar(0.5),!0===v.wireframe?c(V,v.wireframeLinewidth,v.wireframeLinecap,v.wireframeLinejoin):d(V)):v.shading==THREE.SmoothShading&&(y=x.vertexNormalsModelView[0],P.setRGB(y.x,y.y,y.z).multiplyScalar(0.5).addScalar(0.5),y=x.vertexNormalsModelView[1],Z.setRGB(y.x,y.y,y.z).multiplyScalar(0.5).addScalar(0.5),y=x.vertexNormalsModelView[2],U.setRGB(y.x,y.y,y.z).multiplyScalar(0.5).addScalar(0.5),ka.addColors(Z,U).multiplyScalar(0.5),Qa=h(P,Z,U,ka),f(Fa,Ba,da,Aa,$,ea,0,0, -1,0,0,1,Qa)))}}la.union(ra)}}C.setTransform(1,0,0,1,0,0)}}};THREE.ShaderChunk={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n#endif", -envmap_pars_fragment:"#ifdef USE_ENVMAP\nuniform float reflectivity;\nuniform samplerCube envMap;\nuniform float flipEnvMap;\nuniform int combine;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nuniform bool useRefract;\nuniform float refractionRatio;\n#else\nvarying vec3 vReflect;\n#endif\n#endif",envmap_fragment:"#ifdef USE_ENVMAP\nvec3 reflectVec;\n#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nreflectVec = refract( cameraToVertex, normal, refractionRatio );\n} else { \nreflectVec = reflect( cameraToVertex, normal );\n}\n#else\nreflectVec = vReflect;\n#endif\n#ifdef DOUBLE_SIDED\nfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\nvec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#else\nvec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n#endif\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\nif ( combine == 1 ) {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );\n} else if ( combine == 2 ) {\ngl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;\n} else {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );\n}\n#endif", -envmap_pars_vertex:"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\nvarying vec3 vReflect;\nuniform float refractionRatio;\nuniform bool useRefract;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n#ifdef USE_SKINNING\nvec4 worldPosition = modelMatrix * skinned;\n#endif\n#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )\nvec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n#endif\n#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n#endif\n#endif", -envmap_vertex:"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\nvec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;\nworldNormal = normalize( worldNormal );\nvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, worldNormal );\n}\n#endif",map_particle_pars_fragment:"#ifdef USE_MAP\nuniform sampler2D map;\n#endif", -map_particle_fragment:"#ifdef USE_MAP\ngl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );\n#endif",map_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvarying vec2 vUv;\nuniform vec4 offsetRepeat;\n#endif",map_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif", -map_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )\nvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif",map_fragment:"#ifdef USE_MAP\nvec4 texelColor = texture2D( map, vUv );\n#ifdef GAMMA_INPUT\ntexelColor.xyz *= texelColor.xyz;\n#endif\ngl_FragColor = gl_FragColor * texelColor;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\nuniform sampler2D lightMap;\n#endif",lightmap_pars_vertex:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\n#endif", -lightmap_fragment:"#ifdef USE_LIGHTMAP\ngl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );\n#endif",lightmap_vertex:"#ifdef USE_LIGHTMAP\nvUv2 = uv2;\n#endif",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\nuniform sampler2D bumpMap;\nuniform float bumpScale;\nvec2 dHdxy_fwd() {\nvec2 dSTdx = dFdx( vUv );\nvec2 dSTdy = dFdy( vUv );\nfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\nfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\nfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\nreturn vec2( dBx, dBy );\n}\nvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\nvec3 vSigmaX = dFdx( surf_pos );\nvec3 vSigmaY = dFdy( surf_pos );\nvec3 vN = surf_norm;\nvec3 R1 = cross( vSigmaY, vN );\nvec3 R2 = cross( vN, vSigmaX );\nfloat fDet = dot( vSigmaX, R1 );\nvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\nreturn normalize( abs( fDet ) * surf_norm - vGrad );\n}\n#endif", -normalmap_pars_fragment:"#ifdef USE_NORMALMAP\nuniform sampler2D normalMap;\nuniform vec2 normalScale;\nvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\nvec3 q0 = dFdx( eye_pos.xyz );\nvec3 q1 = dFdy( eye_pos.xyz );\nvec2 st0 = dFdx( vUv.st );\nvec2 st1 = dFdy( vUv.st );\nvec3 S = normalize( q0 * st1.t - q1 * st0.t );\nvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\nvec3 N = normalize( surf_norm );\nvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\nmapN.xy = normalScale * mapN.xy;\nmat3 tsn = mat3( S, T, N );\nreturn normalize( tsn * mapN );\n}\n#endif", -specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\nuniform sampler2D specularMap;\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\nvec4 texelSpecular = texture2D( specularMap, vUv );\nspecularStrength = texelSpecular.r;\n#else\nspecularStrength = 1.0;\n#endif",lights_lambert_pars_vertex:"uniform vec3 ambient;\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", -lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\nvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n#ifdef DOUBLE_SIDED\nvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", -lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif", -lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvWorldPosition = worldPosition.xyz;\n#endif", -lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", -lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#ifdef USE_NORMALMAP\nnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\nnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += diffuse * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", -color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, 1.0 );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n#ifdef BONE_TEXTURE\nuniform sampler2D boneTexture;\nuniform int boneTextureWidth;\nuniform int boneTextureHeight;\nmat4 getBoneMatrix( const in float i ) {\nfloat j = i * 4.0;\nfloat x = mod( j, float( boneTextureWidth ) );\nfloat y = floor( j / float( boneTextureWidth ) );\nfloat dx = 1.0 / float( boneTextureWidth );\nfloat dy = 1.0 / float( boneTextureHeight );\ny = dy * ( y + 0.5 );\nvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\nvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\nvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\nvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\nmat4 bone = mat4( v1, v2, v3, v4 );\nreturn bone;\n}\n#else\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\nmat4 getBoneMatrix( const in float i ) {\nmat4 bone = boneGlobalMatrices[ int(i) ];\nreturn bone;\n}\n#endif\n#endif", -skinbase_vertex:"#ifdef USE_SKINNING\nmat4 boneMatX = getBoneMatrix( skinIndex.x );\nmat4 boneMatY = getBoneMatrix( skinIndex.y );\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n#ifdef USE_MORPHTARGETS\nvec4 skinVertex = vec4( morphed, 1.0 );\n#else\nvec4 skinVertex = vec4( position, 1.0 );\n#endif\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif", -morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\n#endif", -default_vertex:"vec4 mvPosition;\n#ifdef USE_SKINNING\nmvPosition = modelViewMatrix * skinned;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( position, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\n#endif", -skinnormal_vertex:"#ifdef USE_SKINNING\nmat4 skinMatrix = skinWeight.x * boneMatX;\nskinMatrix \t+= skinWeight.y * boneMatY;\n#ifdef USE_MORPHNORMALS\nvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n#else\nvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n#endif\n#endif",defaultnormal_vertex:"vec3 objectNormal;\n#ifdef USE_SKINNING\nobjectNormal = skinnedNormal.xyz;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )\nobjectNormal = morphedNormal;\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )\nobjectNormal = normal;\n#endif\n#ifdef FLIP_SIDED\nobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;", -shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#if defined( SHADOWMAP_TYPE_PCF )\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\nfloat shadow = 0.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.0 * xPixelOffset;\nfloat dy0 = -1.0 * yPixelOffset;\nfloat dx1 = 1.0 * xPixelOffset;\nfloat dy1 = 1.0 * yPixelOffset;\nmat3 shadowKernel;\nmat3 depthKernel;\ndepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\ndepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\ndepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\ndepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\ndepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\ndepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\ndepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\ndepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\ndepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nvec3 shadowZ = vec3( shadowCoord.z );\nshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\nshadowKernel[0] *= vec3(0.25);\nshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\nshadowKernel[1] *= vec3(0.25);\nshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\nshadowKernel[2] *= vec3(0.25);\nvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\nshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\nshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\nvec4 shadowValues;\nshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\nshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\nshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\nshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\nshadow = dot( shadowValues, vec4( 1.0 ) );\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", -shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; -THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b<a.length;b++)for(c in d=this.clone(a[b]),d)e[c]=d[c];return e},clone:function(a){var b,c,d,e={};for(b in a)for(c in e[b]={},a[b])d=a[b][c],e[b][c]=d instanceof THREE.Color||d instanceof THREE.Vector2||d instanceof THREE.Vector3||d instanceof THREE.Vector4||d instanceof THREE.Matrix4||d instanceof THREE.Texture?d.clone():d instanceof Array?d.slice():d;return e}}; -THREE.UniformsLib={common:{diffuse:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},lightMap:{type:"t",value:null},specularMap:{type:"t",value:null},envMap:{type:"t",value:null},flipEnvMap:{type:"f",value:-1},useRefract:{type:"i",value:0},reflectivity:{type:"f",value:1},refractionRatio:{type:"f",value:0.98},combine:{type:"i",value:0},morphTargetInfluences:{type:"f",value:0}},bump:{bumpMap:{type:"t", -value:null},bumpScale:{type:"f",value:1}},normalmap:{normalMap:{type:"t",value:null},normalScale:{type:"v2",value:new THREE.Vector2(1,1)}},fog:{fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{ambientLightColor:{type:"fv",value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},hemisphereLightDirection:{type:"fv",value:[]},hemisphereLightSkyColor:{type:"fv", -value:[]},hemisphereLightGroundColor:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightDistance:{type:"fv1",value:[]},spotLightColor:{type:"fv",value:[]},spotLightPosition:{type:"fv",value:[]},spotLightDirection:{type:"fv",value:[]},spotLightDistance:{type:"fv1",value:[]},spotLightAngleCos:{type:"fv1",value:[]},spotLightExponent:{type:"fv1",value:[]}},particle:{psColor:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},size:{type:"f", -value:1},scale:{type:"f",value:1},map:{type:"t",value:null},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},shadowmap:{shadowMap:{type:"tv",value:[]},shadowMapSize:{type:"v2v",value:[]},shadowBias:{type:"fv1",value:[]},shadowDarkness:{type:"fv1",value:[]},shadowMatrix:{type:"m4v",value:[]}}}; -THREE.ShaderLib={basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.shadowmap]),vertexShader:[THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex, -THREE.ShaderChunk.skinbase_vertex,"#ifdef USE_ENVMAP",THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"#endif",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment, -THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment, -THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(16777215)},emissive:{type:"c",value:new THREE.Color(0)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif", -THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_lambert_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex, -THREE.ShaderChunk.defaultnormal_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment, -THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,"#ifdef DOUBLE_SIDED\nif ( gl_FrontFacing )\ngl_FragColor.xyz *= vLightFront;\nelse\ngl_FragColor.xyz *= vLightBack;\n#else\ngl_FragColor.xyz *= vLightFront;\n#endif",THREE.ShaderChunk.lightmap_fragment, -THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.bump,THREE.UniformsLib.normalmap,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(16777215)},emissive:{type:"c",value:new THREE.Color(0)},specular:{type:"c", -value:new THREE.Color(1118481)},shininess:{type:"f",value:30},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define PHONG\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_phong_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex, -"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"vNormal = normalize( transformedNormal );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"vViewPosition = -mvPosition.xyz;",THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex, -THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform vec3 ambient;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.lights_phong_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment, -THREE.ShaderChunk.bumpmap_pars_fragment,THREE.ShaderChunk.normalmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment, -THREE.ShaderChunk.fog_fragment,"}"].join("\n")},particle_basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.particle,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n#ifdef USE_SIZEATTENUATION\ngl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n#else\ngl_PointSize = size;\n#endif\ngl_Position = projectionMatrix * mvPosition;", -THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_particle_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( psColor, opacity );",THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.shadowmap_fragment, -THREE.ShaderChunk.fog_fragment,"}"].join("\n")},dashed:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,{scale:{type:"f",value:1},dashSize:{type:"f",value:1},totalSize:{type:"f",value:2}}]),vertexShader:["uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;",THREE.ShaderChunk.color_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"vLineDistance = scale * lineDistance;\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n}"].join("\n"), -fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\nif ( mod( vLineDistance, totalSize ) > dashSize ) {\ndiscard;\n}\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f", -value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.morphtarget_pars_vertex,"void main() {\nvNormal = normalize( normalMatrix * normal );", -THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i", -value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f", -value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0},uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\n#ifdef FLIP_SIDED\nfinalNormal = -finalNormal;\n#endif\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\nfloat pointDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\npointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\npointVector = normalize( pointVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\nfloat spotDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\nspotVector = normalize( spotVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n#endif\nspotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;\nvec3 spotHalfVector = normalize( spotVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += uDiffuseColor * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;\n#endif\nif ( enableReflection ) {\nvec3 vReflect;\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, normal, uRefractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, normal );\n}\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", -THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", -THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING\nvNormal = normalize( normalMatrix * skinnedNormal.xyz );\nvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\nvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n#else\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\n#endif\nvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\nvUv = uv * uRepeat + uOffset;\nvec3 displacedPosition;\n#ifdef VERTEX_TEXTURES\nif ( enableDisplacement ) {\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\ndisplacedPosition = position + normalize( normal ) * df;\n} else {\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n}\n#else\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n#endif\nvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\nvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\nvWorldPosition = worldPosition.xyz;\nvViewPosition = -mvPosition.xyz;\n#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif\n}"].join("\n")}, -cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vWorldPosition;\nvoid main() {\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\nvWorldPosition = worldPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\nvoid main() {\ngl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n}"}, -depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};THREE.WebGLRenderer=function(a){function b(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var h=1;"v2"===f.type?h=2:"v3"===f.type?h=3:"v4"===f.type?h=4:"c"===f.type&&(h=3);f.size=h;f.array=new Float32Array(c*h);f.buffer=j.createBuffer();f.buffer.belongsToAttribute=e;f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}} -function c(a,b){var c=b.geometry,h=a.faces3,g=3*h.length,i=1*h.length,k=3*h.length,h=d(b,a),m=f(h),l=e(h),p=h.vertexColors?h.vertexColors:!1;a.__vertexArray=new Float32Array(3*g);l&&(a.__normalArray=new Float32Array(3*g));c.hasTangents&&(a.__tangentArray=new Float32Array(4*g));p&&(a.__colorArray=new Float32Array(3*g));m&&(0<c.faceVertexUvs.length&&(a.__uvArray=new Float32Array(2*g)),1<c.faceVertexUvs.length&&(a.__uv2Array=new Float32Array(2*g)));b.geometry.skinWeights.length&&b.geometry.skinIndices.length&& -(a.__skinIndexArray=new Float32Array(4*g),a.__skinWeightArray=new Float32Array(4*g));a.__faceArray=new Uint16Array(3*i);a.__lineArray=new Uint16Array(2*k);if(a.numMorphTargets){a.__morphTargetsArrays=[];c=0;for(m=a.numMorphTargets;c<m;c++)a.__morphTargetsArrays.push(new Float32Array(3*g))}if(a.numMorphNormals){a.__morphNormalsArrays=[];c=0;for(m=a.numMorphNormals;c<m;c++)a.__morphNormalsArrays.push(new Float32Array(3*g))}a.__webglFaceCount=3*i;a.__webglLineCount=2*k;if(h.attributes){void 0===a.__webglCustomAttributesList&& -(a.__webglCustomAttributesList=[]);for(var n in h.attributes){var i=h.attributes[n],k={},r;for(r in i)k[r]=i[r];if(!k.__webglInitialized||k.createUniqueBuffers)k.__webglInitialized=!0,c=1,"v2"===k.type?c=2:"v3"===k.type?c=3:"v4"===k.type?c=4:"c"===k.type&&(c=3),k.size=c,k.array=new Float32Array(g*c),k.buffer=j.createBuffer(),k.buffer.belongsToAttribute=n,i.needsUpdate=!0,k.__original=i;a.__webglCustomAttributesList.push(k)}}a.__inittedArrays=!0}function d(a,b){return a.material instanceof THREE.MeshFaceMaterial? -a.material.materials[b.materialIndex]:a.material}function e(a){return a instanceof THREE.MeshBasicMaterial&&!a.envMap||a instanceof THREE.MeshDepthMaterial?!1:a&&void 0!==a.shading&&a.shading===THREE.SmoothShading?THREE.SmoothShading:THREE.FlatShading}function f(a){return a.map||a.lightMap||a.bumpMap||a.normalMap||a.specularMap||a instanceof THREE.ShaderMaterial?!0:!1}function h(a){Ha[a]||(j.enableVertexAttribArray(a),Ha[a]=!0)}function g(){for(var a in Ha)Ha[a]&&(j.disableVertexAttribArray(a),Ha[a]= -!1)}function i(a,b){return a.z!==b.z?b.z-a.z:a.id-b.id}function k(a,b){return b[0]-a[0]}function m(a,b,c){if(a.length)for(var d=0,e=a.length;d<e;d++)ea=Ba=null,Aa=$=U=Z=fa=Ga=ka=-1,ua=!0,a[d].render(b,c,sb,pb),ea=Ba=null,Aa=$=U=Z=fa=Ga=ka=-1,ua=!0}function l(a,b,c,d,e,f,h,g){var j,i,k,m;b?(i=a.length-1,m=b=-1):(i=0,b=a.length,m=1);for(var l=i;l!==b;l+=m)if(j=a[l],j.render){i=j.object;k=j.buffer;if(g)j=g;else{j=j[c];if(!j)continue;h&&K.setBlending(j.blending,j.blendEquation,j.blendSrc,j.blendDst); -K.setDepthTest(j.depthTest);K.setDepthWrite(j.depthWrite);A(j.polygonOffset,j.polygonOffsetFactor,j.polygonOffsetUnits)}K.setMaterialFaces(j);k instanceof THREE.BufferGeometry?K.renderBufferDirect(d,e,f,j,k,i):K.renderBuffer(d,e,f,j,k,i)}}function p(a,b,c,d,e,f,h){for(var g,j,i=0,k=a.length;i<k;i++)if(g=a[i],j=g.object,j.visible){if(h)g=h;else{g=g[b];if(!g)continue;f&&K.setBlending(g.blending,g.blendEquation,g.blendSrc,g.blendDst);K.setDepthTest(g.depthTest);K.setDepthWrite(g.depthWrite);A(g.polygonOffset, -g.polygonOffsetFactor,g.polygonOffsetUnits)}K.renderImmediateObject(c,d,e,g,j)}}function s(a,d){var e,f,h,g;if(void 0===a.__webglInit&&(a.__webglInit=!0,a._modelViewMatrix=new THREE.Matrix4,a._normalMatrix=new THREE.Matrix3,void 0!==a.geometry&&void 0===a.geometry.__webglInit&&(a.geometry.__webglInit=!0,a.geometry.addEventListener("dispose",Cb)),f=a.geometry,void 0!==f))if(f instanceof THREE.BufferGeometry){var i,k;for(i in f.attributes)k="index"===i?j.ELEMENT_ARRAY_BUFFER:j.ARRAY_BUFFER,g=f.attributes[i], -void 0===g.numItems&&(g.numItems=g.array.length),g.buffer=j.createBuffer(),j.bindBuffer(k,g.buffer),j.bufferData(k,g.array,j.STATIC_DRAW)}else if(a instanceof THREE.Mesh){h=a.material;if(void 0===f.geometryGroups){i=f;var m,l,p;k={};var n=i.morphTargets.length,r=i.morphNormals.length,s=h instanceof THREE.MeshFaceMaterial;i.geometryGroups={};h=0;for(m=i.faces.length;h<m;h++)l=i.faces[h],l=s?l.materialIndex:0,void 0===k[l]&&(k[l]={hash:l,counter:0}),p=k[l].hash+"_"+k[l].counter,void 0===i.geometryGroups[p]&& -(i.geometryGroups[p]={faces3:[],materialIndex:l,vertices:0,numMorphTargets:n,numMorphNormals:r}),65535<i.geometryGroups[p].vertices+3&&(k[l].counter+=1,p=k[l].hash+"_"+k[l].counter,void 0===i.geometryGroups[p]&&(i.geometryGroups[p]={faces3:[],materialIndex:l,vertices:0,numMorphTargets:n,numMorphNormals:r})),i.geometryGroups[p].faces3.push(h),i.geometryGroups[p].vertices+=3;i.geometryGroupsList=[];for(g in i.geometryGroups)i.geometryGroups[g].id=V++,i.geometryGroupsList.push(i.geometryGroups[g])}for(e in f.geometryGroups)if(g= -f.geometryGroups[e],!g.__webglVertexBuffer){i=g;i.__webglVertexBuffer=j.createBuffer();i.__webglNormalBuffer=j.createBuffer();i.__webglTangentBuffer=j.createBuffer();i.__webglColorBuffer=j.createBuffer();i.__webglUVBuffer=j.createBuffer();i.__webglUV2Buffer=j.createBuffer();i.__webglSkinIndicesBuffer=j.createBuffer();i.__webglSkinWeightsBuffer=j.createBuffer();i.__webglFaceBuffer=j.createBuffer();i.__webglLineBuffer=j.createBuffer();n=k=void 0;if(i.numMorphTargets){i.__webglMorphTargetsBuffers=[]; -k=0;for(n=i.numMorphTargets;k<n;k++)i.__webglMorphTargetsBuffers.push(j.createBuffer())}if(i.numMorphNormals){i.__webglMorphNormalsBuffers=[];k=0;for(n=i.numMorphNormals;k<n;k++)i.__webglMorphNormalsBuffers.push(j.createBuffer())}K.info.memory.geometries++;c(g,a);f.verticesNeedUpdate=!0;f.morphTargetsNeedUpdate=!0;f.elementsNeedUpdate=!0;f.uvsNeedUpdate=!0;f.normalsNeedUpdate=!0;f.tangentsNeedUpdate=!0;f.colorsNeedUpdate=!0}}else a instanceof THREE.Line?f.__webglVertexBuffer||(g=f,g.__webglVertexBuffer= -j.createBuffer(),g.__webglColorBuffer=j.createBuffer(),g.__webglLineDistanceBuffer=j.createBuffer(),K.info.memory.geometries++,g=f,i=g.vertices.length,g.__vertexArray=new Float32Array(3*i),g.__colorArray=new Float32Array(3*i),g.__lineDistanceArray=new Float32Array(1*i),g.__webglLineCount=i,b(g,a),f.verticesNeedUpdate=!0,f.colorsNeedUpdate=!0,f.lineDistancesNeedUpdate=!0):a instanceof THREE.ParticleSystem&&!f.__webglVertexBuffer&&(g=f,g.__webglVertexBuffer=j.createBuffer(),g.__webglColorBuffer=j.createBuffer(), -K.info.memory.geometries++,g=f,i=g.vertices.length,g.__vertexArray=new Float32Array(3*i),g.__colorArray=new Float32Array(3*i),g.__sortArray=[],g.__webglParticleCount=i,b(g,a),f.verticesNeedUpdate=!0,f.colorsNeedUpdate=!0);if(void 0===a.__webglActive){if(a instanceof THREE.Mesh)if(f=a.geometry,f instanceof THREE.BufferGeometry)t(d.__webglObjects,f,a);else{if(f instanceof THREE.Geometry)for(e in f.geometryGroups)g=f.geometryGroups[e],t(d.__webglObjects,g,a)}else a instanceof THREE.Line||a instanceof -THREE.ParticleSystem?(f=a.geometry,t(d.__webglObjects,f,a)):a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback?d.__webglObjectsImmediate.push({id:null,object:a,opaque:null,transparent:null,z:0}):a instanceof THREE.Sprite?d.__webglSprites.push(a):a instanceof THREE.LensFlare&&d.__webglFlares.push(a);a.__webglActive=!0}}function t(a,b,c){a.push({id:null,buffer:b,object:c,opaque:null,transparent:null,z:0})}function n(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0; -return!1}function r(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}function q(a,b){a instanceof THREE.Mesh||a instanceof THREE.ParticleSystem||a instanceof THREE.Line?u(b.__webglObjects,a):a instanceof THREE.Sprite?w(b.__webglSprites,a):a instanceof THREE.LensFlare?w(b.__webglFlares,a):(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)&&u(b.__webglObjectsImmediate,a);delete a.__webglActive}function u(a,b){for(var c=a.length-1;0<=c;c--)a[c].object===b&&a.splice(c,1)} -function w(a,b){for(var c=a.length-1;0<=c;c--)a[c]===b&&a.splice(c,1)}function z(a,b,c,d,e){P=0;d.needsUpdate&&(d.program&&Gb(d),K.initMaterial(d,b,c,e),d.needsUpdate=!1);d.morphTargets&&!e.__webglMorphTargetInfluences&&(e.__webglMorphTargetInfluences=new Float32Array(K.maxMorphTargets));var f=!1,g=d.program,h=g.uniforms,i=d.uniforms;g!==Ba&&(j.useProgram(g),Ba=g,f=!0);d.id!==Aa&&(Aa=d.id,f=!0);if(f||a!==ea)j.uniformMatrix4fv(h.projectionMatrix,!1,a.projectionMatrix.elements),a!==ea&&(ea=a);if(d.skinning)if(yb&& -e.useVertexTexture){if(null!==h.boneTexture){var k=B();j.uniform1i(h.boneTexture,k);K.setTexture(e.boneTexture,k)}null!==h.boneTextureWidth&&j.uniform1i(h.boneTextureWidth,e.boneTextureWidth);null!==h.boneTextureHeight&&j.uniform1i(h.boneTextureHeight,e.boneTextureHeight)}else null!==h.boneGlobalMatrices&&j.uniformMatrix4fv(h.boneGlobalMatrices,!1,e.boneMatrices);if(f){c&&d.fog&&(i.fogColor.value=c.color,c instanceof THREE.Fog?(i.fogNear.value=c.near,i.fogFar.value=c.far):c instanceof THREE.FogExp2&& -(i.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(ua){for(var m,l=k=0,p=0,n,r,s,q=Pa,t=q.directional.colors,u=q.directional.positions,w=q.point.colors,z=q.point.positions,y=q.point.distances,A=q.spot.colors,C=q.spot.positions,F=q.spot.distances,J=q.spot.directions,N=q.spot.anglesCos,O=q.spot.exponents,I=q.hemi.skyColors,V=q.hemi.groundColors,R=q.hemi.positions,M=0,U=0,da=0,Z=0,Fa=0,dc=0,X=0,W=0,Q=m=0,c=s=Q=0,f=b.length;c< -f;c++)m=b[c],m.onlyShadow||(n=m.color,r=m.intensity,s=m.distance,m instanceof THREE.AmbientLight?m.visible&&(K.gammaInput?(k+=n.r*n.r,l+=n.g*n.g,p+=n.b*n.b):(k+=n.r,l+=n.g,p+=n.b)):m instanceof THREE.DirectionalLight?(Fa+=1,m.visible&&(ga.getPositionFromMatrix(m.matrixWorld),sa.getPositionFromMatrix(m.target.matrixWorld),ga.sub(sa),ga.normalize(),0===ga.x&&0===ga.y&&0===ga.z||(m=3*M,u[m]=ga.x,u[m+1]=ga.y,u[m+2]=ga.z,K.gammaInput?D(t,m,n,r*r):x(t,m,n,r),M+=1))):m instanceof THREE.PointLight?(dc+=1, -m.visible&&(Q=3*U,K.gammaInput?D(w,Q,n,r*r):x(w,Q,n,r),sa.getPositionFromMatrix(m.matrixWorld),z[Q]=sa.x,z[Q+1]=sa.y,z[Q+2]=sa.z,y[U]=s,U+=1)):m instanceof THREE.SpotLight?(X+=1,m.visible&&(Q=3*da,K.gammaInput?D(A,Q,n,r*r):x(A,Q,n,r),sa.getPositionFromMatrix(m.matrixWorld),C[Q]=sa.x,C[Q+1]=sa.y,C[Q+2]=sa.z,F[da]=s,ga.copy(sa),sa.getPositionFromMatrix(m.target.matrixWorld),ga.sub(sa),ga.normalize(),J[Q]=ga.x,J[Q+1]=ga.y,J[Q+2]=ga.z,N[da]=Math.cos(m.angle),O[da]=m.exponent,da+=1)):m instanceof THREE.HemisphereLight&& -(W+=1,m.visible&&(ga.getPositionFromMatrix(m.matrixWorld),ga.normalize(),0===ga.x&&0===ga.y&&0===ga.z||(s=3*Z,R[s]=ga.x,R[s+1]=ga.y,R[s+2]=ga.z,n=m.color,m=m.groundColor,K.gammaInput?(r*=r,D(I,s,n,r),D(V,s,m,r)):(x(I,s,n,r),x(V,s,m,r)),Z+=1))));c=3*M;for(f=Math.max(t.length,3*Fa);c<f;c++)t[c]=0;c=3*U;for(f=Math.max(w.length,3*dc);c<f;c++)w[c]=0;c=3*da;for(f=Math.max(A.length,3*X);c<f;c++)A[c]=0;c=3*Z;for(f=Math.max(I.length,3*W);c<f;c++)I[c]=0;c=3*Z;for(f=Math.max(V.length,3*W);c<f;c++)V[c]=0;q.directional.length= -M;q.point.length=U;q.spot.length=da;q.hemi.length=Z;q.ambient[0]=k;q.ambient[1]=l;q.ambient[2]=p;ua=!1}c=Pa;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.spotLightAngleCos.value=c.spot.anglesCos;i.spotLightExponent.value=c.spot.exponents;i.hemisphereLightSkyColor.value=c.hemi.skyColors;i.hemisphereLightGroundColor.value=c.hemi.groundColors;i.hemisphereLightDirection.value=c.hemi.positions}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){i.opacity.value=d.opacity;K.gammaInput?i.diffuse.value.copyGammaToLinear(d.color):i.diffuse.value= -d.color;i.map.value=d.map;i.lightMap.value=d.lightMap;i.specularMap.value=d.specularMap;d.bumpMap&&(i.bumpMap.value=d.bumpMap,i.bumpScale.value=d.bumpScale);d.normalMap&&(i.normalMap.value=d.normalMap,i.normalScale.value.copy(d.normalScale));var $;d.map?$=d.map:d.specularMap?$=d.specularMap:d.normalMap?$=d.normalMap:d.bumpMap&&($=d.bumpMap);void 0!==$&&(c=$.offset,$=$.repeat,i.offsetRepeat.value.set(c.x,c.y,$.x,$.y));i.envMap.value=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}d instanceof THREE.LineBasicMaterial?(i.diffuse.value=d.color,i.opacity.value=d.opacity):d instanceof THREE.LineDashedMaterial?(i.diffuse.value=d.color,i.opacity.value=d.opacity,i.dashSize.value=d.dashSize,i.totalSize.value=d.dashSize+d.gapSize,i.scale.value=d.scale):d instanceof THREE.ParticleSystemMaterial? -(i.psColor.value=d.color,i.opacity.value=d.opacity,i.size.value=d.size,i.scale.value=G.height/2,i.map.value=d.map):d instanceof THREE.MeshPhongMaterial?(i.shininess.value=d.shininess,K.gammaInput?(i.ambient.value.copyGammaToLinear(d.ambient),i.emissive.value.copyGammaToLinear(d.emissive),i.specular.value.copyGammaToLinear(d.specular)):(i.ambient.value=d.ambient,i.emissive.value=d.emissive,i.specular.value=d.specular),d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshLambertMaterial? -(K.gammaInput?(i.ambient.value.copyGammaToLinear(d.ambient),i.emissive.value.copyGammaToLinear(d.emissive)):(i.ambient.value=d.ambient,i.emissive.value=d.emissive),d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshDepthMaterial?(i.mNear.value=a.near,i.mFar.value=a.far,i.opacity.value=d.opacity):d instanceof THREE.MeshNormalMaterial&&(i.opacity.value=d.opacity);if(e.receiveShadow&&!d._shadowPass&&i.shadowMatrix){c=$=0;for(f=b.length;c<f;c++)if(k=b[c],k.castShadow&&(k instanceof -THREE.SpotLight||k instanceof THREE.DirectionalLight&&!k.shadowCascade))i.shadowMap.value[$]=k.shadowMap,i.shadowMapSize.value[$]=k.shadowMapSize,i.shadowMatrix.value[$]=k.shadowMatrix,i.shadowDarkness.value[$]=k.shadowDarkness,i.shadowBias.value[$]=k.shadowBias,$++}b=d.uniformsList;i=0;for($=b.length;i<$;i++)if(f=g.uniforms[b[i][1]])if(c=b[i][0],l=c.type,k=c.value,"i"===l)j.uniform1i(f,k);else if("f"===l)j.uniform1f(f,k);else if("v2"===l)j.uniform2f(f,k.x,k.y);else if("v3"===l)j.uniform3f(f,k.x, -k.y,k.z);else if("v4"===l)j.uniform4f(f,k.x,k.y,k.z,k.w);else if("c"===l)j.uniform3f(f,k.r,k.g,k.b);else if("iv1"===l)j.uniform1iv(f,k);else if("iv"===l)j.uniform3iv(f,k);else if("fv1"===l)j.uniform1fv(f,k);else if("fv"===l)j.uniform3fv(f,k);else if("v2v"===l){void 0===c._array&&(c._array=new Float32Array(2*k.length));l=0;for(p=k.length;l<p;l++)q=2*l,c._array[q]=k[l].x,c._array[q+1]=k[l].y;j.uniform2fv(f,c._array)}else if("v3v"===l){void 0===c._array&&(c._array=new Float32Array(3*k.length));l=0;for(p= -k.length;l<p;l++)q=3*l,c._array[q]=k[l].x,c._array[q+1]=k[l].y,c._array[q+2]=k[l].z;j.uniform3fv(f,c._array)}else if("v4v"===l){void 0===c._array&&(c._array=new Float32Array(4*k.length));l=0;for(p=k.length;l<p;l++)q=4*l,c._array[q]=k[l].x,c._array[q+1]=k[l].y,c._array[q+2]=k[l].z,c._array[q+3]=k[l].w;j.uniform4fv(f,c._array)}else if("m4"===l)void 0===c._array&&(c._array=new Float32Array(16)),k.flattenToArray(c._array),j.uniformMatrix4fv(f,!1,c._array);else if("m4v"===l){void 0===c._array&&(c._array= -new Float32Array(16*k.length));l=0;for(p=k.length;l<p;l++)k[l].flattenToArrayOffset(c._array,16*l);j.uniformMatrix4fv(f,!1,c._array)}else if("t"===l){if(q=k,k=B(),j.uniform1i(f,k),q)if(q.image instanceof Array&&6===q.image.length){if(c=q,f=k,6===c.image.length)if(c.needsUpdate){c.image.__webglTextureCube||(c.addEventListener("dispose",Db),c.image.__webglTextureCube=j.createTexture(),K.info.memory.textures++);j.activeTexture(j.TEXTURE0+f);j.bindTexture(j.TEXTURE_CUBE_MAP,c.image.__webglTextureCube); -j.pixelStorei(j.UNPACK_FLIP_Y_WEBGL,c.flipY);f=c instanceof THREE.CompressedTexture;k=[];for(l=0;6>l;l++)K.autoScaleCubemaps&&!f?(p=k,q=l,t=c.image[l],w=ac,t.width<=w&&t.height<=w||(z=Math.max(t.width,t.height),u=Math.floor(t.width*w/z),w=Math.floor(t.height*w/z),z=document.createElement("canvas"),z.width=u,z.height=w,z.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,u,w),t=z),p[q]=t):k[l]=c.image[l];l=k[0];p=0===(l.width&l.width-1)&&0===(l.height&l.height-1);q=v(c.format);t=v(c.type);E(j.TEXTURE_CUBE_MAP, -c,p);for(l=0;6>l;l++)if(f){w=k[l].mipmaps;z=0;for(y=w.length;z<y;z++)u=w[z],c.format!==THREE.RGBAFormat?j.compressedTexImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,z,q,u.width,u.height,0,u.data):j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,z,q,u.width,u.height,0,q,t,u.data)}else j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,0,q,q,t,k[l]);c.generateMipmaps&&p&&j.generateMipmap(j.TEXTURE_CUBE_MAP);c.needsUpdate=!1;if(c.onUpdate)c.onUpdate()}else j.activeTexture(j.TEXTURE0+f),j.bindTexture(j.TEXTURE_CUBE_MAP, -c.image.__webglTextureCube)}else q instanceof THREE.WebGLRenderTargetCube?(c=q,j.activeTexture(j.TEXTURE0+k),j.bindTexture(j.TEXTURE_CUBE_MAP,c.__webglTexture)):K.setTexture(q,k)}else if("tv"===l){void 0===c._array&&(c._array=[]);l=0;for(p=c.value.length;l<p;l++)c._array[l]=B();j.uniform1iv(f,c._array);l=0;for(p=c.value.length;l<p;l++)q=c.value[l],k=c._array[l],q&&K.setTexture(q,k)}else console.warn("THREE.WebGLRenderer: Unknown uniform type: "+l);if((d instanceof THREE.ShaderMaterial||d instanceof -THREE.MeshPhongMaterial||d.envMap)&&null!==h.cameraPosition)sa.getPositionFromMatrix(a.matrixWorld),j.uniform3f(h.cameraPosition,sa.x,sa.y,sa.z);(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==h.viewMatrix&&j.uniformMatrix4fv(h.viewMatrix,!1,a.matrixWorldInverse.elements)}j.uniformMatrix4fv(h.modelViewMatrix,!1,e._modelViewMatrix.elements);h.normalMatrix&&j.uniformMatrix3fv(h.normalMatrix,!1,e._normalMatrix.elements); -null!==h.modelMatrix&&j.uniformMatrix4fv(h.modelMatrix,!1,e.matrixWorld.elements);return g}function B(){var a=P;a>=Mb&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Mb);P+=1;return a}function D(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function x(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function F(a){a!==xa&&(j.lineWidth(a),xa=a)}function A(a,b,c){Da!==a&&(a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL),Da=a); -if(a&&(Ua!==b||Qa!==c))j.polygonOffset(b,c),Ua=b,Qa=c}function O(a){for(var a=a.split("\n"),b=0,c=a.length;b<c;b++)a[b]=b+1+": "+a[b];return a.join("\n")}function C(a,b){var c;"fragment"===a?c=j.createShader(j.FRAGMENT_SHADER):"vertex"===a&&(c=j.createShader(j.VERTEX_SHADER));j.shaderSource(c,b);j.compileShader(c);return!j.getShaderParameter(c,j.COMPILE_STATUS)?(console.error(j.getShaderInfoLog(c)),console.error(O(b)),null):c}function E(a,b,c){c?(j.texParameteri(a,j.TEXTURE_WRAP_S,v(b.wrapS)),j.texParameteri(a, -j.TEXTURE_WRAP_T,v(b.wrapT)),j.texParameteri(a,j.TEXTURE_MAG_FILTER,v(b.magFilter)),j.texParameteri(a,j.TEXTURE_MIN_FILTER,v(b.minFilter))):(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,y(b.magFilter)),j.texParameteri(a,j.TEXTURE_MIN_FILTER,y(b.minFilter)));if(wa&&b.type!==THREE.FloatType&&(1<b.anisotropy||b.__oldAnisotropy))j.texParameterf(a,wa.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,Nb)),b.__oldAnisotropy= -b.anisotropy}function I(a,b){j.bindRenderbuffer(j.RENDERBUFFER,a);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)):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)):j.renderbufferStorage(j.RENDERBUFFER,j.RGBA4,b.width,b.height)} -function y(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?j.NEAREST:j.LINEAR}function v(a){if(a===THREE.RepeatWrapping)return j.REPEAT;if(a===THREE.ClampToEdgeWrapping)return j.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return j.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return j.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return j.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return j.NEAREST_MIPMAP_LINEAR;if(a=== -THREE.LinearFilter)return j.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return j.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return j.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return j.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return j.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return j.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return j.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return j.BYTE;if(a===THREE.ShortType)return j.SHORT;if(a=== -THREE.UnsignedShortType)return j.UNSIGNED_SHORT;if(a===THREE.IntType)return j.INT;if(a===THREE.UnsignedIntType)return j.UNSIGNED_INT;if(a===THREE.FloatType)return j.FLOAT;if(a===THREE.AlphaFormat)return j.ALPHA;if(a===THREE.RGBFormat)return j.RGB;if(a===THREE.RGBAFormat)return j.RGBA;if(a===THREE.LuminanceFormat)return j.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return j.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return j.FUNC_ADD;if(a===THREE.SubtractEquation)return j.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return j.FUNC_REVERSE_SUBTRACT; -if(a===THREE.ZeroFactor)return j.ZERO;if(a===THREE.OneFactor)return j.ONE;if(a===THREE.SrcColorFactor)return j.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return j.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return j.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return j.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return j.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return j.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return j.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return j.ONE_MINUS_DST_COLOR; -if(a===THREE.SrcAlphaSaturateFactor)return j.SRC_ALPHA_SATURATE;if(void 0!==Ea){if(a===THREE.RGB_S3TC_DXT1_Format)return Ea.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT1_Format)return Ea.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return Ea.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return Ea.COMPRESSED_RGBA_S3TC_DXT5_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);var a=a||{},G=void 0!==a.canvas?a.canvas:document.createElement("canvas"), -R=void 0!==a.precision?a.precision:"highp",J=void 0!==a.alpha?a.alpha:!0,ba=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,oa=void 0!==a.antialias?a.antialias:!1,pa=void 0!==a.stencil?a.stencil:!0,N=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,M=new THREE.Color(0),Q=0;this.domElement=G;this.context=null;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==self.devicePixelRatio?self.devicePixelRatio:1;this.autoUpdateObjects=this.sortObjects=this.autoClearStencil= -this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=this.physicallyBasedShading=this.gammaOutput=this.gammaInput=!1;this.shadowMapAutoUpdate=!0;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.renderPluginsPre=[];this.renderPluginsPost=[];this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0, -faces:0,points:0}};var K=this,ca=[],Fa=0,Ba=null,da=null,Aa=-1,$=null,ea=null,V=0,P=0,Z=-1,U=-1,ka=-1,ta=-1,ia=-1,La=-1,Ga=-1,fa=-1,Da=null,Ua=null,Qa=null,xa=null,bb=0,cb=0,Ma=G.width,fb=G.height,sb=0,pb=0,Ha={},la=new THREE.Frustum,ra=new THREE.Matrix4,gb=new THREE.Matrix4,sa=new THREE.Vector3,ga=new THREE.Vector3,ua=!0,Pa={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[], -anglesCos:[],exponents:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},j,Oa,va,wa,Ea;try{var Ra={alpha:J,premultipliedAlpha:ba,antialias:oa,stencil:pa,preserveDrawingBuffer:N};j=G.getContext("webgl",Ra)||G.getContext("experimental-webgl",Ra);if(null===j)throw"Error creating WebGL context.";}catch(Zb){console.error(Zb)}Oa=j.getExtension("OES_texture_float");j.getExtension("OES_texture_float_linear");va=j.getExtension("OES_standard_derivatives");wa=j.getExtension("EXT_texture_filter_anisotropic")|| -j.getExtension("MOZ_EXT_texture_filter_anisotropic")||j.getExtension("WEBKIT_EXT_texture_filter_anisotropic");Ea=j.getExtension("WEBGL_compressed_texture_s3tc")||j.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||j.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");Oa||console.log("THREE.WebGLRenderer: Float textures not supported.");va||console.log("THREE.WebGLRenderer: Standard derivatives not supported.");wa||console.log("THREE.WebGLRenderer: Anisotropic texture filtering not supported."); -Ea||console.log("THREE.WebGLRenderer: S3TC compressed textures not supported.");void 0===j.getShaderPrecisionFormat&&(j.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});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.viewport(bb,cb,Ma,fb);j.clearColor(M.r,M.g,M.b, -Q);this.context=j;var Mb=j.getParameter(j.MAX_TEXTURE_IMAGE_UNITS),$b=j.getParameter(j.MAX_VERTEX_TEXTURE_IMAGE_UNITS);j.getParameter(j.MAX_TEXTURE_SIZE);var ac=j.getParameter(j.MAX_CUBE_MAP_TEXTURE_SIZE),Nb=wa?j.getParameter(wa.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0,Bb=0<$b,yb=Bb&&Oa;Ea&&j.getParameter(j.COMPRESSED_TEXTURE_FORMATS);var bc=j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.HIGH_FLOAT),cc=j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.MEDIUM_FLOAT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.LOW_FLOAT); -var qc=j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.HIGH_FLOAT),rc=j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.MEDIUM_FLOAT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.LOW_FLOAT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.HIGH_INT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.MEDIUM_INT);j.getShaderPrecisionFormat(j.VERTEX_SHADER,j.LOW_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.HIGH_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER,j.MEDIUM_INT);j.getShaderPrecisionFormat(j.FRAGMENT_SHADER, -j.LOW_INT);var sc=0<bc.precision&&0<qc.precision,Ob=0<cc.precision&&0<rc.precision;"highp"===R&&!sc&&(Ob?(R="mediump",console.warn("WebGLRenderer: highp not supported, using mediump")):(R="lowp",console.warn("WebGLRenderer: highp and mediump not supported, using lowp")));"mediump"===R&&!Ob&&(R="lowp",console.warn("WebGLRenderer: mediump not supported, using lowp"));this.getContext=function(){return j};this.supportsVertexTextures=function(){return Bb};this.supportsFloatTextures=function(){return Oa}; -this.supportsStandardDerivatives=function(){return va};this.supportsCompressedTextureS3TC=function(){return Ea};this.getMaxAnisotropy=function(){return Nb};this.getPrecision=function(){return R};this.setSize=function(a,b,c){G.width=a*this.devicePixelRatio;G.height=b*this.devicePixelRatio;1!==this.devicePixelRatio&&!1!==c&&(G.style.width=a+"px",G.style.height=b+"px");this.setViewport(0,0,G.width,G.height)};this.setViewport=function(a,b,c,d){bb=void 0!==a?a:0;cb=void 0!==b?b:0;Ma=void 0!==c?c:G.width; -fb=void 0!==d?d:G.height;j.viewport(bb,cb,Ma,fb)};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.setClearColor=function(a,b){M.set(a);Q=void 0!==b?b:1;j.clearColor(M.r,M.g,M.b,Q)};this.setClearColorHex=function(a,b){console.warn("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.");this.setClearColor(a,b)};this.getClearColor=function(){return M};this.getClearAlpha=function(){return Q}; -this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=j.COLOR_BUFFER_BIT;if(void 0===b||b)d|=j.DEPTH_BUFFER_BIT;if(void 0===c||c)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.updateShadowMap=function(a,b){Ba=null;Aa=$=fa=Ga=ka=-1;ua=!0;U=Z=-1;this.shadowMapPlugin.update(a,b)}; -var Cb=function(a){a=a.target;a.removeEventListener("dispose",Cb);a.__webglInit=void 0;if(a instanceof THREE.BufferGeometry){var b=a.attributes,c;for(c in b)void 0!==b[c].buffer&&j.deleteBuffer(b[c].buffer);K.info.memory.geometries--}else if(void 0!==a.geometryGroups)for(b in a.geometryGroups){c=a.geometryGroups[b];if(void 0!==c.numMorphTargets)for(var d=0,e=c.numMorphTargets;d<e;d++)j.deleteBuffer(c.__webglMorphTargetsBuffers[d]);if(void 0!==c.numMorphNormals){d=0;for(e=c.numMorphNormals;d<e;d++)j.deleteBuffer(c.__webglMorphNormalsBuffers[d])}Hb(c)}else Hb(a)}, -Db=function(a){a=a.target;a.removeEventListener("dispose",Db);a.image&&a.image.__webglTextureCube?j.deleteTexture(a.image.__webglTextureCube):a.__webglInit&&(a.__webglInit=!1,j.deleteTexture(a.__webglTexture));K.info.memory.textures--},Eb=function(a){a=a.target;a.removeEventListener("dispose",Eb);if(a&&a.__webglTexture)if(j.deleteTexture(a.__webglTexture),a instanceof THREE.WebGLRenderTargetCube)for(var b=0;6>b;b++)j.deleteFramebuffer(a.__webglFramebuffer[b]),j.deleteRenderbuffer(a.__webglRenderbuffer[b]); -else j.deleteFramebuffer(a.__webglFramebuffer),j.deleteRenderbuffer(a.__webglRenderbuffer);K.info.memory.textures--},Fb=function(a){a=a.target;a.removeEventListener("dispose",Fb);Gb(a)},Hb=function(a){void 0!==a.__webglVertexBuffer&&j.deleteBuffer(a.__webglVertexBuffer);void 0!==a.__webglNormalBuffer&&j.deleteBuffer(a.__webglNormalBuffer);void 0!==a.__webglTangentBuffer&&j.deleteBuffer(a.__webglTangentBuffer);void 0!==a.__webglColorBuffer&&j.deleteBuffer(a.__webglColorBuffer);void 0!==a.__webglUVBuffer&& -j.deleteBuffer(a.__webglUVBuffer);void 0!==a.__webglUV2Buffer&&j.deleteBuffer(a.__webglUV2Buffer);void 0!==a.__webglSkinIndicesBuffer&&j.deleteBuffer(a.__webglSkinIndicesBuffer);void 0!==a.__webglSkinWeightsBuffer&&j.deleteBuffer(a.__webglSkinWeightsBuffer);void 0!==a.__webglFaceBuffer&&j.deleteBuffer(a.__webglFaceBuffer);void 0!==a.__webglLineBuffer&&j.deleteBuffer(a.__webglLineBuffer);void 0!==a.__webglLineDistanceBuffer&&j.deleteBuffer(a.__webglLineDistanceBuffer);if(void 0!==a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)j.deleteBuffer(a.__webglCustomAttributesList[b].buffer); -K.info.memory.geometries--},Gb=function(a){var b=a.program;if(void 0!==b){a.program=void 0;var c,d,e=!1,a=0;for(c=ca.length;a<c;a++)if(d=ca[a],d.program===b){d.usedTimes--;0===d.usedTimes&&(e=!0);break}if(!0===e){e=[];a=0;for(c=ca.length;a<c;a++)d=ca[a],d.program!==b&&e.push(d);ca=e;j.deleteProgram(b);K.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=j.createBuffer());a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer= -j.createBuffer());a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=j.createBuffer());a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=j.createBuffer());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,!1,0,0));if(a.hasNormals){j.bindBuffer(j.ARRAY_BUFFER,a.__webglNormalBuffer);if(c.shading===THREE.FlatShading){var d, -e,f,h,g,i,k,l,m,p,n,q=3*a.count;for(n=0;n<q;n+=9)p=a.normalArray,d=p[n],e=p[n+1],f=p[n+2],h=p[n+3],i=p[n+4],l=p[n+5],g=p[n+6],k=p[n+7],m=p[n+8],d=(d+h+g)/3,e=(e+i+k)/3,f=(f+l+m)/3,p[n]=d,p[n+1]=e,p[n+2]=f,p[n+3]=d,p[n+4]=e,p[n+5]=f,p[n+6]=d,p[n+7]=e,p[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,!1,0,0)}a.hasUvs&&c.map&&(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,!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(j.bindBuffer(j.ARRAY_BUFFER,a.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,a.colorArray,j.DYNAMIC_DRAW),j.enableVertexAttribArray(b.attributes.color),j.vertexAttribPointer(b.attributes.color,3,j.FLOAT,!1,0,0));j.drawArrays(j.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,e,f){if(!1!==d.visible){var i, -k,l,m;i=z(a,b,c,d,f);b=i.attributes;a=e.attributes;c=!1;i=16777215*e.id+2*i.id+(d.wireframe?1:0);i!==$&&($=i,c=!0);c&&g();if(f instanceof THREE.Mesh)if(f=a.index){e=e.offsets;1<e.length&&(c=!0);for(var p=0,n=e.length;p<n;p++){var q=e[p].index;if(c){for(k in b)l=b[k],i=a[k],0<=l&&(i?(m=i.itemSize,j.bindBuffer(j.ARRAY_BUFFER,i.buffer),h(l),j.vertexAttribPointer(l,m,j.FLOAT,!1,0,4*q*m)):d.defaultAttributeValues&&(2===d.defaultAttributeValues[k].length?j.vertexAttrib2fv(l,d.defaultAttributeValues[k]): -3===d.defaultAttributeValues[k].length&&j.vertexAttrib3fv(l,d.defaultAttributeValues[k])));j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,f.buffer)}j.drawElements(j.TRIANGLES,e[p].count,j.UNSIGNED_SHORT,2*e[p].start);K.info.render.calls++;K.info.render.vertices+=e[p].count;K.info.render.faces+=e[p].count/3}}else{if(c)for(k in b)"index"!==k&&(l=b[k],i=a[k],0<=l&&(i?(m=i.itemSize,j.bindBuffer(j.ARRAY_BUFFER,i.buffer),h(l),j.vertexAttribPointer(l,m,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[k]&& -(2===d.defaultAttributeValues[k].length?j.vertexAttrib2fv(l,d.defaultAttributeValues[k]):3===d.defaultAttributeValues[k].length&&j.vertexAttrib3fv(l,d.defaultAttributeValues[k]))));d=e.attributes.position;j.drawArrays(j.TRIANGLES,0,d.numItems/3);K.info.render.calls++;K.info.render.vertices+=d.numItems/3;K.info.render.faces+=d.numItems/3/3}else if(f instanceof THREE.ParticleSystem){if(c){for(k in b)l=b[k],i=a[k],0<=l&&(i?(m=i.itemSize,j.bindBuffer(j.ARRAY_BUFFER,i.buffer),h(l),j.vertexAttribPointer(l, -m,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[k]&&(2===d.defaultAttributeValues[k].length?j.vertexAttrib2fv(l,d.defaultAttributeValues[k]):3===d.defaultAttributeValues[k].length&&j.vertexAttrib3fv(l,d.defaultAttributeValues[k])));d=a.position;j.drawArrays(j.POINTS,0,d.numItems/3);K.info.render.calls++;K.info.render.points+=d.numItems/3}}else if(f instanceof THREE.Line&&c){for(k in b)l=b[k],i=a[k],0<=l&&(i?(m=i.itemSize,j.bindBuffer(j.ARRAY_BUFFER,i.buffer),h(l),j.vertexAttribPointer(l, -m,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[k]&&(2===d.defaultAttributeValues[k].length?j.vertexAttrib2fv(l,d.defaultAttributeValues[k]):3===d.defaultAttributeValues[k].length&&j.vertexAttrib3fv(l,d.defaultAttributeValues[k])));k=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES;F(d.linewidth);d=a.position;j.drawArrays(k,0,d.numItems/3);K.info.render.calls++;K.info.render.points+=d.numItems}}};this.renderBuffer=function(a,b,c,d,e,f){if(!1!==d.visible){var i,l,c=z(a,b,c,d,f), -a=c.attributes,b=!1,c=16777215*e.id+2*c.id+(d.wireframe?1:0);c!==$&&($=c,b=!0);b&&g();if(!d.morphTargets&&0<=a.position)b&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer),h(a.position),j.vertexAttribPointer(a.position,3,j.FLOAT,!1,0,0));else if(f.morphTargetBase){c=d.program.attributes;-1!==f.morphTargetBase&&0<=c.position?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]),h(c.position),j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0)):0<=c.position&&(j.bindBuffer(j.ARRAY_BUFFER, -e.__webglVertexBuffer),h(c.position),j.vertexAttribPointer(c.position,3,j.FLOAT,!1,0,0));if(f.morphTargetForcedOrder.length){var m=0;l=f.morphTargetForcedOrder;for(i=f.morphTargetInfluences;m<d.numSupportedMorphTargets&&m<l.length;)0<=c["morphTarget"+m]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[l[m]]),h(c["morphTarget"+m]),j.vertexAttribPointer(c["morphTarget"+m],3,j.FLOAT,!1,0,0)),0<=c["morphNormal"+m]&&d.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[l[m]]), -h(c["morphNormal"+m]),j.vertexAttribPointer(c["morphNormal"+m],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[m]=i[l[m]],m++}else{l=[];i=f.morphTargetInfluences;var p,n=i.length;for(p=0;p<n;p++)m=i[p],0<m&&l.push([m,p]);l.length>d.numSupportedMorphTargets?(l.sort(k),l.length=d.numSupportedMorphTargets):l.length>d.numSupportedMorphNormals?l.sort(k):0===l.length&&l.push([0,0]);for(m=0;m<d.numSupportedMorphTargets;)l[m]?(p=l[m][1],0<=c["morphTarget"+m]&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[p]), -h(c["morphTarget"+m]),j.vertexAttribPointer(c["morphTarget"+m],3,j.FLOAT,!1,0,0)),0<=c["morphNormal"+m]&&d.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[p]),h(c["morphNormal"+m]),j.vertexAttribPointer(c["morphNormal"+m],3,j.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[m]=i[p]):f.__webglMorphTargetInfluences[m]=0,m++}null!==d.program.uniforms.morphTargetInfluences&&j.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(b){if(e.__webglCustomAttributesList){i= -0;for(l=e.__webglCustomAttributesList.length;i<l;i++)c=e.__webglCustomAttributesList[i],0<=a[c.buffer.belongsToAttribute]&&(j.bindBuffer(j.ARRAY_BUFFER,c.buffer),h(a[c.buffer.belongsToAttribute]),j.vertexAttribPointer(a[c.buffer.belongsToAttribute],c.size,j.FLOAT,!1,0,0))}0<=a.color&&(0<f.geometry.colors.length||0<f.geometry.faces.length?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglColorBuffer),h(a.color),j.vertexAttribPointer(a.color,3,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&j.vertexAttrib3fv(a.color, -d.defaultAttributeValues.color));0<=a.normal&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglNormalBuffer),h(a.normal),j.vertexAttribPointer(a.normal,3,j.FLOAT,!1,0,0));0<=a.tangent&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglTangentBuffer),h(a.tangent),j.vertexAttribPointer(a.tangent,4,j.FLOAT,!1,0,0));0<=a.uv&&(f.geometry.faceVertexUvs[0]?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUVBuffer),h(a.uv),j.vertexAttribPointer(a.uv,2,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&j.vertexAttrib2fv(a.uv,d.defaultAttributeValues.uv)); -0<=a.uv2&&(f.geometry.faceVertexUvs[1]?(j.bindBuffer(j.ARRAY_BUFFER,e.__webglUV2Buffer),h(a.uv2),j.vertexAttribPointer(a.uv2,2,j.FLOAT,!1,0,0)):d.defaultAttributeValues&&j.vertexAttrib2fv(a.uv2,d.defaultAttributeValues.uv2));d.skinning&&(0<=a.skinIndex&&0<=a.skinWeight)&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinIndicesBuffer),h(a.skinIndex),j.vertexAttribPointer(a.skinIndex,4,j.FLOAT,!1,0,0),j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinWeightsBuffer),h(a.skinWeight),j.vertexAttribPointer(a.skinWeight, -4,j.FLOAT,!1,0,0));0<=a.lineDistance&&(j.bindBuffer(j.ARRAY_BUFFER,e.__webglLineDistanceBuffer),h(a.lineDistance),j.vertexAttribPointer(a.lineDistance,1,j.FLOAT,!1,0,0))}f instanceof THREE.Mesh?(d.wireframe?(F(d.wireframeLinewidth),b&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer),j.drawElements(j.LINES,e.__webglLineCount,j.UNSIGNED_SHORT,0)):(b&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer),j.drawElements(j.TRIANGLES,e.__webglFaceCount,j.UNSIGNED_SHORT,0)),K.info.render.calls++, -K.info.render.vertices+=e.__webglFaceCount,K.info.render.faces+=e.__webglFaceCount/3):f instanceof THREE.Line?(f=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES,F(d.linewidth),j.drawArrays(f,0,e.__webglLineCount),K.info.render.calls++):f instanceof THREE.ParticleSystem&&(j.drawArrays(j.POINTS,0,e.__webglParticleCount),K.info.render.calls++,K.info.render.points+=e.__webglParticleCount)}};this.render=function(a,b,c,d){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera."); -else{var e,f,h,g,k=a.__lights,n=a.fog;Aa=-1;ua=!0;!0===a.autoUpdate&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b.matrixWorld);ra.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);la.setFromMatrix(ra);this.autoUpdateObjects&&this.initWebGLObjects(a);m(this.renderPluginsPre,a,b);K.info.render.calls=0;K.info.render.vertices=0;K.info.render.faces=0;K.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor, -this.autoClearDepth,this.autoClearStencil);g=a.__webglObjects;d=0;for(e=g.length;d<e;d++)if(f=g[d],h=f.object,f.id=d,f.render=!1,h.visible&&(!(h instanceof THREE.Mesh||h instanceof THREE.ParticleSystem)||!h.frustumCulled||la.intersectsObject(h))){var q=h;q._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,q.matrixWorld);q._normalMatrix.getNormalMatrix(q._modelViewMatrix);var q=f,r=q.buffer,s=void 0,t=s=void 0,t=q.object.material;if(t instanceof THREE.MeshFaceMaterial)s=r.materialIndex,s=t.materials[s], -s.transparent?(q.transparent=s,q.opaque=null):(q.opaque=s,q.transparent=null);else if(s=t)s.transparent?(q.transparent=s,q.opaque=null):(q.opaque=s,q.transparent=null);f.render=!0;!0===this.sortObjects&&(null!==h.renderDepth?f.z=h.renderDepth:(sa.getPositionFromMatrix(h.matrixWorld),sa.applyProjection(ra),f.z=sa.z))}this.sortObjects&&g.sort(i);g=a.__webglObjectsImmediate;d=0;for(e=g.length;d<e;d++)f=g[d],h=f.object,h.visible&&(h._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,h.matrixWorld), -h._normalMatrix.getNormalMatrix(h._modelViewMatrix),h=f.object.material,h.transparent?(f.transparent=h,f.opaque=null):(f.opaque=h,f.transparent=null));a.overrideMaterial?(d=a.overrideMaterial,this.setBlending(d.blending,d.blendEquation,d.blendSrc,d.blendDst),this.setDepthTest(d.depthTest),this.setDepthWrite(d.depthWrite),A(d.polygonOffset,d.polygonOffsetFactor,d.polygonOffsetUnits),l(a.__webglObjects,!1,"",b,k,n,!0,d),p(a.__webglObjectsImmediate,"",b,k,n,!1,d)):(d=null,this.setBlending(THREE.NoBlending), -l(a.__webglObjects,!0,"opaque",b,k,n,!1,d),p(a.__webglObjectsImmediate,"opaque",b,k,n,!1,d),l(a.__webglObjects,!1,"transparent",b,k,n,!0,d),p(a.__webglObjectsImmediate,"transparent",b,k,n,!0,d));m(this.renderPluginsPost,a,b);c&&(c.generateMipmaps&&c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter)&&(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)):(j.bindTexture(j.TEXTURE_2D, -c.__webglTexture),j.generateMipmap(j.TEXTURE_2D),j.bindTexture(j.TEXTURE_2D,null)));this.setDepthTest(!0);this.setDepthWrite(!0)}};this.renderImmediateObject=function(a,b,c,d,e){var f=z(a,b,c,d,e);$=-1;K.setMaterialFaces(d);e.immediateRenderCallback?e.immediateRenderCallback(f,j,la):e.render(function(a){K.renderBufferImmediate(a,f,d)})};this.initWebGLObjects=function(a){a.__webglObjects||(a.__webglObjects=[],a.__webglObjectsImmediate=[],a.__webglSprites=[],a.__webglFlares=[]);for(;a.__objectsAdded.length;)s(a.__objectsAdded[0], -a),a.__objectsAdded.splice(0,1);for(;a.__objectsRemoved.length;)q(a.__objectsRemoved[0],a),a.__objectsRemoved.splice(0,1);for(var b=0,h=a.__webglObjects.length;b<h;b++){var g=a.__webglObjects[b].object;void 0===g.__webglInit&&(void 0!==g.__webglActive&&q(g,a),s(g,a));var i=g,l=i.geometry,m=void 0,p=void 0,t=void 0;if(l instanceof THREE.BufferGeometry){var u=j.DYNAMIC_DRAW,w=!l.dynamic,z=l.attributes,y=void 0,x=void 0;for(y in z)x=z[y],x.needsUpdate&&("index"===y?(j.bindBuffer(j.ELEMENT_ARRAY_BUFFER, -x.buffer),j.bufferData(j.ELEMENT_ARRAY_BUFFER,x.array,u)):(j.bindBuffer(j.ARRAY_BUFFER,x.buffer),j.bufferData(j.ARRAY_BUFFER,x.array,u)),x.needsUpdate=!1),w&&!x.dynamic&&(x.array=null)}else if(i instanceof THREE.Mesh){for(var A=0,B=l.geometryGroupsList.length;A<B;A++)if(m=l.geometryGroupsList[A],t=d(i,m),l.buffersNeedUpdate&&c(m,i),p=t.attributes&&n(t),l.verticesNeedUpdate||l.morphTargetsNeedUpdate||l.elementsNeedUpdate||l.uvsNeedUpdate||l.normalsNeedUpdate||l.colorsNeedUpdate||l.tangentsNeedUpdate|| -p){var v=m,C=i,D=j.DYNAMIC_DRAW,F=!l.dynamic,G=t;if(v.__inittedArrays){var J=e(G),K=G.vertexColors?G.vertexColors:!1,N=f(G),O=J===THREE.SmoothShading,E=void 0,I=void 0,V=void 0,M=void 0,R=void 0,U=void 0,Q=void 0,da=void 0,Z=void 0,$=void 0,Fa=void 0,P=void 0,X=void 0,W=void 0,Ba=void 0,ea=void 0,Aa=void 0,ba=void 0,ca=void 0,ia=void 0,fa=void 0,ga=void 0,ka=void 0,la=void 0,oa=void 0,pa=void 0,ta=void 0,ua=void 0,va=void 0,Ca=void 0,Da=void 0,Ga=void 0,Ea=void 0,La=void 0,Sa=void 0,Ha=void 0,wa= -void 0,xa=void 0,Qa=void 0,Ra=void 0,db=0,eb=0,Oa=0,Pa=0,Ua=0,hb=0,Ta=0,tb=0,Za=0,qa=0,ya=0,L=0,Na=void 0,ib=v.__vertexArray,bb=v.__uvArray,cb=v.__uv2Array,Ma=v.__normalArray,Va=v.__tangentArray,jb=v.__colorArray,Wa=v.__skinIndexArray,Xa=v.__skinWeightArray,fb=v.__morphTargetsArrays,sb=v.__morphNormalsArrays,pb=v.__webglCustomAttributesList,H=void 0,Pb=v.__faceArray,vb=v.__lineArray,Ia=C.geometry,Bb=Ia.elementsNeedUpdate,yb=Ia.uvsNeedUpdate,Db=Ia.normalsNeedUpdate,Mb=Ia.tangentsNeedUpdate,Nb=Ia.colorsNeedUpdate, -Ob=Ia.morphTargetsNeedUpdate,ec=Ia.vertices,aa=v.faces3,kb=Ia.faces,Cb=Ia.faceVertexUvs[0],Eb=Ia.faceVertexUvs[1],fc=Ia.skinIndices,Qb=Ia.skinWeights,Rb=Ia.morphTargets,Fb=Ia.morphNormals;if(Ia.verticesNeedUpdate){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],P=ec[M.a],X=ec[M.b],W=ec[M.c],ib[eb]=P.x,ib[eb+1]=P.y,ib[eb+2]=P.z,ib[eb+3]=X.x,ib[eb+4]=X.y,ib[eb+5]=X.z,ib[eb+6]=W.x,ib[eb+7]=W.y,ib[eb+8]=W.z,eb+=9;j.bindBuffer(j.ARRAY_BUFFER,v.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,ib,D)}if(Ob){Sa=0; -for(Ha=Rb.length;Sa<Ha;Sa++){E=ya=0;for(I=aa.length;E<I;E++)Qa=aa[E],M=kb[Qa],P=Rb[Sa].vertices[M.a],X=Rb[Sa].vertices[M.b],W=Rb[Sa].vertices[M.c],wa=fb[Sa],wa[ya]=P.x,wa[ya+1]=P.y,wa[ya+2]=P.z,wa[ya+3]=X.x,wa[ya+4]=X.y,wa[ya+5]=X.z,wa[ya+6]=W.x,wa[ya+7]=W.y,wa[ya+8]=W.z,G.morphNormals&&(O?(Ra=Fb[Sa].vertexNormals[Qa],ba=Ra.a,ca=Ra.b,ia=Ra.c):ia=ca=ba=Fb[Sa].faceNormals[Qa],xa=sb[Sa],xa[ya]=ba.x,xa[ya+1]=ba.y,xa[ya+2]=ba.z,xa[ya+3]=ca.x,xa[ya+4]=ca.y,xa[ya+5]=ca.z,xa[ya+6]=ia.x,xa[ya+7]=ia.y,xa[ya+ -8]=ia.z),ya+=9;j.bindBuffer(j.ARRAY_BUFFER,v.__webglMorphTargetsBuffers[Sa]);j.bufferData(j.ARRAY_BUFFER,fb[Sa],D);G.morphNormals&&(j.bindBuffer(j.ARRAY_BUFFER,v.__webglMorphNormalsBuffers[Sa]),j.bufferData(j.ARRAY_BUFFER,sb[Sa],D))}}if(Qb.length){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],la=Qb[M.a],oa=Qb[M.b],pa=Qb[M.c],Xa[qa]=la.x,Xa[qa+1]=la.y,Xa[qa+2]=la.z,Xa[qa+3]=la.w,Xa[qa+4]=oa.x,Xa[qa+5]=oa.y,Xa[qa+6]=oa.z,Xa[qa+7]=oa.w,Xa[qa+8]=pa.x,Xa[qa+9]=pa.y,Xa[qa+10]=pa.z,Xa[qa+11]=pa.w,ta=fc[M.a],ua= -fc[M.b],va=fc[M.c],Wa[qa]=ta.x,Wa[qa+1]=ta.y,Wa[qa+2]=ta.z,Wa[qa+3]=ta.w,Wa[qa+4]=ua.x,Wa[qa+5]=ua.y,Wa[qa+6]=ua.z,Wa[qa+7]=ua.w,Wa[qa+8]=va.x,Wa[qa+9]=va.y,Wa[qa+10]=va.z,Wa[qa+11]=va.w,qa+=12;0<qa&&(j.bindBuffer(j.ARRAY_BUFFER,v.__webglSkinIndicesBuffer),j.bufferData(j.ARRAY_BUFFER,Wa,D),j.bindBuffer(j.ARRAY_BUFFER,v.__webglSkinWeightsBuffer),j.bufferData(j.ARRAY_BUFFER,Xa,D))}if(Nb&&K){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],Q=M.vertexColors,da=M.color,3===Q.length&&K===THREE.VertexColors?(fa= -Q[0],ga=Q[1],ka=Q[2]):ka=ga=fa=da,jb[Za]=fa.r,jb[Za+1]=fa.g,jb[Za+2]=fa.b,jb[Za+3]=ga.r,jb[Za+4]=ga.g,jb[Za+5]=ga.b,jb[Za+6]=ka.r,jb[Za+7]=ka.g,jb[Za+8]=ka.b,Za+=9;0<Za&&(j.bindBuffer(j.ARRAY_BUFFER,v.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,jb,D))}if(Mb&&Ia.hasTangents){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],Z=M.vertexTangents,Ba=Z[0],ea=Z[1],Aa=Z[2],Va[Ta]=Ba.x,Va[Ta+1]=Ba.y,Va[Ta+2]=Ba.z,Va[Ta+3]=Ba.w,Va[Ta+4]=ea.x,Va[Ta+5]=ea.y,Va[Ta+6]=ea.z,Va[Ta+7]=ea.w,Va[Ta+8]=Aa.x,Va[Ta+9]=Aa.y,Va[Ta+ -10]=Aa.z,Va[Ta+11]=Aa.w,Ta+=12;j.bindBuffer(j.ARRAY_BUFFER,v.__webglTangentBuffer);j.bufferData(j.ARRAY_BUFFER,Va,D)}if(Db&&J){E=0;for(I=aa.length;E<I;E++)if(M=kb[aa[E]],R=M.vertexNormals,U=M.normal,3===R.length&&O)for(Ca=0;3>Ca;Ca++)Ga=R[Ca],Ma[hb]=Ga.x,Ma[hb+1]=Ga.y,Ma[hb+2]=Ga.z,hb+=3;else for(Ca=0;3>Ca;Ca++)Ma[hb]=U.x,Ma[hb+1]=U.y,Ma[hb+2]=U.z,hb+=3;j.bindBuffer(j.ARRAY_BUFFER,v.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Ma,D)}if(yb&&Cb&&N){E=0;for(I=aa.length;E<I;E++)if(V=aa[E],$=Cb[V], -void 0!==$)for(Ca=0;3>Ca;Ca++)Ea=$[Ca],bb[Oa]=Ea.x,bb[Oa+1]=Ea.y,Oa+=2;0<Oa&&(j.bindBuffer(j.ARRAY_BUFFER,v.__webglUVBuffer),j.bufferData(j.ARRAY_BUFFER,bb,D))}if(yb&&Eb&&N){E=0;for(I=aa.length;E<I;E++)if(V=aa[E],Fa=Eb[V],void 0!==Fa)for(Ca=0;3>Ca;Ca++)La=Fa[Ca],cb[Pa]=La.x,cb[Pa+1]=La.y,Pa+=2;0<Pa&&(j.bindBuffer(j.ARRAY_BUFFER,v.__webglUV2Buffer),j.bufferData(j.ARRAY_BUFFER,cb,D))}if(Bb){E=0;for(I=aa.length;E<I;E++)Pb[Ua]=db,Pb[Ua+1]=db+1,Pb[Ua+2]=db+2,Ua+=3,vb[tb]=db,vb[tb+1]=db+1,vb[tb+2]=db,vb[tb+ -3]=db+2,vb[tb+4]=db+1,vb[tb+5]=db+2,tb+=6,db+=3;j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,v.__webglFaceBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,Pb,D);j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,v.__webglLineBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,vb,D)}if(pb){Ca=0;for(Da=pb.length;Ca<Da;Ca++)if(H=pb[Ca],H.__original.needsUpdate){L=0;if(1===H.size)if(void 0===H.boundTo||"vertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],H.array[L]=H.value[M.a],H.array[L+1]=H.value[M.b],H.array[L+2]=H.value[M.c], -L+=3}else{if("faces"===H.boundTo){E=0;for(I=aa.length;E<I;E++)Na=H.value[aa[E]],H.array[L]=Na,H.array[L+1]=Na,H.array[L+2]=Na,L+=3}}else if(2===H.size)if(void 0===H.boundTo||"vertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],P=H.value[M.a],X=H.value[M.b],W=H.value[M.c],H.array[L]=P.x,H.array[L+1]=P.y,H.array[L+2]=X.x,H.array[L+3]=X.y,H.array[L+4]=W.x,H.array[L+5]=W.y,L+=6}else{if("faces"===H.boundTo){E=0;for(I=aa.length;E<I;E++)W=X=P=Na=H.value[aa[E]],H.array[L]=P.x,H.array[L+1]=P.y, -H.array[L+2]=X.x,H.array[L+3]=X.y,H.array[L+4]=W.x,H.array[L+5]=W.y,L+=6}}else if(3===H.size){var na;na="c"===H.type?["r","g","b"]:["x","y","z"];if(void 0===H.boundTo||"vertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],P=H.value[M.a],X=H.value[M.b],W=H.value[M.c],H.array[L]=P[na[0]],H.array[L+1]=P[na[1]],H.array[L+2]=P[na[2]],H.array[L+3]=X[na[0]],H.array[L+4]=X[na[1]],H.array[L+5]=X[na[2]],H.array[L+6]=W[na[0]],H.array[L+7]=W[na[1]],H.array[L+8]=W[na[2]],L+=9}else if("faces"===H.boundTo){E= -0;for(I=aa.length;E<I;E++)W=X=P=Na=H.value[aa[E]],H.array[L]=P[na[0]],H.array[L+1]=P[na[1]],H.array[L+2]=P[na[2]],H.array[L+3]=X[na[0]],H.array[L+4]=X[na[1]],H.array[L+5]=X[na[2]],H.array[L+6]=W[na[0]],H.array[L+7]=W[na[1]],H.array[L+8]=W[na[2]],L+=9}else if("faceVertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)Na=H.value[aa[E]],P=Na[0],X=Na[1],W=Na[2],H.array[L]=P[na[0]],H.array[L+1]=P[na[1]],H.array[L+2]=P[na[2]],H.array[L+3]=X[na[0]],H.array[L+4]=X[na[1]],H.array[L+5]=X[na[2]],H.array[L+6]=W[na[0]], -H.array[L+7]=W[na[1]],H.array[L+8]=W[na[2]],L+=9}}else if(4===H.size)if(void 0===H.boundTo||"vertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)M=kb[aa[E]],P=H.value[M.a],X=H.value[M.b],W=H.value[M.c],H.array[L]=P.x,H.array[L+1]=P.y,H.array[L+2]=P.z,H.array[L+3]=P.w,H.array[L+4]=X.x,H.array[L+5]=X.y,H.array[L+6]=X.z,H.array[L+7]=X.w,H.array[L+8]=W.x,H.array[L+9]=W.y,H.array[L+10]=W.z,H.array[L+11]=W.w,L+=12}else if("faces"===H.boundTo){E=0;for(I=aa.length;E<I;E++)W=X=P=Na=H.value[aa[E]],H.array[L]= -P.x,H.array[L+1]=P.y,H.array[L+2]=P.z,H.array[L+3]=P.w,H.array[L+4]=X.x,H.array[L+5]=X.y,H.array[L+6]=X.z,H.array[L+7]=X.w,H.array[L+8]=W.x,H.array[L+9]=W.y,H.array[L+10]=W.z,H.array[L+11]=W.w,L+=12}else if("faceVertices"===H.boundTo){E=0;for(I=aa.length;E<I;E++)Na=H.value[aa[E]],P=Na[0],X=Na[1],W=Na[2],H.array[L]=P.x,H.array[L+1]=P.y,H.array[L+2]=P.z,H.array[L+3]=P.w,H.array[L+4]=X.x,H.array[L+5]=X.y,H.array[L+6]=X.z,H.array[L+7]=X.w,H.array[L+8]=W.x,H.array[L+9]=W.y,H.array[L+10]=W.z,H.array[L+ -11]=W.w,L+=12}j.bindBuffer(j.ARRAY_BUFFER,H.buffer);j.bufferData(j.ARRAY_BUFFER,H.array,D)}}F&&(delete v.__inittedArrays,delete v.__colorArray,delete v.__normalArray,delete v.__tangentArray,delete v.__uvArray,delete v.__uv2Array,delete v.__faceArray,delete v.__vertexArray,delete v.__lineArray,delete v.__skinIndexArray,delete v.__skinWeightArray)}}l.verticesNeedUpdate=!1;l.morphTargetsNeedUpdate=!1;l.elementsNeedUpdate=!1;l.uvsNeedUpdate=!1;l.normalsNeedUpdate=!1;l.colorsNeedUpdate=!1;l.tangentsNeedUpdate= -!1;l.buffersNeedUpdate=!1;t.attributes&&r(t)}else if(i instanceof THREE.Line){t=d(i,l);p=t.attributes&&n(t);if(l.verticesNeedUpdate||l.colorsNeedUpdate||l.lineDistancesNeedUpdate||p){var Ya=l,Sb=j.DYNAMIC_DRAW,Ib=void 0,Jb=void 0,Kb=void 0,Tb=void 0,ma=void 0,Ub=void 0,Gb=Ya.vertices,Hb=Ya.colors,kc=Ya.lineDistances,Zb=Gb.length,$b=Hb.length,ac=kc.length,Vb=Ya.__vertexArray,Wb=Ya.__colorArray,lc=Ya.__lineDistanceArray,bc=Ya.colorsNeedUpdate,cc=Ya.lineDistancesNeedUpdate,gc=Ya.__webglCustomAttributesList, -Xb=void 0,mc=void 0,za=void 0,zb=void 0,Ja=void 0,ja=void 0;if(Ya.verticesNeedUpdate){for(Ib=0;Ib<Zb;Ib++)Tb=Gb[Ib],ma=3*Ib,Vb[ma]=Tb.x,Vb[ma+1]=Tb.y,Vb[ma+2]=Tb.z;j.bindBuffer(j.ARRAY_BUFFER,Ya.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Vb,Sb)}if(bc){for(Jb=0;Jb<$b;Jb++)Ub=Hb[Jb],ma=3*Jb,Wb[ma]=Ub.r,Wb[ma+1]=Ub.g,Wb[ma+2]=Ub.b;j.bindBuffer(j.ARRAY_BUFFER,Ya.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Wb,Sb)}if(cc){for(Kb=0;Kb<ac;Kb++)lc[Kb]=kc[Kb];j.bindBuffer(j.ARRAY_BUFFER,Ya.__webglLineDistanceBuffer); -j.bufferData(j.ARRAY_BUFFER,lc,Sb)}if(gc){Xb=0;for(mc=gc.length;Xb<mc;Xb++)if(ja=gc[Xb],ja.needsUpdate&&(void 0===ja.boundTo||"vertices"===ja.boundTo)){ma=0;zb=ja.value.length;if(1===ja.size)for(za=0;za<zb;za++)ja.array[za]=ja.value[za];else if(2===ja.size)for(za=0;za<zb;za++)Ja=ja.value[za],ja.array[ma]=Ja.x,ja.array[ma+1]=Ja.y,ma+=2;else if(3===ja.size)if("c"===ja.type)for(za=0;za<zb;za++)Ja=ja.value[za],ja.array[ma]=Ja.r,ja.array[ma+1]=Ja.g,ja.array[ma+2]=Ja.b,ma+=3;else for(za=0;za<zb;za++)Ja= -ja.value[za],ja.array[ma]=Ja.x,ja.array[ma+1]=Ja.y,ja.array[ma+2]=Ja.z,ma+=3;else if(4===ja.size)for(za=0;za<zb;za++)Ja=ja.value[za],ja.array[ma]=Ja.x,ja.array[ma+1]=Ja.y,ja.array[ma+2]=Ja.z,ja.array[ma+3]=Ja.w,ma+=4;j.bindBuffer(j.ARRAY_BUFFER,ja.buffer);j.bufferData(j.ARRAY_BUFFER,ja.array,Sb)}}}l.verticesNeedUpdate=!1;l.colorsNeedUpdate=!1;l.lineDistancesNeedUpdate=!1;t.attributes&&r(t)}else if(i instanceof THREE.ParticleSystem){t=d(i,l);p=t.attributes&&n(t);if(l.verticesNeedUpdate||l.colorsNeedUpdate|| -i.sortParticles||p){var lb=l,hc=j.DYNAMIC_DRAW,Lb=i,Ka=void 0,mb=void 0,nb=void 0,T=void 0,ob=void 0,ub=void 0,Yb=lb.vertices,ic=Yb.length,jc=lb.colors,nc=jc.length,wb=lb.__vertexArray,xb=lb.__colorArray,qb=lb.__sortArray,oc=lb.verticesNeedUpdate,pc=lb.colorsNeedUpdate,rb=lb.__webglCustomAttributesList,$a=void 0,Ab=void 0,Y=void 0,ab=void 0,ha=void 0,S=void 0;if(Lb.sortParticles){gb.copy(ra);gb.multiply(Lb.matrixWorld);for(Ka=0;Ka<ic;Ka++)nb=Yb[Ka],sa.copy(nb),sa.applyProjection(gb),qb[Ka]=[sa.z, -Ka];qb.sort(k);for(Ka=0;Ka<ic;Ka++)nb=Yb[qb[Ka][1]],T=3*Ka,wb[T]=nb.x,wb[T+1]=nb.y,wb[T+2]=nb.z;for(mb=0;mb<nc;mb++)T=3*mb,ub=jc[qb[mb][1]],xb[T]=ub.r,xb[T+1]=ub.g,xb[T+2]=ub.b;if(rb){$a=0;for(Ab=rb.length;$a<Ab;$a++)if(S=rb[$a],void 0===S.boundTo||"vertices"===S.boundTo)if(T=0,ab=S.value.length,1===S.size)for(Y=0;Y<ab;Y++)ob=qb[Y][1],S.array[Y]=S.value[ob];else if(2===S.size)for(Y=0;Y<ab;Y++)ob=qb[Y][1],ha=S.value[ob],S.array[T]=ha.x,S.array[T+1]=ha.y,T+=2;else if(3===S.size)if("c"===S.type)for(Y= -0;Y<ab;Y++)ob=qb[Y][1],ha=S.value[ob],S.array[T]=ha.r,S.array[T+1]=ha.g,S.array[T+2]=ha.b,T+=3;else for(Y=0;Y<ab;Y++)ob=qb[Y][1],ha=S.value[ob],S.array[T]=ha.x,S.array[T+1]=ha.y,S.array[T+2]=ha.z,T+=3;else if(4===S.size)for(Y=0;Y<ab;Y++)ob=qb[Y][1],ha=S.value[ob],S.array[T]=ha.x,S.array[T+1]=ha.y,S.array[T+2]=ha.z,S.array[T+3]=ha.w,T+=4}}else{if(oc)for(Ka=0;Ka<ic;Ka++)nb=Yb[Ka],T=3*Ka,wb[T]=nb.x,wb[T+1]=nb.y,wb[T+2]=nb.z;if(pc)for(mb=0;mb<nc;mb++)ub=jc[mb],T=3*mb,xb[T]=ub.r,xb[T+1]=ub.g,xb[T+2]=ub.b; -if(rb){$a=0;for(Ab=rb.length;$a<Ab;$a++)if(S=rb[$a],S.needsUpdate&&(void 0===S.boundTo||"vertices"===S.boundTo))if(ab=S.value.length,T=0,1===S.size)for(Y=0;Y<ab;Y++)S.array[Y]=S.value[Y];else if(2===S.size)for(Y=0;Y<ab;Y++)ha=S.value[Y],S.array[T]=ha.x,S.array[T+1]=ha.y,T+=2;else if(3===S.size)if("c"===S.type)for(Y=0;Y<ab;Y++)ha=S.value[Y],S.array[T]=ha.r,S.array[T+1]=ha.g,S.array[T+2]=ha.b,T+=3;else for(Y=0;Y<ab;Y++)ha=S.value[Y],S.array[T]=ha.x,S.array[T+1]=ha.y,S.array[T+2]=ha.z,T+=3;else if(4=== -S.size)for(Y=0;Y<ab;Y++)ha=S.value[Y],S.array[T]=ha.x,S.array[T+1]=ha.y,S.array[T+2]=ha.z,S.array[T+3]=ha.w,T+=4}}if(oc||Lb.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,lb.__webglVertexBuffer),j.bufferData(j.ARRAY_BUFFER,wb,hc);if(pc||Lb.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,lb.__webglColorBuffer),j.bufferData(j.ARRAY_BUFFER,xb,hc);if(rb){$a=0;for(Ab=rb.length;$a<Ab;$a++)if(S=rb[$a],S.needsUpdate||Lb.sortParticles)j.bindBuffer(j.ARRAY_BUFFER,S.buffer),j.bufferData(j.ARRAY_BUFFER,S.array,hc)}}l.verticesNeedUpdate= -!1;l.colorsNeedUpdate=!1;t.attributes&&r(t)}}};this.initMaterial=function(a,b,c,d){var e,f,h,g;a.addEventListener("dispose",Fb);var i,k,l,m,p;a instanceof THREE.MeshDepthMaterial?p="depth":a instanceof THREE.MeshNormalMaterial?p="normal":a instanceof THREE.MeshBasicMaterial?p="basic":a instanceof THREE.MeshLambertMaterial?p="lambert":a instanceof THREE.MeshPhongMaterial?p="phong":a instanceof THREE.LineBasicMaterial?p="basic":a instanceof THREE.LineDashedMaterial?p="dashed":a instanceof THREE.ParticleSystemMaterial&& -(p="particle_basic");if(p){var n=THREE.ShaderLib[p];a.uniforms=THREE.UniformsUtils.clone(n.uniforms);a.vertexShader=n.vertexShader;a.fragmentShader=n.fragmentShader}var q=e=0,r=0,t=n=0;for(f=b.length;t<f;t++)h=b[t],h.onlyShadow||(h instanceof THREE.DirectionalLight&&e++,h instanceof THREE.PointLight&&q++,h instanceof THREE.SpotLight&&r++,h instanceof THREE.HemisphereLight&&n++);f=q;h=r;g=n;r=n=0;for(q=b.length;r<q;r++)t=b[r],t.castShadow&&(t instanceof THREE.SpotLight&&n++,t instanceof THREE.DirectionalLight&& -!t.shadowCascade&&n++);m=n;yb&&d&&d.useVertexTexture?l=1024:(b=j.getParameter(j.MAX_VERTEX_UNIFORM_VECTORS),b=Math.floor((b-20)/4),void 0!==d&&d instanceof THREE.SkinnedMesh&&(b=Math.min(d.bones.length,b),b<d.bones.length&&console.warn("WebGLRenderer: too many bones - "+d.bones.length+", this GPU supports just "+b+" (try OpenGL instead of ANGLE)")),l=b);a:{var r=a.fragmentShader,q=a.vertexShader,n=a.uniforms,b=a.attributes,t=a.defines,c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,bumpMap:!!a.bumpMap, -normalMap:!!a.normalMap,specularMap:!!a.specularMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,fogExp:c instanceof THREE.FogExp2,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:l,useVertexTexture:yb&&d&&d.useVertexTexture,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:e,maxPointLights:f,maxSpotLights:h,maxHemiLights:g,maxShadows:m,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow, -shadowMapType:this.shadowMapType,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:a.side===THREE.DoubleSide,flipSided:a.side===THREE.BackSide},d=a.index0AttributeName,s,u,w;e=[];p?e.push(p):(e.push(r),e.push(q));for(u in t)e.push(u),e.push(t[u]);for(s in c)e.push(s),e.push(c[s]);p=e.join();s=0;for(u=ca.length;s<u;s++)if(e=ca[s],e.code===p){e.usedTimes++;k=e.program;break a}s="SHADOWMAP_TYPE_BASIC"; -c.shadowMapType===THREE.PCFShadowMap?s="SHADOWMAP_TYPE_PCF":c.shadowMapType===THREE.PCFSoftShadowMap&&(s="SHADOWMAP_TYPE_PCF_SOFT");u=[];for(w in t)e=t[w],!1!==e&&(e="#define "+w+" "+e,u.push(e));e=u.join("\n");w=j.createProgram();u=["precision "+R+" float;","precision "+R+" int;",e,Bb?"#define VERTEX_TEXTURES":"",K.gammaInput?"#define GAMMA_INPUT":"",K.gammaOutput?"#define GAMMA_OUTPUT":"",K.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_HEMI_LIGHTS "+c.maxHemiLights,"#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.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.useVertexTexture?"#define BONE_TEXTURE": -"",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.flipSided?"#define FLIP_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapEnabled?"#define "+s:"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 modelMatrix;\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 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n"); -s=["precision "+R+" float;","precision "+R+" int;",c.bumpMap||c.normalMap?"#extension GL_OES_standard_derivatives : enable":"",e,"#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_HEMI_LIGHTS "+c.maxHemiLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",K.gammaInput?"#define GAMMA_INPUT":"",K.gammaOutput?"#define GAMMA_OUTPUT":"",K.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING": -"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fogExp?"#define FOG_EXP2":"",c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.bumpMap?"#define USE_BUMPMAP":"",c.normalMap?"#define USE_NORMALMAP":"",c.specularMap?"#define USE_SPECULARMAP":"",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.flipSided?"#define FLIP_SIDED": -"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapEnabled?"#define "+s:"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");u=C("vertex",u+q);s=C("fragment",s+r);j.attachShader(w,u);j.attachShader(w,s);d&&j.bindAttribLocation(w,0,d);j.linkProgram(w);j.getProgramParameter(w,j.LINK_STATUS)||(console.error("Could not initialise shader\nVALIDATE_STATUS: "+j.getProgramParameter(w, -j.VALIDATE_STATUS)+", gl error ["+j.getError()+"]"),console.error("Program Info Log: "+j.getProgramInfoLog(w)));j.deleteShader(s);j.deleteShader(u);w.uniforms={};w.attributes={};var v;s="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences".split(" ");c.useVertexTexture?(s.push("boneTexture"),s.push("boneTextureWidth"),s.push("boneTextureHeight")):s.push("boneGlobalMatrices");for(v in n)s.push(v);v=s;s=0;for(u=v.length;s<u;s++)n=v[s],w.uniforms[n]= -j.getUniformLocation(w,n);s="position normal uv uv2 tangent color skinIndex skinWeight lineDistance".split(" ");for(v=0;v<c.maxMorphTargets;v++)s.push("morphTarget"+v);for(v=0;v<c.maxMorphNormals;v++)s.push("morphNormal"+v);for(k in b)s.push(k);k=s;v=0;for(b=k.length;v<b;v++)s=k[v],w.attributes[s]=j.getAttribLocation(w,s);w.id=Fa++;ca.push({program:w,code:p,usedTimes:1});K.info.memory.programs=ca.length;k=w}a.program=k;v=a.program.attributes;if(a.morphTargets){a.numSupportedMorphTargets=0;b="morphTarget"; -for(k=0;k<this.maxMorphTargets;k++)w=b+k,0<=v[w]&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNormals=0;b="morphNormal";for(k=0;k<this.maxMorphNormals;k++)w=b+k,0<=v[w]&&a.numSupportedMorphNormals++}a.uniformsList=[];for(i in a.uniforms)a.uniformsList.push([a.uniforms[i],i])};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?j.disable(j.CULL_FACE):(b===THREE.FrontFaceDirectionCW?j.frontFace(j.CW):j.frontFace(j.CCW),a===THREE.CullFaceBack?j.cullFace(j.BACK):a===THREE.CullFaceFront? -j.cullFace(j.FRONT):j.cullFace(j.FRONT_AND_BACK),j.enable(j.CULL_FACE))};this.setMaterialFaces=function(a){var b=a.side===THREE.DoubleSide,a=a.side===THREE.BackSide;Z!==b&&(b?j.disable(j.CULL_FACE):j.enable(j.CULL_FACE),Z=b);U!==a&&(a?j.frontFace(j.CW):j.frontFace(j.CCW),U=a)};this.setDepthTest=function(a){Ga!==a&&(a?j.enable(j.DEPTH_TEST):j.disable(j.DEPTH_TEST),Ga=a)};this.setDepthWrite=function(a){fa!==a&&(j.depthMask(a),fa=a)};this.setBlending=function(a,b,c,d){a!==ka&&(a===THREE.NoBlending?j.disable(j.BLEND): -a===THREE.AdditiveBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.SRC_ALPHA,j.ONE)):a===THREE.SubtractiveBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.ONE_MINUS_SRC_COLOR)):a===THREE.MultiplyBlending?(j.enable(j.BLEND),j.blendEquation(j.FUNC_ADD),j.blendFunc(j.ZERO,j.SRC_COLOR)):a===THREE.CustomBlending?j.enable(j.BLEND):(j.enable(j.BLEND),j.blendEquationSeparate(j.FUNC_ADD,j.FUNC_ADD),j.blendFuncSeparate(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA,j.ONE, -j.ONE_MINUS_SRC_ALPHA)),ka=a);if(a===THREE.CustomBlending){if(b!==ta&&(j.blendEquation(v(b)),ta=b),c!==ia||d!==La)j.blendFunc(v(c),v(d)),ia=c,La=d}else La=ia=ta=null};this.setTexture=function(a,b){if(a.needsUpdate){a.__webglInit||(a.__webglInit=!0,a.addEventListener("dispose",Db),a.__webglTexture=j.createTexture(),K.info.memory.textures++);j.activeTexture(j.TEXTURE0+b);j.bindTexture(j.TEXTURE_2D,a.__webglTexture);j.pixelStorei(j.UNPACK_FLIP_Y_WEBGL,a.flipY);j.pixelStorei(j.UNPACK_PREMULTIPLY_ALPHA_WEBGL, -a.premultiplyAlpha);j.pixelStorei(j.UNPACK_ALIGNMENT,a.unpackAlignment);var c=a.image,d=0===(c.width&c.width-1)&&0===(c.height&c.height-1),e=v(a.format),f=v(a.type);E(j.TEXTURE_2D,a,d);var h=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<h.length&&d){for(var g=0,i=h.length;g<i;g++)c=h[g],j.texImage2D(j.TEXTURE_2D,g,e,c.width,c.height,0,e,f,c.data);a.generateMipmaps=!1}else j.texImage2D(j.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data);else if(a instanceof THREE.CompressedTexture){g=0;for(i=h.length;g< -i;g++)c=h[g],a.format!==THREE.RGBAFormat?j.compressedTexImage2D(j.TEXTURE_2D,g,e,c.width,c.height,0,c.data):j.texImage2D(j.TEXTURE_2D,g,e,c.width,c.height,0,e,f,c.data)}else if(0<h.length&&d){g=0;for(i=h.length;g<i;g++)c=h[g],j.texImage2D(j.TEXTURE_2D,g,e,e,f,c);a.generateMipmaps=!1}else j.texImage2D(j.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&j.generateMipmap(j.TEXTURE_2D);a.needsUpdate=!1;if(a.onUpdate)a.onUpdate()}else j.activeTexture(j.TEXTURE0+b),j.bindTexture(j.TEXTURE_2D,a.__webglTexture)}; -this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",Eb);a.__webglTexture=j.createTexture();K.info.memory.textures++;var c=0===(a.width&a.width-1)&&0===(a.height&a.height-1),d=v(a.format),e=v(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];j.bindTexture(j.TEXTURE_CUBE_MAP,a.__webglTexture);E(j.TEXTURE_CUBE_MAP, -a,c);for(var f=0;6>f;f++){a.__webglFramebuffer[f]=j.createFramebuffer();a.__webglRenderbuffer[f]=j.createRenderbuffer();j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var h=a,g=j.TEXTURE_CUBE_MAP_POSITIVE_X+f;j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer[f]);j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,g,h.__webglTexture,0);I(a.__webglRenderbuffer[f],a)}c&&j.generateMipmap(j.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=j.createFramebuffer(),a.__webglRenderbuffer= -a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:j.createRenderbuffer(),j.bindTexture(j.TEXTURE_2D,a.__webglTexture),E(j.TEXTURE_2D,a,c),j.texImage2D(j.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=j.TEXTURE_2D,j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer),j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&& -a.stencilBuffer&&j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):I(a.__webglRenderbuffer,a),c&&j.generateMipmap(j.TEXTURE_2D);b?j.bindTexture(j.TEXTURE_CUBE_MAP,null):j.bindTexture(j.TEXTURE_2D,null);j.bindRenderbuffer(j.RENDERBUFFER,null);j.bindFramebuffer(j.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=Ma,a=fb,d=bb,e=cb);b!==da&&(j.bindFramebuffer(j.FRAMEBUFFER,b), -j.viewport(d,e,c,a),da=b);sb=c;pb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: -THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; -THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps;a.shareDepthFrom=this.shareDepthFrom; -return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};THREE.RenderableFace3=function(){this.id=0;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.material=this.color=null;this.uvs=[[]];this.z= -0};THREE.RenderableObject=function(){this.id=0;this.object=null;this.z=0};THREE.RenderableSprite=function(){this.id=0;this.object=null;this.rotation=this.z=this.y=this.x=0;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.id=0;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.vertexColors=[new THREE.Color,new THREE.Color];this.material=null;this.z=0};THREE.GeometryUtils={merge:function(a,b,c){var d,e,f=a.vertices.length,h=b instanceof THREE.Mesh?b.geometry:b,g=a.vertices,i=h.vertices,k=a.faces,m=h.faces,a=a.faceVertexUvs[0],h=h.faceVertexUvs[0];void 0===c&&(c=0);b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,e=(new THREE.Matrix3).getNormalMatrix(d));for(var b=0,l=i.length;b<l;b++){var p=i[b].clone();d&&p.applyMatrix4(d);g.push(p)}b=0;for(l=m.length;b<l;b++){var p=m[b],s,t,n=p.vertexNormals,r=p.vertexColors;s=new THREE.Face3(p.a+ -f,p.b+f,p.c+f);s.normal.copy(p.normal);e&&s.normal.applyMatrix3(e).normalize();g=0;for(i=n.length;g<i;g++)t=n[g].clone(),e&&t.applyMatrix3(e).normalize(),s.vertexNormals.push(t);s.color.copy(p.color);g=0;for(i=r.length;g<i;g++)t=r[g],s.vertexColors.push(t.clone());s.materialIndex=p.materialIndex+c;s.centroid.copy(p.centroid);d&&s.centroid.applyMatrix4(d);k.push(s)}b=0;for(l=h.length;b<l;b++){c=h[b];d=[];g=0;for(i=c.length;g<i;g++)d.push(new THREE.Vector2(c[g].x,c[g].y));a.push(d)}},randomPointInTriangle:function(){var a= -new THREE.Vector3;return function(b,c,d){var e=new THREE.Vector3,f=THREE.Math.random16(),h=THREE.Math.random16();1<f+h&&(f=1-f,h=1-h);var g=1-f-h;e.copy(b);e.multiplyScalar(f);a.copy(c);a.multiplyScalar(h);e.add(a);a.copy(d);a.multiplyScalar(g);e.add(a);return e}}(),randomPointInFace:function(a,b){return THREE.GeometryUtils.randomPointInTriangle(b.vertices[a.a],b.vertices[a.b],b.vertices[a.c])},randomPointsInGeometry:function(a,b){function c(a){function b(c,d){if(d<c)return c;var e=c+Math.floor((d- -c)/2);return k[e]>a?b(c,e-1):k[e]<a?b(e+1,d):e}return b(0,k.length-1)}var d,e,f=a.faces,h=a.vertices,g=f.length,i=0,k=[],m,l,p;for(e=0;e<g;e++)d=f[e],m=h[d.a],l=h[d.b],p=h[d.c],d._area=THREE.GeometryUtils.triangleArea(m,l,p),i+=d._area,k[e]=i;d=[];for(e=0;e<b;e++)h=THREE.Math.random16()*i,h=c(h),d[e]=THREE.GeometryUtils.randomPointInFace(f[h],a,!0);return d},triangleArea:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){a.subVectors(d,c);b.subVectors(e,c);a.cross(b);return 0.5* -a.length()}}(),center:function(a){a.computeBoundingBox();var b=a.boundingBox,c=new THREE.Vector3;c.addVectors(b.min,b.max);c.multiplyScalar(-0.5);a.applyMatrix((new THREE.Matrix4).makeTranslation(c.x,c.y,c.z));a.computeBoundingBox();return c},triangulateQuads:function(a){var b,c,d,e,f=[],h=[];b=0;for(c=a.faceVertexUvs.length;b<c;b++)h[b]=[];b=0;for(c=a.faces.length;b<c;b++){f.push(a.faces[b]);d=0;for(e=a.faceVertexUvs.length;d<e;d++)h[d].push(a.faceVertexUvs[d][b])}a.faces=f;a.faceVertexUvs=h;a.computeCentroids(); -a.computeFaceNormals();a.computeVertexNormals();a.hasTangents&&a.computeTangents()}};THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(a,b,c){var d=new THREE.ImageLoader;d.crossOrigin=this.crossOrigin;var e=new THREE.Texture(void 0,b),b=d.load(a,function(){e.needsUpdate=!0;c&&c(e)});e.image=b;e.sourceFile=a;return e},loadCompressedTexture:function(a,b,c,d){var e=new THREE.CompressedTexture;e.mapping=b;var f=new XMLHttpRequest;f.onload=function(){var a=THREE.ImageUtils.parseDDS(f.response,!0);e.format=a.format;e.mipmaps=a.mipmaps;e.image.width=a.width;e.image.height=a.height; -e.generateMipmaps=!1;e.needsUpdate=!0;c&&c(e)};f.onerror=d;f.open("GET",a,!0);f.responseType="arraybuffer";f.send(null);return e},loadTextureCube:function(a,b,c,d){var e=[];e.loadCount=0;var f=new THREE.Texture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;for(var b=0,h=a.length;b<h;++b){var g=new Image;e[b]=g;g.onload=function(){e.loadCount+=1;6===e.loadCount&&(f.needsUpdate=!0,c&&c(f))};g.onerror=d;g.crossOrigin=this.crossOrigin;g.src=a[b]}return f},loadCompressedTextureCube:function(a,b,c,d){var e= -[];e.loadCount=0;var f=new THREE.CompressedTexture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;f.generateMipmaps=!1;b=function(a,b){return function(){var d=THREE.ImageUtils.parseDDS(a.response,!0);b.format=d.format;b.mipmaps=d.mipmaps;b.width=d.width;b.height=d.height;e.loadCount+=1;6===e.loadCount&&(f.format=d.format,f.needsUpdate=!0,c&&c(f))}};if(a instanceof Array)for(var h=0,g=a.length;h<g;++h){var i={};e[h]=i;var k=new XMLHttpRequest;k.onload=b(k,i);k.onerror=d;i=a[h];k.open("GET",i,!0);k.responseType= -"arraybuffer";k.send(null)}else k=new XMLHttpRequest,k.onload=function(){var a=THREE.ImageUtils.parseDDS(k.response,!0);if(a.isCubemap){for(var b=a.mipmaps.length/a.mipmapCount,d=0;d<b;d++){e[d]={mipmaps:[]};for(var h=0;h<a.mipmapCount;h++)e[d].mipmaps.push(a.mipmaps[d*a.mipmapCount+h]),e[d].format=a.format,e[d].width=a.width,e[d].height=a.height}f.format=a.format;f.needsUpdate=!0;c&&c(f)}},k.onerror=d,k.open("GET",a,!0),k.responseType="arraybuffer",k.send(null);return f},loadDDSTexture:function(a, -b,c,d){var e=[];e.loadCount=0;var f=new THREE.CompressedTexture;f.image=e;void 0!==b&&(f.mapping=b);f.flipY=!1;f.generateMipmaps=!1;var h=new XMLHttpRequest;h.onload=function(){var a=THREE.ImageUtils.parseDDS(h.response,!0);if(a.isCubemap)for(var b=a.mipmaps.length/a.mipmapCount,d=0;d<b;d++){e[d]={mipmaps:[]};for(var m=0;m<a.mipmapCount;m++)e[d].mipmaps.push(a.mipmaps[d*a.mipmapCount+m]),e[d].format=a.format,e[d].width=a.width,e[d].height=a.height}else f.image.width=a.width,f.image.height=a.height, -f.mipmaps=a.mipmaps;f.format=a.format;f.needsUpdate=!0;c&&c(f)};h.onerror=d;h.open("GET",a,!0);h.responseType="arraybuffer";h.send(null);return f},parseDDS:function(a,b){function c(a){return a.charCodeAt(0)+(a.charCodeAt(1)<<8)+(a.charCodeAt(2)<<16)+(a.charCodeAt(3)<<24)}var d={mipmaps:[],width:0,height:0,format:null,mipmapCount:1},e=c("DXT1"),f=c("DXT3"),h=c("DXT5"),g=new Int32Array(a,0,31);if(542327876!==g[0])return console.error("ImageUtils.parseDDS(): Invalid magic number in DDS header"),d;if(!g[20]& -4)return console.error("ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code"),d;var i=g[21],k=!1;switch(i){case e:e=8;d.format=THREE.RGB_S3TC_DXT1_Format;break;case f:e=16;d.format=THREE.RGBA_S3TC_DXT3_Format;break;case h:e=16;d.format=THREE.RGBA_S3TC_DXT5_Format;break;default:if(32==g[22]&&g[23]&16711680&&g[24]&65280&&g[25]&255&&g[26]&4278190080)k=!0,e=64,d.format=THREE.RGBAFormat;else return console.error("ImageUtils.parseDDS(): Unsupported FourCC code: ",String.fromCharCode(i& -255,i>>8&255,i>>16&255,i>>24&255)),d}d.mipmapCount=1;g[2]&131072&&!1!==b&&(d.mipmapCount=Math.max(1,g[7]));d.isCubemap=g[28]&512?!0:!1;d.width=g[4];d.height=g[3];for(var g=g[1]+4,f=d.width,h=d.height,i=d.isCubemap?6:1,m=0;m<i;m++){for(var l=0;l<d.mipmapCount;l++){if(k){var p;p=f;for(var s=h,t=4*p*s,n=new Uint8Array(a,g,t),t=new Uint8Array(t),r=0,q=0,u=0;u<s;u++)for(var w=0;w<p;w++){var z=n[q];q++;var B=n[q];q++;var D=n[q];q++;var x=n[q];q++;t[r]=D;r++;t[r]=B;r++;t[r]=z;r++;t[r]=x;r++}p=t;s=p.length}else s= -Math.max(4,f)/4*Math.max(4,h)/4*e,p=new Uint8Array(a,g,s);d.mipmaps.push({data:p,width:f,height:h});g+=s;f=Math.max(0.5*f,1);h=Math.max(0.5*h,1)}f=d.width;h=d.height}return d},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 h=f.getContext("2d");h.drawImage(a,0,0);for(var g=h.getImageData(0,0,d,e).data,i=h.createImageData(d,e),k=i.data,m=0;m< -d;m++)for(var l=0;l<e;l++){var p=0>l-1?0:l-1,s=l+1>e-1?e-1:l+1,t=0>m-1?0:m-1,n=m+1>d-1?d-1:m+1,r=[],q=[0,0,g[4*(l*d+m)]/255*b];r.push([-1,0,g[4*(l*d+t)]/255*b]);r.push([-1,-1,g[4*(p*d+t)]/255*b]);r.push([0,-1,g[4*(p*d+m)]/255*b]);r.push([1,-1,g[4*(p*d+n)]/255*b]);r.push([1,0,g[4*(l*d+n)]/255*b]);r.push([1,1,g[4*(s*d+n)]/255*b]);r.push([0,1,g[4*(s*d+m)]/255*b]);r.push([-1,1,g[4*(s*d+t)]/255*b]);p=[];t=r.length;for(s=0;s<t;s++){var n=r[s],u=r[(s+1)%t],n=[n[0]-q[0],n[1]-q[1],n[2]-q[2]],u=[u[0]-q[0], -u[1]-q[1],u[2]-q[2]];p.push(c([n[1]*u[2]-n[2]*u[1],n[2]*u[0]-n[0]*u[2],n[0]*u[1]-n[1]*u[0]]))}r=[0,0,0];for(s=0;s<p.length;s++)r[0]+=p[s][0],r[1]+=p[s][1],r[2]+=p[s][2];r[0]/=p.length;r[1]/=p.length;r[2]/=p.length;q=4*(l*d+m);k[q]=255*((r[0]+1)/2)|0;k[q+1]=255*((r[1]+1)/2)|0;k[q+2]=255*r[2]|0;k[q+3]=255}h.putImageData(i,0,0);return f},generateDataTexture:function(a,b,c){for(var d=a*b,e=new Uint8Array(3*d),f=Math.floor(255*c.r),h=Math.floor(255*c.g),c=Math.floor(255*c.b),g=0;g<d;g++)e[3*g]=f,e[3*g+ -1]=h,e[3*g+2]=c;a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}};THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){return this.faces[this.face][this.weight][this.style]},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]=a},drawText:function(a){for(var b=this.getFace(),c=this.size/b.resolution,d= -0,e=String(a).split(""),f=e.length,h=[],a=0;a<f;a++){var g=new THREE.Path,g=this.extractGlyphPoints(e[a],b,c,d,g),d=d+g.offset;h.push(g.path)}return{paths:h,offset:d/2}},extractGlyphPoints:function(a,b,c,d,e){var f=[],h,g,i,k,m,l,p,s,t,n,r,q=b.glyphs[a]||b.glyphs["?"];if(q){if(q.o){b=q._cachedOutline||(q._cachedOutline=q.o.split(" "));k=b.length;for(a=0;a<k;)switch(i=b[a++],i){case "m":i=b[a++]*c+d;m=b[a++]*c;e.moveTo(i,m);break;case "l":i=b[a++]*c+d;m=b[a++]*c;e.lineTo(i,m);break;case "q":i=b[a++]* -c+d;m=b[a++]*c;s=b[a++]*c+d;t=b[a++]*c;e.quadraticCurveTo(s,t,i,m);if(h=f[f.length-1]){l=h.x;p=h.y;h=1;for(g=this.divisions;h<=g;h++){var u=h/g;THREE.Shape.Utils.b2(u,l,s,i);THREE.Shape.Utils.b2(u,p,t,m)}}break;case "b":if(i=b[a++]*c+d,m=b[a++]*c,s=b[a++]*c+d,t=b[a++]*-c,n=b[a++]*c+d,r=b[a++]*-c,e.bezierCurveTo(i,m,s,t,n,r),h=f[f.length-1]){l=h.x;p=h.y;h=1;for(g=this.divisions;h<=g;h++)u=h/g,THREE.Shape.Utils.b3(u,l,s,n,i),THREE.Shape.Utils.b3(u,p,t,r,m)}}}return{offset:q.ha*c,path:e}}}}; -THREE.FontUtils.generateShapes=function(a,b){var b=b||{},c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",e=void 0!==b.weight?b.weight:"normal",f=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(a).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d}; -(function(a){var b=function(a){for(var b=a.length,e=0,f=b-1,h=0;h<b;f=h++)e+=a[f].x*a[h].y-a[h].x*a[f].y;return 0.5*e};a.Triangulate=function(a,d){var e=a.length;if(3>e)return null;var f=[],h=[],g=[],i,k,m;if(0<b(a))for(k=0;k<e;k++)h[k]=k;else for(k=0;k<e;k++)h[k]=e-1-k;var l=2*e;for(k=e-1;2<e;){if(0>=l--){console.log("Warning, unable to triangulate polygon!");break}i=k;e<=i&&(i=0);k=i+1;e<=k&&(k=0);m=k+1;e<=m&&(m=0);var p;a:{var s=p=void 0,t=void 0,n=void 0,r=void 0,q=void 0,u=void 0,w=void 0,z= -void 0,s=a[h[i]].x,t=a[h[i]].y,n=a[h[k]].x,r=a[h[k]].y,q=a[h[m]].x,u=a[h[m]].y;if(1E-10>(n-s)*(u-t)-(r-t)*(q-s))p=!1;else{var B=void 0,D=void 0,x=void 0,F=void 0,A=void 0,O=void 0,C=void 0,E=void 0,I=void 0,y=void 0,I=E=C=z=w=void 0,B=q-n,D=u-r,x=s-q,F=t-u,A=n-s,O=r-t;for(p=0;p<e;p++)if(!(p===i||p===k||p===m))if(w=a[h[p]].x,z=a[h[p]].y,C=w-s,E=z-t,I=w-n,y=z-r,w-=q,z-=u,I=B*y-D*I,C=A*E-O*C,E=x*z-F*w,-1E-10<=I&&-1E-10<=E&&-1E-10<=C){p=!1;break a}p=!0}}if(p){f.push([a[h[i]],a[h[k]],a[h[m]]]);g.push([h[i], -h[k],h[m]]);i=k;for(m=k+1;m<e;i++,m++)h[i]=h[m];e--;l=2*e}}return d?g:f};a.Triangulate.area=b;return a})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};THREE.typeface_js=self._typeface_js;THREE.Curve=function(){};THREE.Curve.prototype.getPoint=function(){console.log("Warning, getPoint() not implemented!");return null};THREE.Curve.prototype.getPointAt=function(a){a=this.getUtoTmapping(a);return this.getPoint(a)};THREE.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPoint(b/a));return c};THREE.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPointAt(b/a));return c}; +THREE.MorphAnimMesh.prototype.interpolateTargets=function(a,b,c){for(var d=this.morphTargetInfluences,e=0,f=d.length;e<f;e++)d[e]=0;-1<a&&(d[a]=1-c);-1<b&&(d[b]=c)}; +THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.objects=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype); +THREE.LOD.prototype.constructor=THREE.LOD;THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);b=Math.abs(b);for(var c=0;c<this.objects.length&&!(b<this.objects[c].distance);c++);this.objects.splice(c,0,{distance:b,object:a});this.add(a)};THREE.LOD.prototype.getObjectForDistance=function(a){for(var b=1,c=this.objects.length;b<c&&!(a<this.objects[b].distance);b++);return this.objects[b-1].object}; +THREE.LOD.prototype.raycast=function(){var a=new THREE.Vector3;return function(b,c){a.setFromMatrixPosition(this.matrixWorld);var d=b.ray.origin.distanceTo(a);this.getObjectForDistance(d).raycast(b,c)}}(); +THREE.LOD.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){if(1<this.objects.length){a.setFromMatrixPosition(c.matrixWorld);b.setFromMatrixPosition(this.matrixWorld);c=a.distanceTo(b);this.objects[0].object.visible=!0;for(var d=1,e=this.objects.length;d<e;d++)if(c>=this.objects[d].distance)this.objects[d-1].object.visible=!1,this.objects[d].object.visible=!0;else break;for(;d<e;d++)this.objects[d].object.visible=!1}}}(); +THREE.LOD.prototype.clone=function(a){void 0===a&&(a=new THREE.LOD);THREE.Object3D.prototype.clone.call(this,a);for(var b=0,c=this.objects.length;b<c;b++){var d=this.objects[b].object.clone();d.visible=0===b;a.addLevel(d,this.objects[b].distance)}return a}; +THREE.Sprite=function(){var a=new Uint16Array([0,1,2,0,2,3]),b=new Float32Array([-.5,-.5,0,.5,-.5,0,.5,.5,0,-.5,.5,0]),c=new Float32Array([0,0,1,0,1,1,0,1]),d=new THREE.BufferGeometry;d.addAttribute("index",new THREE.BufferAttribute(a,1));d.addAttribute("position",new THREE.BufferAttribute(b,3));d.addAttribute("uv",new THREE.BufferAttribute(c,2));return function(a){THREE.Object3D.call(this);this.type="Sprite";this.geometry=d;this.material=void 0!==a?a:new THREE.SpriteMaterial}}(); +THREE.Sprite.prototype=Object.create(THREE.Object3D.prototype);THREE.Sprite.prototype.constructor=THREE.Sprite;THREE.Sprite.prototype.raycast=function(){var a=new THREE.Vector3;return function(b,c){a.setFromMatrixPosition(this.matrixWorld);var d=b.ray.distanceToPoint(a);d>this.scale.x||c.push({distance:d,point:this.position,face:null,object:this})}}();THREE.Sprite.prototype.clone=function(a){void 0===a&&(a=new THREE.Sprite(this.material));THREE.Object3D.prototype.clone.call(this,a);return a}; +THREE.Particle=THREE.Sprite;THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype);THREE.LensFlare.prototype.constructor=THREE.LensFlare; +THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; +THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a<b;a++)c=this.lensFlares[a],c.x=this.positionScreen.x+d*c.distance,c.y=this.positionScreen.y+e*c.distance,c.wantedRotation=c.x*Math.PI*.25,c.rotation+=.25*(c.wantedRotation-c.rotation)};THREE.Scene=function(){THREE.Object3D.call(this);this.type="Scene";this.overrideMaterial=this.fog=null;this.autoUpdate=!0};THREE.Scene.prototype=Object.create(THREE.Object3D.prototype); +THREE.Scene.prototype.constructor=THREE.Scene;THREE.Scene.prototype.clone=function(a){void 0===a&&(a=new THREE.Scene);THREE.Object3D.prototype.clone.call(this,a);null!==this.fog&&(a.fog=this.fog.clone());null!==this.overrideMaterial&&(a.overrideMaterial=this.overrideMaterial.clone());a.autoUpdate=this.autoUpdate;a.matrixAutoUpdate=this.matrixAutoUpdate;return a};THREE.Fog=function(a,b,c){this.name="";this.color=new THREE.Color(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3}; +THREE.Fog.prototype.clone=function(){return new THREE.Fog(this.color.getHex(),this.near,this.far)};THREE.FogExp2=function(a,b){this.name="";this.color=new THREE.Color(a);this.density=void 0!==b?b:2.5E-4};THREE.FogExp2.prototype.clone=function(){return new THREE.FogExp2(this.color.getHex(),this.density)};THREE.ShaderChunk={};THREE.ShaderChunk.common="#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n\treturn normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n\tfloat distance = dot( planeNormal, point-pointOnPlane );\n\treturn point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n\tif ( decayExponent > 0.0 ) {\n\t return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n\t}\n\treturn 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n\treturn pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n\treturn a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n\treturn pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n\treturn a;\n#endif\n}\n"; +THREE.ShaderChunk.alphatest_fragment="#ifdef ALPHATEST\n\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n";THREE.ShaderChunk.lights_lambert_vertex="vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\tfloat dotProduct = dot( transformedNormal, dirVector );\n\tvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t#endif\n\n\t#endif\n\n\t#ifdef WRAP_AROUND\n\n\t\tvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\tdirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tdirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n\t\t#endif\n\n\t#endif\n\n\tvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n\t#endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\n\t\tvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\t\tpointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tpointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t\tvLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n\t\t#endif\n\n\t}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n\t\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\t\tlVector = normalize( lVector );\n\n\t\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\t\t\tvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\t\tvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t\t\t#endif\n\n\t\t\t#endif\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\t\t\tspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n\t\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\t\tspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n\t\t\t\t#endif\n\n\t\t\t#endif\n\n\t\t\tvLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tvLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n\t\t\t#endif\n\n\t\t}\n\n\t}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\t\tfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n\t\tvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n\t\t#endif\n\n\t}\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack += ambientLightColor;\n\n#endif\n"; +THREE.ShaderChunk.map_particle_pars_fragment="#ifdef USE_MAP\n\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n\n#endif\n";THREE.ShaderChunk.default_vertex="#ifdef USE_SKINNING\n\n\tvec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n\tvec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; +THREE.ShaderChunk.map_pars_fragment="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvarying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n\tuniform sampler2D map;\n\n#endif";THREE.ShaderChunk.skinnormal_vertex="#ifdef USE_SKINNING\n\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\n\t#ifdef USE_MORPHNORMALS\n\n\tvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n\t#else\n\n\tvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.logdepthbuf_pars_vertex="#ifdef USE_LOGDEPTHBUF\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n\tuniform float logDepthBufFC;\n\n#endif";THREE.ShaderChunk.lightmap_pars_vertex="#ifdef USE_LIGHTMAP\n\n\tvarying vec2 vUv2;\n\n#endif";THREE.ShaderChunk.lights_phong_fragment="#ifndef FLAT_SHADED\n\n\tvec3 normal = normalize( vNormal );\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n\t#endif\n\n#else\n\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lVector );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\tfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\tvec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n\t\t#else\n\n\t\t\tfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t#endif\n\n\t\ttotalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n\t\t\t\t// specular\n\n\t\tvec3 pointHalfVector = normalize( lVector + viewPosition );\n\t\tfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n\t\tfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n\t}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n\t\t\t// diffuse\n\n\t\t\tfloat dotProduct = dot( normal, lVector );\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\t\tfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\t\tvec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n\t\t\t#else\n\n\t\t\t\tfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t\t#endif\n\n\t\t\ttotalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n\t\t\t// specular\n\n\t\t\tvec3 spotHalfVector = normalize( lVector + viewPosition );\n\t\t\tfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n\t\t\tfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n\t\t\ttotalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n\t\t}\n\n\t}\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n\t\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, dirVector );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\tfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\tvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n\t\t#else\n\n\t\t\tfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t#endif\n\n\t\ttotalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n\t\t// specular\n\n\t\tvec3 dirHalfVector = normalize( dirVector + viewPosition );\n\t\tfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n\t\tfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n\t\t/*\n\t\t// fresnel term from skin shader\n\t\tconst float F0 = 0.128;\n\n\t\tfloat base = 1.0 - dot( viewPosition, dirHalfVector );\n\t\tfloat exponential = pow( base, 5.0 );\n\n\t\tfloat fresnel = exponential + F0 * ( 1.0 - exponential );\n\t\t*/\n\n\t\t/*\n\t\t// fresnel term from fresnel shader\n\t\tconst float mFresnelBias = 0.08;\n\t\tconst float mFresnelScale = 0.3;\n\t\tconst float mFresnelPower = 5.0;\n\n\t\tfloat fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n\t\t*/\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\t// \t\tdirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n\t}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lVector );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n\t\tvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n\t\ttotalDiffuseLight += hemiColor;\n\n\t\t// specular (sky light)\n\n\t\tvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n\t\tfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n\t\tfloat hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n\t\t// specular (ground light)\n\n\t\tvec3 lVectorGround = -lVector;\n\n\t\tvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n\t\tfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n\t\tfloat hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n\t\tfloat dotProductGround = dot( normal, lVectorGround );\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\tvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n\t\tvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n\t}\n\n#endif\n\n#ifdef METAL\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; +THREE.ShaderChunk.fog_pars_fragment="#ifdef USE_FOG\n\n\tuniform vec3 fogColor;\n\n\t#ifdef FOG_EXP2\n\n\t\tuniform float fogDensity;\n\n\t#else\n\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n\n#endif";THREE.ShaderChunk.morphnormal_vertex="#ifdef USE_MORPHNORMALS\n\n\tvec3 morphedNormal = vec3( 0.0 );\n\n\tmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n\tmorphedNormal += normal;\n\n#endif"; +THREE.ShaderChunk.envmap_pars_fragment="#ifdef USE_ENVMAP\n\n\tuniform float reflectivity;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tuniform float refractionRatio;\n\n\t#else\n\n\t\tvarying vec3 vReflect;\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.logdepthbuf_fragment="#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; +THREE.ShaderChunk.normalmap_pars_fragment="#ifdef USE_NORMALMAP\n\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\n\t// Per-Pixel Tangent Space Normal Mapping\n\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\n\t}\n\n#endif\n"; +THREE.ShaderChunk.lights_phong_pars_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n";THREE.ShaderChunk.lightmap_pars_fragment="#ifdef USE_LIGHTMAP\n\n\tvarying vec2 vUv2;\n\tuniform sampler2D lightMap;\n\n#endif";THREE.ShaderChunk.shadowmap_vertex="#ifdef USE_SHADOWMAP\n\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n\t}\n\n#endif"; +THREE.ShaderChunk.lights_phong_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvWorldPosition = worldPosition.xyz;\n\n#endif";THREE.ShaderChunk.map_fragment="#ifdef USE_MAP\n\n\tvec4 texelColor = texture2D( map, vUv );\n\n\ttexelColor.xyz = inputToLinear( texelColor.xyz );\n\n\tdiffuseColor *= texelColor;\n\n#endif";THREE.ShaderChunk.lightmap_vertex="#ifdef USE_LIGHTMAP\n\n\tvUv2 = uv2;\n\n#endif";THREE.ShaderChunk.map_particle_fragment="#ifdef USE_MAP\n\n\tdiffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; +THREE.ShaderChunk.color_pars_fragment="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif\n";THREE.ShaderChunk.color_vertex="#ifdef USE_COLOR\n\n\tvColor.xyz = inputToLinear( color.xyz );\n\n#endif";THREE.ShaderChunk.skinning_vertex="#ifdef USE_SKINNING\n\n\t#ifdef USE_MORPHTARGETS\n\n\tvec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n\t#else\n\n\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n\t#endif\n\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n\n#endif\n"; +THREE.ShaderChunk.envmap_pars_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvarying vec3 vReflect;\n\n\tuniform float refractionRatio;\n\n#endif\n";THREE.ShaderChunk.linear_to_gamma_fragment="\n\toutgoingLight = linearToOutput( outgoingLight );\n";THREE.ShaderChunk.color_pars_vertex="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif";THREE.ShaderChunk.lights_lambert_pars_vertex="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n"; +THREE.ShaderChunk.map_pars_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n\n#endif\n";THREE.ShaderChunk.envmap_fragment="#ifdef USE_ENVMAP\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n\t\t// Transforming Normal Vectors with the Inverse Transformation\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n\t\t#else\n\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t\t#endif\n\n\t#else\n\n\t\tvec3 reflectVec = vReflect;\n\n\t#endif\n\n\t#ifdef DOUBLE_SIDED\n\t\tfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\t#else\n\t\tfloat flipNormal = 1.0;\n\t#endif\n\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#endif\n\n\tenvColor.xyz = inputToLinear( envColor.xyz );\n\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.specularmap_pars_fragment="#ifdef USE_SPECULARMAP\n\n\tuniform sampler2D specularMap;\n\n#endif";THREE.ShaderChunk.logdepthbuf_vertex="#ifdef USE_LOGDEPTHBUF\n\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.morphtarget_pars_vertex="#ifdef USE_MORPHTARGETS\n\n\t#ifndef USE_MORPHNORMALS\n\n\tuniform float morphTargetInfluences[ 8 ];\n\n\t#else\n\n\tuniform float morphTargetInfluences[ 4 ];\n\n\t#endif\n\n#endif"; +THREE.ShaderChunk.specularmap_fragment="float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n\n#else\n\n\tspecularStrength = 1.0;\n\n#endif";THREE.ShaderChunk.fog_fragment="#ifdef USE_FOG\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n\t#else\n\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\n\t#endif\n\n\t#ifdef FOG_EXP2\n\n\t\tfloat fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n\t\tfogFactor = whiteCompliment( fogFactor );\n\n\t#else\n\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n\n\t#endif\n\t\n\toutgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; +THREE.ShaderChunk.bumpmap_pars_fragment="#ifdef USE_BUMPMAP\n\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\n\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n\t// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n\tvec2 dHdxy_fwd() {\n\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n\t\treturn vec2( dBx, dBy );\n\n\t}\n\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\t\t// normalized\n\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\n\t}\n\n#endif\n"; +THREE.ShaderChunk.defaultnormal_vertex="#ifdef USE_SKINNING\n\n\tvec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n\tvec3 objectNormal = morphedNormal;\n\n#else\n\n\tvec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n\tobjectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n";THREE.ShaderChunk.lights_phong_pars_fragment="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n\tvarying vec3 vNormal;\n\n#endif\n"; +THREE.ShaderChunk.skinbase_vertex="#ifdef USE_SKINNING\n\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif";THREE.ShaderChunk.map_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; +THREE.ShaderChunk.lightmap_fragment="#ifdef USE_LIGHTMAP\n\n\toutgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif";THREE.ShaderChunk.shadowmap_pars_vertex="#ifdef USE_SHADOWMAP\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\tuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif";THREE.ShaderChunk.color_fragment="#ifdef USE_COLOR\n\n\tdiffuseColor.rgb *= vColor;\n\n#endif";THREE.ShaderChunk.morphtarget_vertex="#ifdef USE_MORPHTARGETS\n\n\tvec3 morphed = vec3( 0.0 );\n\tmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\tmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\tmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\tmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n\t#ifndef USE_MORPHNORMALS\n\n\tmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\tmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\tmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\tmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n\t#endif\n\n\tmorphed += position;\n\n#endif"; +THREE.ShaderChunk.envmap_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\n\t#else\n\n\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.shadowmap_fragment="#ifdef USE_SHADOWMAP\n\n\t#ifdef SHADOWMAP_DEBUG\n\n\t\tvec3 frustumColors[3];\n\t\tfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n\t\tfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n\t\tfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n\t#endif\n\n\t#ifdef SHADOWMAP_CASCADE\n\n\t\tint inFrustumCount = 0;\n\n\t#endif\n\n\tfloat fDepth;\n\tvec3 shadowColor = vec3( 1.0 );\n\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n\t\t\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\n\t\t\t\t// if ( all( something, something ) ) using this instead\n\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\n\t\t\t\t// don't shadow pixels outside of light frustum\n\t\t\t\t// use just first frustum (for cascades)\n\t\t\t\t// don't shadow pixels behind far plane of light frustum\n\n\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\tinFrustumCount += int( inFrustum );\n\t\t\tbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n\t\t#else\n\n\t\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n\t\t#endif\n\n\t\tbool frustumTest = all( frustumTestVec );\n\n\t\tif ( frustumTest ) {\n\n\t\t\tshadowCoord.z += shadowBias[ i ];\n\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t/*\n\t\t\t\t\t\t// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n\t\t\t\t\t\t// must enroll loop manually\n\n\t\t\t\tfor ( float y = -1.25; y <= 1.25; y += 1.25 )\n\t\t\t\t\tfor ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n\t\t\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n\t\t\t\t\t\t\t\t// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n\t\t\t\t\t\t\t\t//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n\t\t\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\t\t\tif ( fDepth < shadowCoord.z )\n\t\t\t\t\t\t\tshadow += 1.0;\n\n\t\t\t\t}\n\n\t\t\t\tshadow /= 9.0;\n\n\t\t*/\n\n\t\t\t\tconst float shadowDelta = 1.0 / 9.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.25 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.25 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.25 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.25 * yPixelOffset;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.0 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.0 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.0 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.0 * yPixelOffset;\n\n\t\t\t\tmat3 shadowKernel;\n\t\t\t\tmat3 depthKernel;\n\n\t\t\t\tdepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tdepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tdepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tdepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tdepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tdepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tdepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tdepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tdepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n\t\t\t\tvec3 shadowZ = vec3( shadowCoord.z );\n\t\t\t\tshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n\t\t\t\tshadowKernel[0] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n\t\t\t\tshadowKernel[1] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n\t\t\t\tshadowKernel[2] *= vec3(0.25);\n\n\t\t\t\tvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n\t\t\t\tshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n\t\t\t\tshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n\t\t\t\tvec4 shadowValues;\n\t\t\t\tshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n\t\t\t\tshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n\t\t\t\tshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n\t\t\t\tshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n\t\t\t\tshadow = dot( shadowValues, vec4( 1.0 ) );\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#else\n\n\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\tif ( fDepth < shadowCoord.z )\n\n\t\t// spot with multiple shadows is darker\n\n\t\t\t\t\tshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n\t\t// spot with multiple shadows has the same color as single shadow spot\n\n\t\t// \t\t\t\t\tshadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n\t\t\t#endif\n\n\t\t}\n\n\n\t\t#ifdef SHADOWMAP_DEBUG\n\n\t\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\t\tif ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n\t\t\t#else\n\n\t\t\t\tif ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t}\n\n\t// NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n\tshadowColor = inputToLinear( shadowColor );\n\n\toutgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; +THREE.ShaderChunk.worldpos_vertex="#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n\t#ifdef USE_SKINNING\n\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\n\t#elif defined( USE_MORPHTARGETS )\n\n\t\tvec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n\t#else\n\n\t\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.shadowmap_pars_fragment="#ifdef USE_SHADOWMAP\n\n\tuniform sampler2D shadowMap[ MAX_SHADOWS ];\n\tuniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n\tuniform float shadowDarkness[ MAX_SHADOWS ];\n\tuniform float shadowBias[ MAX_SHADOWS ];\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n\tfloat unpackDepth( const in vec4 rgba_depth ) {\n\n\t\tconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n\t\tfloat depth = dot( rgba_depth, bit_shift );\n\t\treturn depth;\n\n\t}\n\n#endif"; +THREE.ShaderChunk.skinning_pars_vertex="#ifdef USE_SKINNING\n\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\n\t#ifdef BONE_TEXTURE\n\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\n\t\tmat4 getBoneMatrix( const in float i ) {\n\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\n\t\t\ty = dy * ( y + 0.5 );\n\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\n\t\t\treturn bone;\n\n\t\t}\n\n\t#else\n\n\t\tuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n\t\tmat4 getBoneMatrix( const in float i ) {\n\n\t\t\tmat4 bone = boneGlobalMatrices[ int(i) ];\n\t\t\treturn bone;\n\n\t\t}\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.logdepthbuf_pars_fragment="#ifdef USE_LOGDEPTHBUF\n\n\tuniform float logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\t#extension GL_EXT_frag_depth : enable\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.alphamap_fragment="#ifdef USE_ALPHAMAP\n\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n";THREE.ShaderChunk.alphamap_pars_fragment="#ifdef USE_ALPHAMAP\n\n\tuniform sampler2D alphaMap;\n\n#endif\n"; +THREE.UniformsUtils={merge:function(a){for(var b={},c=0;c<a.length;c++){var d=this.clone(a[c]),e;for(e in d)b[e]=d[e]}return b},clone:function(a){var b={},c;for(c in a){b[c]={};for(var d in a[c]){var e=a[c][d];b[c][d]=e instanceof THREE.Color||e instanceof THREE.Vector2||e instanceof THREE.Vector3||e instanceof THREE.Vector4||e instanceof THREE.Matrix4||e instanceof THREE.Texture?e.clone():e instanceof Array?e.slice():e}}return b}}; +THREE.UniformsLib={common:{diffuse:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},lightMap:{type:"t",value:null},specularMap:{type:"t",value:null},alphaMap:{type:"t",value:null},envMap:{type:"t",value:null},flipEnvMap:{type:"f",value:-1},reflectivity:{type:"f",value:1},refractionRatio:{type:"f",value:.98},morphTargetInfluences:{type:"f",value:0}},bump:{bumpMap:{type:"t",value:null},bumpScale:{type:"f", +value:1}},normalmap:{normalMap:{type:"t",value:null},normalScale:{type:"v2",value:new THREE.Vector2(1,1)}},fog:{fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{ambientLightColor:{type:"fv",value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},hemisphereLightDirection:{type:"fv",value:[]},hemisphereLightSkyColor:{type:"fv",value:[]},hemisphereLightGroundColor:{type:"fv", +value:[]},pointLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightDistance:{type:"fv1",value:[]},pointLightDecay:{type:"fv1",value:[]},spotLightColor:{type:"fv",value:[]},spotLightPosition:{type:"fv",value:[]},spotLightDirection:{type:"fv",value:[]},spotLightDistance:{type:"fv1",value:[]},spotLightAngleCos:{type:"fv1",value:[]},spotLightExponent:{type:"fv1",value:[]},spotLightDecay:{type:"fv1",value:[]}},particle:{psColor:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f", +value:1},size:{type:"f",value:1},scale:{type:"f",value:1},map:{type:"t",value:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},shadowmap:{shadowMap:{type:"tv",value:[]},shadowMapSize:{type:"v2v",value:[]},shadowBias:{type:"fv1",value:[]},shadowDarkness:{type:"fv1",value:[]},shadowMatrix:{type:"m4v",value:[]}}}; +THREE.ShaderLib={basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.shadowmap]),vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {", +THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.skinbase_vertex,"\t#ifdef USE_ENVMAP",THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"\t#endif",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.shadowmap_vertex, +"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );", +THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{emissive:{type:"c",value:new THREE.Color(0)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.common,THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_lambert_pars_vertex, +THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex, +THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment, +THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment, +THREE.ShaderChunk.specularmap_fragment,"\t#ifdef DOUBLE_SIDED\n\t\tif ( gl_FrontFacing )\n\t\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\n\t\telse\n\t\t\toutgoingLight += diffuseColor.rgb * vLightBack + emissive;\n\t#else\n\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\n\t#endif",THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.bump,THREE.UniformsLib.normalmap,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{emissive:{type:"c",value:new THREE.Color(0)},specular:{type:"c",value:new THREE.Color(1118481)},shininess:{type:"f",value:30},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif",THREE.ShaderChunk.common, +THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_phong_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.skinbase_vertex, +THREE.ShaderChunk.skinnormal_vertex,THREE.ShaderChunk.defaultnormal_vertex,"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"\tvViewPosition = -mvPosition.xyz;",THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;", +THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.lights_phong_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.bumpmap_pars_fragment,THREE.ShaderChunk.normalmap_pars_fragment,THREE.ShaderChunk.specularmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment, +"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment, +THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},particle_basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.particle,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\tgl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_particle_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( psColor, opacity );", +THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphatest_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},dashed:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,{scale:{type:"f",value:1},dashSize:{type:"f",value:1},totalSize:{type:"f",value:2}}]), +vertexShader:["uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;", +THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.color_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment, +"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\n\tgl_FragColor = vec4( vec3( color ), opacity );\n}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex, +"void main() {\n\tvNormal = normalize( normalMatrix * normal );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null}, +tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment, +"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},equirect:{uniforms:{tEquirect:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", +THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\nvec3 direction = normalize( vWorldPosition );\nvec2 sampleUV;\nsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\nsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\ngl_FragColor = texture2D( tEquirect, sampleUV );",THREE.ShaderChunk.logdepthbuf_fragment, +"}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {", +THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}}; +THREE.WebGLRenderer=function(a){function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a.attributes){void 0===b.__webglCustomAttributesList&&(b.__webglCustomAttributesList=[]);for(var d in a.attributes){var e=a.attributes[d];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var f=1;"v2"===e.type?f=2:"v3"===e.type?f=3:"v4"===e.type?f=4:"c"===e.type&&(f=3);e.size=f;e.array=new Float32Array(c*f);e.buffer=m.createBuffer();e.buffer.belongsToAttribute=d;e.needsUpdate= +!0}b.__webglCustomAttributesList.push(e)}}}function c(a,b){return a.material instanceof THREE.MeshFaceMaterial?a.material.materials[b.materialIndex]:a.material}function d(a,b,c,d){c=c.attributes;var e=b.attributes;b=b.attributesKeys;for(var f=0,g=b.length;f<g;f++){var h=b[f],k=e[h];if(0<=k){var n=c[h];void 0!==n?(h=n.itemSize,m.bindBuffer(m.ARRAY_BUFFER,n.buffer),W.enableAttribute(k),m.vertexAttribPointer(k,h,m.FLOAT,!1,0,d*h*4)):void 0!==a.defaultAttributeValues&&(2===a.defaultAttributeValues[h].length? +m.vertexAttrib2fv(k,a.defaultAttributeValues[h]):3===a.defaultAttributeValues[h].length&&m.vertexAttrib3fv(k,a.defaultAttributeValues[h]))}}W.disableUnusedAttributes()}function e(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.material.id!==b.material.id?a.material.id-b.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function f(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function g(a, +b){return b[0]-a[0]}function h(a){if(!1!==a.visible){if(!(a instanceof THREE.Scene||a instanceof THREE.Group)){void 0===a.__webglInit&&(a.__webglInit=!0,a._modelViewMatrix=new THREE.Matrix4,a._normalMatrix=new THREE.Matrix3,a.addEventListener("removed",wb));var c=a.geometry;if(void 0!==c&&void 0===c.__webglInit)if(c.__webglInit=!0,c.addEventListener("dispose",jb),c instanceof THREE.BufferGeometry)B.info.memory.geometries++;else if(a instanceof THREE.Mesh)q(a,c);else if(a instanceof THREE.Line){if(void 0=== +c.__webglVertexBuffer){c.__webglVertexBuffer=m.createBuffer();c.__webglColorBuffer=m.createBuffer();c.__webglLineDistanceBuffer=m.createBuffer();B.info.memory.geometries++;var d=c.vertices.length;c.__vertexArray=new Float32Array(3*d);c.__colorArray=new Float32Array(3*d);c.__lineDistanceArray=new Float32Array(1*d);c.__webglLineCount=d;b(a);c.verticesNeedUpdate=!0;c.colorsNeedUpdate=!0;c.lineDistancesNeedUpdate=!0}}else a instanceof THREE.PointCloud&&void 0===c.__webglVertexBuffer&&(c.__webglVertexBuffer= +m.createBuffer(),c.__webglColorBuffer=m.createBuffer(),B.info.memory.geometries++,d=c.vertices.length,c.__vertexArray=new Float32Array(3*d),c.__colorArray=new Float32Array(3*d),c.__webglParticleCount=d,b(a),c.verticesNeedUpdate=!0,c.colorsNeedUpdate=!0);if(void 0===a.__webglActive)if(a.__webglActive=!0,a instanceof THREE.Mesh)if(c instanceof THREE.BufferGeometry)n(ba,c,a);else{if(c instanceof THREE.Geometry)for(var c=Ua[c.id],d=0,e=c.length;d<e;d++)n(ba,c[d],a)}else a instanceof THREE.Line||a instanceof +THREE.PointCloud?n(ba,c,a):(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)&&qa.push({id:null,object:a,opaque:null,transparent:null,z:0});if(a instanceof THREE.Light)ca.push(a);else if(a instanceof THREE.Sprite)Xa.push(a);else if(a instanceof THREE.LensFlare)Ya.push(a);else if((c=ba[a.id])&&(!1===a.frustumCulled||!0===cb.intersectsObject(a)))for(d=0,e=c.length;d<e;d++){var f=c[d],g=f,k=g.object,l=g.buffer,p=k.geometry,k=k.material;k instanceof THREE.MeshFaceMaterial?(k=k.materials[p instanceof +THREE.BufferGeometry?0:l.materialIndex],g.material=k,k.transparent?Qa.push(g):Ka.push(g)):k&&(g.material=k,k.transparent?Qa.push(g):Ka.push(g));f.render=!0;!0===B.sortObjects&&(wa.setFromMatrixPosition(a.matrixWorld),wa.applyProjection(db),f.z=wa.z)}}d=0;for(e=a.children.length;d<e;d++)h(a.children[d])}}function k(a,b,c,d,e){for(var f,g=0,h=a.length;g<h;g++){f=a[g];var k=f.object,m=f.buffer;w(k,b);if(e)f=e;else{f=f.material;if(!f)continue;u(f)}B.setMaterialFaces(f);m instanceof THREE.BufferGeometry? +B.renderBufferDirect(b,c,d,f,m,k):B.renderBuffer(b,c,d,f,m,k)}}function l(a,b,c,d,e,f){for(var g,h=0,k=a.length;h<k;h++){g=a[h];var m=g.object;if(m.visible){if(f)g=f;else{g=g[b];if(!g)continue;u(g)}B.renderImmediateObject(c,d,e,g,m)}}}function p(a){var b=a.object.material;b.transparent?(a.transparent=b,a.opaque=null):(a.opaque=b,a.transparent=null)}function q(a,b){var d=a.material,e=!1;if(void 0===Ua[b.id]||!0===b.groupsNeedUpdate){delete ba[a.id];for(var f=Ua,g=b.id,d=d instanceof THREE.MeshFaceMaterial, +h=da.get("OES_element_index_uint")?4294967296:65535,k,e={},l=b.morphTargets.length,p=b.morphNormals.length,q,s={},t=[],r=0,w=b.faces.length;r<w;r++){k=b.faces[r];var u=d?k.materialIndex:0;u in e||(e[u]={hash:u,counter:0});k=e[u].hash+"_"+e[u].counter;k in s||(q={id:Qb++,faces3:[],materialIndex:u,vertices:0,numMorphTargets:l,numMorphNormals:p},s[k]=q,t.push(q));s[k].vertices+3>h&&(e[u].counter+=1,k=e[u].hash+"_"+e[u].counter,k in s||(q={id:Qb++,faces3:[],materialIndex:u,vertices:0,numMorphTargets:l, +numMorphNormals:p},s[k]=q,t.push(q)));s[k].faces3.push(r);s[k].vertices+=3}f[g]=t;b.groupsNeedUpdate=!1}f=Ua[b.id];g=0;for(d=f.length;g<d;g++){h=f[g];if(void 0===h.__webglVertexBuffer){e=h;e.__webglVertexBuffer=m.createBuffer();e.__webglNormalBuffer=m.createBuffer();e.__webglTangentBuffer=m.createBuffer();e.__webglColorBuffer=m.createBuffer();e.__webglUVBuffer=m.createBuffer();e.__webglUV2Buffer=m.createBuffer();e.__webglSkinIndicesBuffer=m.createBuffer();e.__webglSkinWeightsBuffer=m.createBuffer(); +e.__webglFaceBuffer=m.createBuffer();e.__webglLineBuffer=m.createBuffer();if(p=e.numMorphTargets)for(e.__webglMorphTargetsBuffers=[],l=0;l<p;l++)e.__webglMorphTargetsBuffers.push(m.createBuffer());if(p=e.numMorphNormals)for(e.__webglMorphNormalsBuffers=[],l=0;l<p;l++)e.__webglMorphNormalsBuffers.push(m.createBuffer());B.info.memory.geometries++;e=h;r=a;w=r.geometry;p=e.faces3;l=3*p.length;s=1*p.length;t=3*p.length;p=c(r,e);e.__vertexArray=new Float32Array(3*l);e.__normalArray=new Float32Array(3*l); +e.__colorArray=new Float32Array(3*l);e.__uvArray=new Float32Array(2*l);1<w.faceVertexUvs.length&&(e.__uv2Array=new Float32Array(2*l));w.hasTangents&&(e.__tangentArray=new Float32Array(4*l));r.geometry.skinWeights.length&&r.geometry.skinIndices.length&&(e.__skinIndexArray=new Float32Array(4*l),e.__skinWeightArray=new Float32Array(4*l));r=null!==da.get("OES_element_index_uint")&&21845<s?Uint32Array:Uint16Array;e.__typeArray=r;e.__faceArray=new r(3*s);e.__lineArray=new r(2*t);if(w=e.numMorphTargets)for(e.__morphTargetsArrays= +[],r=0;r<w;r++)e.__morphTargetsArrays.push(new Float32Array(3*l));if(w=e.numMorphNormals)for(e.__morphNormalsArrays=[],r=0;r<w;r++)e.__morphNormalsArrays.push(new Float32Array(3*l));e.__webglFaceCount=3*s;e.__webglLineCount=2*t;if(p.attributes)for(s in void 0===e.__webglCustomAttributesList&&(e.__webglCustomAttributesList=[]),s=void 0,p.attributes){var t=p.attributes[s],r={},v;for(v in t)r[v]=t[v];if(!r.__webglInitialized||r.createUniqueBuffers)r.__webglInitialized=!0,w=1,"v2"===r.type?w=2:"v3"=== +r.type?w=3:"v4"===r.type?w=4:"c"===r.type&&(w=3),r.size=w,r.array=new Float32Array(l*w),r.buffer=m.createBuffer(),r.buffer.belongsToAttribute=s,t.needsUpdate=!0,r.__original=t;e.__webglCustomAttributesList.push(r)}e.__inittedArrays=!0;b.verticesNeedUpdate=!0;b.morphTargetsNeedUpdate=!0;b.elementsNeedUpdate=!0;b.uvsNeedUpdate=!0;b.normalsNeedUpdate=!0;b.tangentsNeedUpdate=!0;e=b.colorsNeedUpdate=!0}else e=!1;(e||void 0===a.__webglActive)&&n(ba,h,a)}a.__webglActive=!0}function n(a,b,c){var d=c.id;a[d]= +a[d]||[];a[d].push({id:d,buffer:b,object:c,material:null,z:0})}function t(a){var b=a.geometry;if(b instanceof THREE.BufferGeometry)for(var d=b.attributes,e=b.attributesKeys,f=0,g=e.length;f<g;f++){var h=e[f],k=d[h],n="index"===h?m.ELEMENT_ARRAY_BUFFER:m.ARRAY_BUFFER;void 0===k.buffer?(k.buffer=m.createBuffer(),m.bindBuffer(n,k.buffer),m.bufferData(n,k.array,k instanceof THREE.DynamicBufferAttribute?m.DYNAMIC_DRAW:m.STATIC_DRAW),k.needsUpdate=!1):!0===k.needsUpdate&&(m.bindBuffer(n,k.buffer),void 0=== +k.updateRange||-1===k.updateRange.count?m.bufferSubData(n,0,k.array):0===k.updateRange.count?console.error("THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually."):(m.bufferSubData(n,k.updateRange.offset*k.array.BYTES_PER_ELEMENT,k.array.subarray(k.updateRange.offset,k.updateRange.offset+k.updateRange.count)),k.updateRange.count=0),k.needsUpdate=!1)}else if(a instanceof THREE.Mesh){!0=== +b.groupsNeedUpdate&&q(a,b);for(var l=Ua[b.id],f=0,p=l.length;f<p;f++){var t=l[f],w=c(a,t),u=w.attributes&&r(w);if(b.verticesNeedUpdate||b.morphTargetsNeedUpdate||b.elementsNeedUpdate||b.uvsNeedUpdate||b.normalsNeedUpdate||b.colorsNeedUpdate||b.tangentsNeedUpdate||u){var v=t,x=a,D=m.DYNAMIC_DRAW,A=!b.dynamic,E=w;if(v.__inittedArrays){var G=!1===E instanceof THREE.MeshPhongMaterial&&E.shading===THREE.FlatShading,y=void 0,z=void 0,F=void 0,B=void 0,I=void 0,H=void 0,M=void 0,R=void 0,P=void 0,U=void 0, +O=void 0,J=void 0,L=void 0,N=void 0,Ka=void 0,V=void 0,W=void 0,Qa=void 0,Ya=void 0,Xa=void 0,da=void 0,ba=void 0,ja=void 0,Pa=void 0,ka=void 0,Q=void 0,ha=void 0,ia=void 0,ob=void 0,Y=void 0,ub=void 0,pa=void 0,ab=void 0,oa=void 0,ca=void 0,qa=void 0,Ca=void 0,ta=void 0,na=void 0,wa=void 0,La=0,Ma=0,kb=0,yb=0,zb=0,Ra=0,Aa=0,eb=0,Ha=0,la=0,ra=0,K=0,za=void 0,Sa=v.__vertexArray,Ab=v.__uvArray,lb=v.__uv2Array,Na=v.__normalArray,sa=v.__tangentArray,Da=v.__colorArray,Ea=v.__skinIndexArray,Fa=v.__skinWeightArray, +Gb=v.__morphTargetsArrays,Bb=v.__morphNormalsArrays,mb=v.__webglCustomAttributesList,C=void 0,Va=v.__faceArray,Ta=v.__lineArray,ea=x.geometry,fb=ea.elementsNeedUpdate,vb=ea.uvsNeedUpdate,Mb=ea.normalsNeedUpdate,Ob=ea.tangentsNeedUpdate,ib=ea.colorsNeedUpdate,sb=ea.morphTargetsNeedUpdate,Cb=ea.vertices,$=v.faces3,xa=ea.faces,Hb=ea.faceVertexUvs[0],Oa=ea.faceVertexUvs[1],$a=ea.skinIndices,Ga=ea.skinWeights,nb=ea.morphTargets,bb=ea.morphNormals;if(ea.verticesNeedUpdate){y=0;for(z=$.length;y<z;y++)B= +xa[$[y]],J=Cb[B.a],L=Cb[B.b],N=Cb[B.c],Sa[Ma]=J.x,Sa[Ma+1]=J.y,Sa[Ma+2]=J.z,Sa[Ma+3]=L.x,Sa[Ma+4]=L.y,Sa[Ma+5]=L.z,Sa[Ma+6]=N.x,Sa[Ma+7]=N.y,Sa[Ma+8]=N.z,Ma+=9;m.bindBuffer(m.ARRAY_BUFFER,v.__webglVertexBuffer);m.bufferData(m.ARRAY_BUFFER,Sa,D)}if(sb)for(ca=0,qa=nb.length;ca<qa;ca++){y=ra=0;for(z=$.length;y<z;y++)na=$[y],B=xa[na],J=nb[ca].vertices[B.a],L=nb[ca].vertices[B.b],N=nb[ca].vertices[B.c],Ca=Gb[ca],Ca[ra]=J.x,Ca[ra+1]=J.y,Ca[ra+2]=J.z,Ca[ra+3]=L.x,Ca[ra+4]=L.y,Ca[ra+5]=L.z,Ca[ra+6]=N.x,Ca[ra+ +7]=N.y,Ca[ra+8]=N.z,E.morphNormals&&(G?Xa=Ya=Qa=bb[ca].faceNormals[na]:(wa=bb[ca].vertexNormals[na],Qa=wa.a,Ya=wa.b,Xa=wa.c),ta=Bb[ca],ta[ra]=Qa.x,ta[ra+1]=Qa.y,ta[ra+2]=Qa.z,ta[ra+3]=Ya.x,ta[ra+4]=Ya.y,ta[ra+5]=Ya.z,ta[ra+6]=Xa.x,ta[ra+7]=Xa.y,ta[ra+8]=Xa.z),ra+=9;m.bindBuffer(m.ARRAY_BUFFER,v.__webglMorphTargetsBuffers[ca]);m.bufferData(m.ARRAY_BUFFER,Gb[ca],D);E.morphNormals&&(m.bindBuffer(m.ARRAY_BUFFER,v.__webglMorphNormalsBuffers[ca]),m.bufferData(m.ARRAY_BUFFER,Bb[ca],D))}if(Ga.length){y=0; +for(z=$.length;y<z;y++)B=xa[$[y]],Pa=Ga[B.a],ka=Ga[B.b],Q=Ga[B.c],Fa[la]=Pa.x,Fa[la+1]=Pa.y,Fa[la+2]=Pa.z,Fa[la+3]=Pa.w,Fa[la+4]=ka.x,Fa[la+5]=ka.y,Fa[la+6]=ka.z,Fa[la+7]=ka.w,Fa[la+8]=Q.x,Fa[la+9]=Q.y,Fa[la+10]=Q.z,Fa[la+11]=Q.w,ha=$a[B.a],ia=$a[B.b],ob=$a[B.c],Ea[la]=ha.x,Ea[la+1]=ha.y,Ea[la+2]=ha.z,Ea[la+3]=ha.w,Ea[la+4]=ia.x,Ea[la+5]=ia.y,Ea[la+6]=ia.z,Ea[la+7]=ia.w,Ea[la+8]=ob.x,Ea[la+9]=ob.y,Ea[la+10]=ob.z,Ea[la+11]=ob.w,la+=12;0<la&&(m.bindBuffer(m.ARRAY_BUFFER,v.__webglSkinIndicesBuffer), +m.bufferData(m.ARRAY_BUFFER,Ea,D),m.bindBuffer(m.ARRAY_BUFFER,v.__webglSkinWeightsBuffer),m.bufferData(m.ARRAY_BUFFER,Fa,D))}if(ib){y=0;for(z=$.length;y<z;y++)B=xa[$[y]],M=B.vertexColors,R=B.color,3===M.length&&E.vertexColors===THREE.VertexColors?(da=M[0],ba=M[1],ja=M[2]):ja=ba=da=R,Da[Ha]=da.r,Da[Ha+1]=da.g,Da[Ha+2]=da.b,Da[Ha+3]=ba.r,Da[Ha+4]=ba.g,Da[Ha+5]=ba.b,Da[Ha+6]=ja.r,Da[Ha+7]=ja.g,Da[Ha+8]=ja.b,Ha+=9;0<Ha&&(m.bindBuffer(m.ARRAY_BUFFER,v.__webglColorBuffer),m.bufferData(m.ARRAY_BUFFER,Da, +D))}if(Ob&&ea.hasTangents){y=0;for(z=$.length;y<z;y++)B=xa[$[y]],P=B.vertexTangents,Ka=P[0],V=P[1],W=P[2],sa[Aa]=Ka.x,sa[Aa+1]=Ka.y,sa[Aa+2]=Ka.z,sa[Aa+3]=Ka.w,sa[Aa+4]=V.x,sa[Aa+5]=V.y,sa[Aa+6]=V.z,sa[Aa+7]=V.w,sa[Aa+8]=W.x,sa[Aa+9]=W.y,sa[Aa+10]=W.z,sa[Aa+11]=W.w,Aa+=12;m.bindBuffer(m.ARRAY_BUFFER,v.__webglTangentBuffer);m.bufferData(m.ARRAY_BUFFER,sa,D)}if(Mb){y=0;for(z=$.length;y<z;y++)if(B=xa[$[y]],I=B.vertexNormals,H=B.normal,3===I.length&&!1===G)for(Y=0;3>Y;Y++)pa=I[Y],Na[Ra]=pa.x,Na[Ra+1]= +pa.y,Na[Ra+2]=pa.z,Ra+=3;else for(Y=0;3>Y;Y++)Na[Ra]=H.x,Na[Ra+1]=H.y,Na[Ra+2]=H.z,Ra+=3;m.bindBuffer(m.ARRAY_BUFFER,v.__webglNormalBuffer);m.bufferData(m.ARRAY_BUFFER,Na,D)}if(vb&&Hb){y=0;for(z=$.length;y<z;y++)if(F=$[y],U=Hb[F],void 0!==U)for(Y=0;3>Y;Y++)ab=U[Y],Ab[kb]=ab.x,Ab[kb+1]=ab.y,kb+=2;0<kb&&(m.bindBuffer(m.ARRAY_BUFFER,v.__webglUVBuffer),m.bufferData(m.ARRAY_BUFFER,Ab,D))}if(vb&&Oa){y=0;for(z=$.length;y<z;y++)if(F=$[y],O=Oa[F],void 0!==O)for(Y=0;3>Y;Y++)oa=O[Y],lb[yb]=oa.x,lb[yb+1]=oa.y, +yb+=2;0<yb&&(m.bindBuffer(m.ARRAY_BUFFER,v.__webglUV2Buffer),m.bufferData(m.ARRAY_BUFFER,lb,D))}if(fb){y=0;for(z=$.length;y<z;y++)Va[zb]=La,Va[zb+1]=La+1,Va[zb+2]=La+2,zb+=3,Ta[eb]=La,Ta[eb+1]=La+1,Ta[eb+2]=La,Ta[eb+3]=La+2,Ta[eb+4]=La+1,Ta[eb+5]=La+2,eb+=6,La+=3;m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,v.__webglFaceBuffer);m.bufferData(m.ELEMENT_ARRAY_BUFFER,Va,D);m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,v.__webglLineBuffer);m.bufferData(m.ELEMENT_ARRAY_BUFFER,Ta,D)}if(mb)for(Y=0,ub=mb.length;Y<ub;Y++)if(C= +mb[Y],C.__original.needsUpdate){K=0;if(1===C.size)if(void 0===C.boundTo||"vertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)B=xa[$[y]],C.array[K]=C.value[B.a],C.array[K+1]=C.value[B.b],C.array[K+2]=C.value[B.c],K+=3;else{if("faces"===C.boundTo)for(y=0,z=$.length;y<z;y++)za=C.value[$[y]],C.array[K]=za,C.array[K+1]=za,C.array[K+2]=za,K+=3}else if(2===C.size)if(void 0===C.boundTo||"vertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)B=xa[$[y]],J=C.value[B.a],L=C.value[B.b],N=C.value[B.c],C.array[K]=J.x, +C.array[K+1]=J.y,C.array[K+2]=L.x,C.array[K+3]=L.y,C.array[K+4]=N.x,C.array[K+5]=N.y,K+=6;else{if("faces"===C.boundTo)for(y=0,z=$.length;y<z;y++)N=L=J=za=C.value[$[y]],C.array[K]=J.x,C.array[K+1]=J.y,C.array[K+2]=L.x,C.array[K+3]=L.y,C.array[K+4]=N.x,C.array[K+5]=N.y,K+=6}else if(3===C.size){var T;T="c"===C.type?["r","g","b"]:["x","y","z"];if(void 0===C.boundTo||"vertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)B=xa[$[y]],J=C.value[B.a],L=C.value[B.b],N=C.value[B.c],C.array[K]=J[T[0]],C.array[K+1]= +J[T[1]],C.array[K+2]=J[T[2]],C.array[K+3]=L[T[0]],C.array[K+4]=L[T[1]],C.array[K+5]=L[T[2]],C.array[K+6]=N[T[0]],C.array[K+7]=N[T[1]],C.array[K+8]=N[T[2]],K+=9;else if("faces"===C.boundTo)for(y=0,z=$.length;y<z;y++)N=L=J=za=C.value[$[y]],C.array[K]=J[T[0]],C.array[K+1]=J[T[1]],C.array[K+2]=J[T[2]],C.array[K+3]=L[T[0]],C.array[K+4]=L[T[1]],C.array[K+5]=L[T[2]],C.array[K+6]=N[T[0]],C.array[K+7]=N[T[1]],C.array[K+8]=N[T[2]],K+=9;else if("faceVertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)za=C.value[$[y]], +J=za[0],L=za[1],N=za[2],C.array[K]=J[T[0]],C.array[K+1]=J[T[1]],C.array[K+2]=J[T[2]],C.array[K+3]=L[T[0]],C.array[K+4]=L[T[1]],C.array[K+5]=L[T[2]],C.array[K+6]=N[T[0]],C.array[K+7]=N[T[1]],C.array[K+8]=N[T[2]],K+=9}else if(4===C.size)if(void 0===C.boundTo||"vertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)B=xa[$[y]],J=C.value[B.a],L=C.value[B.b],N=C.value[B.c],C.array[K]=J.x,C.array[K+1]=J.y,C.array[K+2]=J.z,C.array[K+3]=J.w,C.array[K+4]=L.x,C.array[K+5]=L.y,C.array[K+6]=L.z,C.array[K+7]=L.w,C.array[K+ +8]=N.x,C.array[K+9]=N.y,C.array[K+10]=N.z,C.array[K+11]=N.w,K+=12;else if("faces"===C.boundTo)for(y=0,z=$.length;y<z;y++)N=L=J=za=C.value[$[y]],C.array[K]=J.x,C.array[K+1]=J.y,C.array[K+2]=J.z,C.array[K+3]=J.w,C.array[K+4]=L.x,C.array[K+5]=L.y,C.array[K+6]=L.z,C.array[K+7]=L.w,C.array[K+8]=N.x,C.array[K+9]=N.y,C.array[K+10]=N.z,C.array[K+11]=N.w,K+=12;else if("faceVertices"===C.boundTo)for(y=0,z=$.length;y<z;y++)za=C.value[$[y]],J=za[0],L=za[1],N=za[2],C.array[K]=J.x,C.array[K+1]=J.y,C.array[K+2]= +J.z,C.array[K+3]=J.w,C.array[K+4]=L.x,C.array[K+5]=L.y,C.array[K+6]=L.z,C.array[K+7]=L.w,C.array[K+8]=N.x,C.array[K+9]=N.y,C.array[K+10]=N.z,C.array[K+11]=N.w,K+=12;m.bindBuffer(m.ARRAY_BUFFER,C.buffer);m.bufferData(m.ARRAY_BUFFER,C.array,D)}A&&(delete v.__inittedArrays,delete v.__colorArray,delete v.__normalArray,delete v.__tangentArray,delete v.__uvArray,delete v.__uv2Array,delete v.__faceArray,delete v.__vertexArray,delete v.__lineArray,delete v.__skinIndexArray,delete v.__skinWeightArray)}}}b.verticesNeedUpdate= +!1;b.morphTargetsNeedUpdate=!1;b.elementsNeedUpdate=!1;b.uvsNeedUpdate=!1;b.normalsNeedUpdate=!1;b.colorsNeedUpdate=!1;b.tangentsNeedUpdate=!1;w.attributes&&s(w)}else if(a instanceof THREE.Line){w=c(a,b);u=w.attributes&&r(w);if(b.verticesNeedUpdate||b.colorsNeedUpdate||b.lineDistancesNeedUpdate||u){var Db=m.DYNAMIC_DRAW,S,aa,Z,Ba,X,Eb,Rb=b.vertices,Ib=b.colors,gb=b.lineDistances,ya=Rb.length,pb=Ib.length,qb=gb.length,Wa=b.__vertexArray,tb=b.__colorArray,hb=b.__lineDistanceArray,$b=b.colorsNeedUpdate, +Fb=b.lineDistancesNeedUpdate,Sb=b.__webglCustomAttributesList,Jb,cb,ua,Kb,Ia,fa;if(b.verticesNeedUpdate){for(S=0;S<ya;S++)Ba=Rb[S],X=3*S,Wa[X]=Ba.x,Wa[X+1]=Ba.y,Wa[X+2]=Ba.z;m.bindBuffer(m.ARRAY_BUFFER,b.__webglVertexBuffer);m.bufferData(m.ARRAY_BUFFER,Wa,Db)}if($b){for(aa=0;aa<pb;aa++)Eb=Ib[aa],X=3*aa,tb[X]=Eb.r,tb[X+1]=Eb.g,tb[X+2]=Eb.b;m.bindBuffer(m.ARRAY_BUFFER,b.__webglColorBuffer);m.bufferData(m.ARRAY_BUFFER,tb,Db)}if(Fb){for(Z=0;Z<qb;Z++)hb[Z]=gb[Z];m.bindBuffer(m.ARRAY_BUFFER,b.__webglLineDistanceBuffer); +m.bufferData(m.ARRAY_BUFFER,hb,Db)}if(Sb)for(Jb=0,cb=Sb.length;Jb<cb;Jb++)if(fa=Sb[Jb],fa.needsUpdate&&(void 0===fa.boundTo||"vertices"===fa.boundTo)){X=0;Kb=fa.value.length;if(1===fa.size)for(ua=0;ua<Kb;ua++)fa.array[ua]=fa.value[ua];else if(2===fa.size)for(ua=0;ua<Kb;ua++)Ia=fa.value[ua],fa.array[X]=Ia.x,fa.array[X+1]=Ia.y,X+=2;else if(3===fa.size)if("c"===fa.type)for(ua=0;ua<Kb;ua++)Ia=fa.value[ua],fa.array[X]=Ia.r,fa.array[X+1]=Ia.g,fa.array[X+2]=Ia.b,X+=3;else for(ua=0;ua<Kb;ua++)Ia=fa.value[ua], +fa.array[X]=Ia.x,fa.array[X+1]=Ia.y,fa.array[X+2]=Ia.z,X+=3;else if(4===fa.size)for(ua=0;ua<Kb;ua++)Ia=fa.value[ua],fa.array[X]=Ia.x,fa.array[X+1]=Ia.y,fa.array[X+2]=Ia.z,fa.array[X+3]=Ia.w,X+=4;m.bindBuffer(m.ARRAY_BUFFER,fa.buffer);m.bufferData(m.ARRAY_BUFFER,fa.array,Db);fa.needsUpdate=!1}}b.verticesNeedUpdate=!1;b.colorsNeedUpdate=!1;b.lineDistancesNeedUpdate=!1;w.attributes&&s(w)}else if(a instanceof THREE.PointCloud){w=c(a,b);u=w.attributes&&r(w);if(b.verticesNeedUpdate||b.colorsNeedUpdate|| +u){var db=m.DYNAMIC_DRAW,Tb,Ub,ac,ma,bc,Nb=b.vertices,Vb=Nb.length,Pb=b.colors,rb=Pb.length,cc=b.__vertexArray,dc=b.__colorArray,wb=b.colorsNeedUpdate,gc=b.__webglCustomAttributesList,ec,jb,va,Lb,Ja,ga;if(b.verticesNeedUpdate){for(Tb=0;Tb<Vb;Tb++)ac=Nb[Tb],ma=3*Tb,cc[ma]=ac.x,cc[ma+1]=ac.y,cc[ma+2]=ac.z;m.bindBuffer(m.ARRAY_BUFFER,b.__webglVertexBuffer);m.bufferData(m.ARRAY_BUFFER,cc,db)}if(wb){for(Ub=0;Ub<rb;Ub++)bc=Pb[Ub],ma=3*Ub,dc[ma]=bc.r,dc[ma+1]=bc.g,dc[ma+2]=bc.b;m.bindBuffer(m.ARRAY_BUFFER, +b.__webglColorBuffer);m.bufferData(m.ARRAY_BUFFER,dc,db)}if(gc)for(ec=0,jb=gc.length;ec<jb;ec++){ga=gc[ec];if(ga.needsUpdate&&(void 0===ga.boundTo||"vertices"===ga.boundTo))if(Lb=ga.value.length,ma=0,1===ga.size)for(va=0;va<Lb;va++)ga.array[va]=ga.value[va];else if(2===ga.size)for(va=0;va<Lb;va++)Ja=ga.value[va],ga.array[ma]=Ja.x,ga.array[ma+1]=Ja.y,ma+=2;else if(3===ga.size)if("c"===ga.type)for(va=0;va<Lb;va++)Ja=ga.value[va],ga.array[ma]=Ja.r,ga.array[ma+1]=Ja.g,ga.array[ma+2]=Ja.b,ma+=3;else for(va= +0;va<Lb;va++)Ja=ga.value[va],ga.array[ma]=Ja.x,ga.array[ma+1]=Ja.y,ga.array[ma+2]=Ja.z,ma+=3;else if(4===ga.size)for(va=0;va<Lb;va++)Ja=ga.value[va],ga.array[ma]=Ja.x,ga.array[ma+1]=Ja.y,ga.array[ma+2]=Ja.z,ga.array[ma+3]=Ja.w,ma+=4;m.bindBuffer(m.ARRAY_BUFFER,ga.buffer);m.bufferData(m.ARRAY_BUFFER,ga.array,db);ga.needsUpdate=!1}}b.verticesNeedUpdate=!1;b.colorsNeedUpdate=!1;w.attributes&&s(w)}}function r(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0;return!1}function s(a){for(var b in a.attributes)a.attributes[b].needsUpdate= +!1}function u(a){!0===a.transparent?W.setBlending(a.blending,a.blendEquation,a.blendSrc,a.blendDst,a.blendEquationAlpha,a.blendSrcAlpha,a.blendDstAlpha):W.setBlending(THREE.NoBlending);W.setDepthTest(a.depthTest);W.setDepthWrite(a.depthWrite);W.setColorWrite(a.colorWrite);W.setPolygonOffset(a.polygonOffset,a.polygonOffsetFactor,a.polygonOffsetUnits)}function v(a,b,c,d,e){var f,g,h,k;Mb=0;if(d.needsUpdate){d.program&&hc(d);d.addEventListener("dispose",ic);var n=pc[d.type];if(n){var l=THREE.ShaderLib[n]; +d.__webglShader={uniforms:THREE.UniformsUtils.clone(l.uniforms),vertexShader:l.vertexShader,fragmentShader:l.fragmentShader}}else d.__webglShader={uniforms:d.uniforms,vertexShader:d.vertexShader,fragmentShader:d.fragmentShader};for(var p=0,q=0,r=0,s=0,t=0,w=b.length;t<w;t++){var v=b[t];v.onlyShadow||!1===v.visible||(v instanceof THREE.DirectionalLight&&p++,v instanceof THREE.PointLight&&q++,v instanceof THREE.SpotLight&&r++,v instanceof THREE.HemisphereLight&&s++)}f=p;g=q;h=r;k=s;for(var u,z=0,G= +0,F=b.length;G<F;G++){var J=b[G];J.castShadow&&(J instanceof THREE.SpotLight&&z++,J instanceof THREE.DirectionalLight&&!J.shadowCascade&&z++)}u=z;var H;if(Nb&&e&&e.skeleton&&e.skeleton.useVertexTexture)H=1024;else{var N=m.getParameter(m.MAX_VERTEX_UNIFORM_VECTORS),M=Math.floor((N-20)/4);void 0!==e&&e instanceof THREE.SkinnedMesh&&(M=Math.min(e.skeleton.bones.length,M),M<e.skeleton.bones.length&&THREE.warn("WebGLRenderer: too many bones - "+e.skeleton.bones.length+", this GPU supports just "+M+" (try OpenGL instead of ANGLE)")); +H=M}var P={precision:L,supportsVertexTextures:Vb,map:!!d.map,envMap:!!d.envMap,envMapMode:d.envMap&&d.envMap.mapping,lightMap:!!d.lightMap,bumpMap:!!d.bumpMap,normalMap:!!d.normalMap,specularMap:!!d.specularMap,alphaMap:!!d.alphaMap,combine:d.combine,vertexColors:d.vertexColors,fog:c,useFog:d.fog,fogExp:c instanceof THREE.FogExp2,flatShading:d.shading===THREE.FlatShading,sizeAttenuation:d.sizeAttenuation,logarithmicDepthBuffer:ja,skinning:d.skinning,maxBones:H,useVertexTexture:Nb&&e&&e.skeleton&& +e.skeleton.useVertexTexture,morphTargets:d.morphTargets,morphNormals:d.morphNormals,maxMorphTargets:B.maxMorphTargets,maxMorphNormals:B.maxMorphNormals,maxDirLights:f,maxPointLights:g,maxSpotLights:h,maxHemiLights:k,maxShadows:u,shadowMapEnabled:B.shadowMapEnabled&&e.receiveShadow&&0<u,shadowMapType:B.shadowMapType,shadowMapDebug:B.shadowMapDebug,shadowMapCascade:B.shadowMapCascade,alphaTest:d.alphaTest,metal:d.metal,wrapAround:d.wrapAround,doubleSided:d.side===THREE.DoubleSide,flipSided:d.side=== +THREE.BackSide},R=[];n?R.push(n):(R.push(d.fragmentShader),R.push(d.vertexShader));if(void 0!==d.defines)for(var O in d.defines)R.push(O),R.push(d.defines[O]);for(O in P)R.push(O),R.push(P[O]);for(var Ka=R.join(),V,W=0,Qa=Pa.length;W<Qa;W++){var Ya=Pa[W];if(Ya.code===Ka){V=Ya;V.usedTimes++;break}}void 0===V&&(V=new THREE.WebGLProgram(B,Ka,d,P),Pa.push(V),B.info.memory.programs=Pa.length);d.program=V;var Xa=V.attributes;if(d.morphTargets){d.numSupportedMorphTargets=0;for(var ca,da="morphTarget",ba= +0;ba<B.maxMorphTargets;ba++)ca=da+ba,0<=Xa[ca]&&d.numSupportedMorphTargets++}if(d.morphNormals)for(d.numSupportedMorphNormals=0,da="morphNormal",ba=0;ba<B.maxMorphNormals;ba++)ca=da+ba,0<=Xa[ca]&&d.numSupportedMorphNormals++;d.uniformsList=[];for(var ha in d.__webglShader.uniforms){var ta=d.program.uniforms[ha];ta&&d.uniformsList.push([d.__webglShader.uniforms[ha],ta])}d.needsUpdate=!1}d.morphTargets&&!e.__webglMorphTargetInfluences&&(e.__webglMorphTargetInfluences=new Float32Array(B.maxMorphTargets)); +var ab=!1,oa=!1,qa=!1,Ua=d.program,ka=Ua.uniforms,Q=d.__webglShader.uniforms;Ua.id!==ob&&(m.useProgram(Ua.program),ob=Ua.id,qa=oa=ab=!0);d.id!==ub&&(-1===ub&&(qa=!0),ub=d.id,oa=!0);if(ab||a!==vb)m.uniformMatrix4fv(ka.projectionMatrix,!1,a.projectionMatrix.elements),ja&&m.uniform1f(ka.logDepthBufFC,2/(Math.log(a.far+1)/Math.LN2)),a!==vb&&(vb=a),(d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&null!==ka.cameraPosition&&(wa.setFromMatrixPosition(a.matrixWorld),m.uniform3f(ka.cameraPosition, +wa.x,wa.y,wa.z)),(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshBasicMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==ka.viewMatrix&&m.uniformMatrix4fv(ka.viewMatrix,!1,a.matrixWorldInverse.elements);if(d.skinning)if(e.bindMatrix&&null!==ka.bindMatrix&&m.uniformMatrix4fv(ka.bindMatrix,!1,e.bindMatrix.elements),e.bindMatrixInverse&&null!==ka.bindMatrixInverse&&m.uniformMatrix4fv(ka.bindMatrixInverse,!1,e.bindMatrixInverse.elements), +Nb&&e.skeleton&&e.skeleton.useVertexTexture){if(null!==ka.boneTexture){var db=D();m.uniform1i(ka.boneTexture,db);B.setTexture(e.skeleton.boneTexture,db)}null!==ka.boneTextureWidth&&m.uniform1i(ka.boneTextureWidth,e.skeleton.boneTextureWidth);null!==ka.boneTextureHeight&&m.uniform1i(ka.boneTextureHeight,e.skeleton.boneTextureHeight)}else e.skeleton&&e.skeleton.boneMatrices&&null!==ka.boneGlobalMatrices&&m.uniformMatrix4fv(ka.boneGlobalMatrices,!1,e.skeleton.boneMatrices);if(oa){c&&d.fog&&(Q.fogColor.value= +c.color,c instanceof THREE.Fog?(Q.fogNear.value=c.near,Q.fogFar.value=c.far):c instanceof THREE.FogExp2&&(Q.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(Ob){var qa=!0,ia,Za,Y,bb=0,cb=0,ib=0,xb,pb,qb,Ca,jb,na=jc,rb=na.directional.colors,La=na.directional.positions,Ma=na.point.colors,kb=na.point.positions,yb=na.point.distances,zb=na.point.decays,Ra=na.spot.colors,Aa=na.spot.positions,eb=na.spot.distances,Ha=na.spot.directions, +la=na.spot.anglesCos,ra=na.spot.exponents,K=na.spot.decays,za=na.hemi.skyColors,Sa=na.hemi.groundColors,Ab=na.hemi.positions,lb=0,Na=0,sa=0,Da=0,Ea=0,Fa=0,Gb=0,Bb=0,mb=0,C=0,Va=0,Ta=0;ia=0;for(Za=b.length;ia<Za;ia++)Y=b[ia],Y.onlyShadow||(xb=Y.color,Ca=Y.intensity,jb=Y.distance,Y instanceof THREE.AmbientLight?Y.visible&&(bb+=xb.r,cb+=xb.g,ib+=xb.b):Y instanceof THREE.DirectionalLight?(Ea+=1,Y.visible&&(pa.setFromMatrixPosition(Y.matrixWorld),wa.setFromMatrixPosition(Y.target.matrixWorld),pa.sub(wa), +pa.normalize(),mb=3*lb,La[mb]=pa.x,La[mb+1]=pa.y,La[mb+2]=pa.z,y(rb,mb,xb,Ca),lb+=1)):Y instanceof THREE.PointLight?(Fa+=1,Y.visible&&(C=3*Na,y(Ma,C,xb,Ca),wa.setFromMatrixPosition(Y.matrixWorld),kb[C]=wa.x,kb[C+1]=wa.y,kb[C+2]=wa.z,yb[Na]=jb,zb[Na]=0===Y.distance?0:Y.decay,Na+=1)):Y instanceof THREE.SpotLight?(Gb+=1,Y.visible&&(Va=3*sa,y(Ra,Va,xb,Ca),pa.setFromMatrixPosition(Y.matrixWorld),Aa[Va]=pa.x,Aa[Va+1]=pa.y,Aa[Va+2]=pa.z,eb[sa]=jb,wa.setFromMatrixPosition(Y.target.matrixWorld),pa.sub(wa), +pa.normalize(),Ha[Va]=pa.x,Ha[Va+1]=pa.y,Ha[Va+2]=pa.z,la[sa]=Math.cos(Y.angle),ra[sa]=Y.exponent,K[sa]=0===Y.distance?0:Y.decay,sa+=1)):Y instanceof THREE.HemisphereLight&&(Bb+=1,Y.visible&&(pa.setFromMatrixPosition(Y.matrixWorld),pa.normalize(),Ta=3*Da,Ab[Ta]=pa.x,Ab[Ta+1]=pa.y,Ab[Ta+2]=pa.z,pb=Y.color,qb=Y.groundColor,y(za,Ta,pb,Ca),y(Sa,Ta,qb,Ca),Da+=1)));ia=3*lb;for(Za=Math.max(rb.length,3*Ea);ia<Za;ia++)rb[ia]=0;ia=3*Na;for(Za=Math.max(Ma.length,3*Fa);ia<Za;ia++)Ma[ia]=0;ia=3*sa;for(Za=Math.max(Ra.length, +3*Gb);ia<Za;ia++)Ra[ia]=0;ia=3*Da;for(Za=Math.max(za.length,3*Bb);ia<Za;ia++)za[ia]=0;ia=3*Da;for(Za=Math.max(Sa.length,3*Bb);ia<Za;ia++)Sa[ia]=0;na.directional.length=lb;na.point.length=Na;na.spot.length=sa;na.hemi.length=Da;na.ambient[0]=bb;na.ambient[1]=cb;na.ambient[2]=ib;Ob=!1}if(qa){var ea=jc;Q.ambientLightColor.value=ea.ambient;Q.directionalLightColor.value=ea.directional.colors;Q.directionalLightDirection.value=ea.directional.positions;Q.pointLightColor.value=ea.point.colors;Q.pointLightPosition.value= +ea.point.positions;Q.pointLightDistance.value=ea.point.distances;Q.pointLightDecay.value=ea.point.decays;Q.spotLightColor.value=ea.spot.colors;Q.spotLightPosition.value=ea.spot.positions;Q.spotLightDistance.value=ea.spot.distances;Q.spotLightDirection.value=ea.spot.directions;Q.spotLightAngleCos.value=ea.spot.anglesCos;Q.spotLightExponent.value=ea.spot.exponents;Q.spotLightDecay.value=ea.spot.decays;Q.hemisphereLightSkyColor.value=ea.hemi.skyColors;Q.hemisphereLightGroundColor.value=ea.hemi.groundColors; +Q.hemisphereLightDirection.value=ea.hemi.positions;x(Q,!0)}else x(Q,!1)}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){Q.opacity.value=d.opacity;Q.diffuse.value=d.color;Q.map.value=d.map;Q.lightMap.value=d.lightMap;Q.specularMap.value=d.specularMap;Q.alphaMap.value=d.alphaMap;d.bumpMap&&(Q.bumpMap.value=d.bumpMap,Q.bumpScale.value=d.bumpScale);d.normalMap&&(Q.normalMap.value=d.normalMap,Q.normalScale.value.copy(d.normalScale)); +var fb;d.map?fb=d.map:d.specularMap?fb=d.specularMap:d.normalMap?fb=d.normalMap:d.bumpMap?fb=d.bumpMap:d.alphaMap&&(fb=d.alphaMap);if(void 0!==fb){var wb=fb.offset,Qb=fb.repeat;Q.offsetRepeat.value.set(wb.x,wb.y,Qb.x,Qb.y)}Q.envMap.value=d.envMap;Q.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;Q.reflectivity.value=d.reflectivity;Q.refractionRatio.value=d.refractionRatio}if(d instanceof THREE.LineBasicMaterial)Q.diffuse.value=d.color,Q.opacity.value=d.opacity;else if(d instanceof +THREE.LineDashedMaterial)Q.diffuse.value=d.color,Q.opacity.value=d.opacity,Q.dashSize.value=d.dashSize,Q.totalSize.value=d.dashSize+d.gapSize,Q.scale.value=d.scale;else if(d instanceof THREE.PointCloudMaterial){if(Q.psColor.value=d.color,Q.opacity.value=d.opacity,Q.size.value=d.size,Q.scale.value=U.height/2,Q.map.value=d.map,null!==d.map){var Wb=d.map.offset,Xb=d.map.repeat;Q.offsetRepeat.value.set(Wb.x,Wb.y,Xb.x,Xb.y)}}else d instanceof THREE.MeshPhongMaterial?(Q.shininess.value=d.shininess,Q.emissive.value= +d.emissive,Q.specular.value=d.specular,d.wrapAround&&Q.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshLambertMaterial?(Q.emissive.value=d.emissive,d.wrapAround&&Q.wrapRGB.value.copy(d.wrapRGB)):d instanceof THREE.MeshDepthMaterial?(Q.mNear.value=a.near,Q.mFar.value=a.far,Q.opacity.value=d.opacity):d instanceof THREE.MeshNormalMaterial&&(Q.opacity.value=d.opacity);if(e.receiveShadow&&!d._shadowPass&&Q.shadowMatrix)for(var sb=0,Cb=0,$=b.length;Cb<$;Cb++){var xa=b[Cb];xa.castShadow&&(xa instanceof +THREE.SpotLight||xa instanceof THREE.DirectionalLight&&!xa.shadowCascade)&&(Q.shadowMap.value[sb]=xa.shadowMap,Q.shadowMapSize.value[sb]=xa.shadowMapSize,Q.shadowMatrix.value[sb]=xa.shadowMatrix,Q.shadowDarkness.value[sb]=xa.shadowDarkness,Q.shadowBias.value[sb]=xa.shadowBias,sb++)}for(var Hb=d.uniformsList,Oa,$a,Ga,nb=0,fc=Hb.length;nb<fc;nb++){var T=Hb[nb][0];if(!1!==T.needsUpdate){var Db=T.type,S=T.value,aa=Hb[nb][1];switch(Db){case "1i":m.uniform1i(aa,S);break;case "1f":m.uniform1f(aa,S);break; +case "2f":m.uniform2f(aa,S[0],S[1]);break;case "3f":m.uniform3f(aa,S[0],S[1],S[2]);break;case "4f":m.uniform4f(aa,S[0],S[1],S[2],S[3]);break;case "1iv":m.uniform1iv(aa,S);break;case "3iv":m.uniform3iv(aa,S);break;case "1fv":m.uniform1fv(aa,S);break;case "2fv":m.uniform2fv(aa,S);break;case "3fv":m.uniform3fv(aa,S);break;case "4fv":m.uniform4fv(aa,S);break;case "Matrix3fv":m.uniformMatrix3fv(aa,!1,S);break;case "Matrix4fv":m.uniformMatrix4fv(aa,!1,S);break;case "i":m.uniform1i(aa,S);break;case "f":m.uniform1f(aa, +S);break;case "v2":m.uniform2f(aa,S.x,S.y);break;case "v3":m.uniform3f(aa,S.x,S.y,S.z);break;case "v4":m.uniform4f(aa,S.x,S.y,S.z,S.w);break;case "c":m.uniform3f(aa,S.r,S.g,S.b);break;case "iv1":m.uniform1iv(aa,S);break;case "iv":m.uniform3iv(aa,S);break;case "fv1":m.uniform1fv(aa,S);break;case "fv":m.uniform3fv(aa,S);break;case "v2v":void 0===T._array&&(T._array=new Float32Array(2*S.length));for(var Z=0,Ba=S.length;Z<Ba;Z++)Ga=2*Z,T._array[Ga]=S[Z].x,T._array[Ga+1]=S[Z].y;m.uniform2fv(aa,T._array); +break;case "v3v":void 0===T._array&&(T._array=new Float32Array(3*S.length));Z=0;for(Ba=S.length;Z<Ba;Z++)Ga=3*Z,T._array[Ga]=S[Z].x,T._array[Ga+1]=S[Z].y,T._array[Ga+2]=S[Z].z;m.uniform3fv(aa,T._array);break;case "v4v":void 0===T._array&&(T._array=new Float32Array(4*S.length));Z=0;for(Ba=S.length;Z<Ba;Z++)Ga=4*Z,T._array[Ga]=S[Z].x,T._array[Ga+1]=S[Z].y,T._array[Ga+2]=S[Z].z,T._array[Ga+3]=S[Z].w;m.uniform4fv(aa,T._array);break;case "m3":m.uniformMatrix3fv(aa,!1,S.elements);break;case "m3v":void 0=== +T._array&&(T._array=new Float32Array(9*S.length));Z=0;for(Ba=S.length;Z<Ba;Z++)S[Z].flattenToArrayOffset(T._array,9*Z);m.uniformMatrix3fv(aa,!1,T._array);break;case "m4":m.uniformMatrix4fv(aa,!1,S.elements);break;case "m4v":void 0===T._array&&(T._array=new Float32Array(16*S.length));Z=0;for(Ba=S.length;Z<Ba;Z++)S[Z].flattenToArrayOffset(T._array,16*Z);m.uniformMatrix4fv(aa,!1,T._array);break;case "t":Oa=S;$a=D();m.uniform1i(aa,$a);if(!Oa)continue;if(Oa instanceof THREE.CubeTexture||Oa.image instanceof +Array&&6===Oa.image.length){var X=Oa,Eb=$a;if(6===X.image.length)if(X.needsUpdate){X.image.__webglTextureCube||(X.addEventListener("dispose",Pb),X.image.__webglTextureCube=m.createTexture(),B.info.memory.textures++);m.activeTexture(m.TEXTURE0+Eb);m.bindTexture(m.TEXTURE_CUBE_MAP,X.image.__webglTextureCube);m.pixelStorei(m.UNPACK_FLIP_Y_WEBGL,X.flipY);for(var Rb=X instanceof THREE.CompressedTexture,Ib=X.image[0]instanceof THREE.DataTexture,gb=[],ya=0;6>ya;ya++)gb[ya]=!B.autoScaleCubemaps||Rb||Ib?Ib? +X.image[ya].image:X.image[ya]:E(X.image[ya],qc);var Yb=gb[0],Zb=THREE.Math.isPowerOfTwo(Yb.width)&&THREE.Math.isPowerOfTwo(Yb.height),Wa=I(X.format),tb=I(X.type);A(m.TEXTURE_CUBE_MAP,X,Zb);for(ya=0;6>ya;ya++)if(Rb)for(var hb,$b=gb[ya].mipmaps,Fb=0,Sb=$b.length;Fb<Sb;Fb++)hb=$b[Fb],X.format!==THREE.RGBAFormat&&X.format!==THREE.RGBFormat?-1<kc().indexOf(Wa)?m.compressedTexImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+ya,Fb,Wa,hb.width,hb.height,0,hb.data):THREE.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()"): +m.texImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+ya,Fb,Wa,hb.width,hb.height,0,Wa,tb,hb.data);else Ib?m.texImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+ya,0,Wa,gb[ya].width,gb[ya].height,0,Wa,tb,gb[ya].data):m.texImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+ya,0,Wa,Wa,tb,gb[ya]);X.generateMipmaps&&Zb&&m.generateMipmap(m.TEXTURE_CUBE_MAP);X.needsUpdate=!1;if(X.onUpdate)X.onUpdate()}else m.activeTexture(m.TEXTURE0+Eb),m.bindTexture(m.TEXTURE_CUBE_MAP,X.image.__webglTextureCube)}else if(Oa instanceof THREE.WebGLRenderTargetCube){var Jb= +Oa;m.activeTexture(m.TEXTURE0+$a);m.bindTexture(m.TEXTURE_CUBE_MAP,Jb.__webglTexture)}else B.setTexture(Oa,$a);break;case "tv":void 0===T._array&&(T._array=[]);Z=0;for(Ba=T.value.length;Z<Ba;Z++)T._array[Z]=D();m.uniform1iv(aa,T._array);Z=0;for(Ba=T.value.length;Z<Ba;Z++)Oa=T.value[Z],$a=T._array[Z],Oa&&B.setTexture(Oa,$a);break;default:THREE.warn("THREE.WebGLRenderer: Unknown uniform type: "+Db)}}}}m.uniformMatrix4fv(ka.modelViewMatrix,!1,e._modelViewMatrix.elements);ka.normalMatrix&&m.uniformMatrix3fv(ka.normalMatrix, +!1,e._normalMatrix.elements);null!==ka.modelMatrix&&m.uniformMatrix4fv(ka.modelMatrix,!1,e.matrixWorld.elements);return Ua}function x(a,b){a.ambientLightColor.needsUpdate=b;a.directionalLightColor.needsUpdate=b;a.directionalLightDirection.needsUpdate=b;a.pointLightColor.needsUpdate=b;a.pointLightPosition.needsUpdate=b;a.pointLightDistance.needsUpdate=b;a.pointLightDecay.needsUpdate=b;a.spotLightColor.needsUpdate=b;a.spotLightPosition.needsUpdate=b;a.spotLightDistance.needsUpdate=b;a.spotLightDirection.needsUpdate= +b;a.spotLightAngleCos.needsUpdate=b;a.spotLightExponent.needsUpdate=b;a.spotLightDecay.needsUpdate=b;a.hemisphereLightSkyColor.needsUpdate=b;a.hemisphereLightGroundColor.needsUpdate=b;a.hemisphereLightDirection.needsUpdate=b}function D(){var a=Mb;a>=Wb&&THREE.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Wb);Mb+=1;return a}function w(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getNormalMatrix(a._modelViewMatrix)} +function y(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function A(a,b,c){c?(m.texParameteri(a,m.TEXTURE_WRAP_S,I(b.wrapS)),m.texParameteri(a,m.TEXTURE_WRAP_T,I(b.wrapT)),m.texParameteri(a,m.TEXTURE_MAG_FILTER,I(b.magFilter)),m.texParameteri(a,m.TEXTURE_MIN_FILTER,I(b.minFilter))):(m.texParameteri(a,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE),m.texParameteri(a,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||THREE.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( "+ +b.sourceFile+" )"),m.texParameteri(a,m.TEXTURE_MAG_FILTER,z(b.magFilter)),m.texParameteri(a,m.TEXTURE_MIN_FILTER,z(b.minFilter)),b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&THREE.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( "+b.sourceFile+" )"));(c=da.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&b.type!==THREE.HalfFloatType&&(1<b.anisotropy||b.__currentAnisotropy)&& +(m.texParameterf(a,c.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,B.getMaxAnisotropy())),b.__currentAnisotropy=b.anisotropy)}function E(a,b){if(a.width>b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);THREE.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a} +function G(a,b){m.bindRenderbuffer(m.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(m.renderbufferStorage(m.RENDERBUFFER,m.DEPTH_COMPONENT16,b.width,b.height),m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_ATTACHMENT,m.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(m.renderbufferStorage(m.RENDERBUFFER,m.DEPTH_STENCIL,b.width,b.height),m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_STENCIL_ATTACHMENT,m.RENDERBUFFER,a)):m.renderbufferStorage(m.RENDERBUFFER,m.RGBA4,b.width,b.height)}function F(a){a instanceof +THREE.WebGLRenderTargetCube?(m.bindTexture(m.TEXTURE_CUBE_MAP,a.__webglTexture),m.generateMipmap(m.TEXTURE_CUBE_MAP),m.bindTexture(m.TEXTURE_CUBE_MAP,null)):(m.bindTexture(m.TEXTURE_2D,a.__webglTexture),m.generateMipmap(m.TEXTURE_2D),m.bindTexture(m.TEXTURE_2D,null))}function z(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?m.NEAREST:m.LINEAR}function I(a){var b;if(a===THREE.RepeatWrapping)return m.REPEAT;if(a===THREE.ClampToEdgeWrapping)return m.CLAMP_TO_EDGE; +if(a===THREE.MirroredRepeatWrapping)return m.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return m.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return m.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return m.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return m.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return m.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return m.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return m.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return m.UNSIGNED_SHORT_4_4_4_4; +if(a===THREE.UnsignedShort5551Type)return m.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return m.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return m.BYTE;if(a===THREE.ShortType)return m.SHORT;if(a===THREE.UnsignedShortType)return m.UNSIGNED_SHORT;if(a===THREE.IntType)return m.INT;if(a===THREE.UnsignedIntType)return m.UNSIGNED_INT;if(a===THREE.FloatType)return m.FLOAT;b=da.get("OES_texture_half_float");if(null!==b&&a===THREE.HalfFloatType)return b.HALF_FLOAT_OES;if(a===THREE.AlphaFormat)return m.ALPHA; +if(a===THREE.RGBFormat)return m.RGB;if(a===THREE.RGBAFormat)return m.RGBA;if(a===THREE.LuminanceFormat)return m.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return m.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return m.FUNC_ADD;if(a===THREE.SubtractEquation)return m.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return m.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return m.ZERO;if(a===THREE.OneFactor)return m.ONE;if(a===THREE.SrcColorFactor)return m.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return m.ONE_MINUS_SRC_COLOR; +if(a===THREE.SrcAlphaFactor)return m.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return m.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return m.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return m.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return m.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return m.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return m.SRC_ALPHA_SATURATE;b=da.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT; +if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=da.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; +if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=da.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var U=void 0!==a.canvas?a.canvas:document.createElement("canvas"),M=void 0!==a.context?a.context:null,H=1,L=void 0!==a.precision?a.precision:"highp",P=void 0!==a.alpha?a.alpha:!1,N=void 0!==a.depth?a.depth:!0,R=void 0!==a.stencil? +a.stencil:!0,V=void 0!==a.antialias?a.antialias:!1,J=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,oa=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,ja=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,ha=new THREE.Color(0),O=0,ca=[],ba={},qa=[],Ka=[],Qa=[],Xa=[],Ya=[];this.domElement=U;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.gammaFactor=2;this.shadowMapEnabled=this.gammaOutput=this.gammaInput= +!1;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var B=this,Pa=[],ob=null,ab=null,ub=-1,ta="",vb=null,Mb=0,ib=0,bb=0,pb=U.width,qb=U.height,Xb=0,fc=0,cb=new THREE.Frustum,db=new THREE.Matrix4,wa=new THREE.Vector3,pa=new THREE.Vector3,Ob=!0,jc={ambient:[0, +0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[],decays:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[],decays:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},m;try{var Yb={alpha:P,depth:N,stencil:R,antialias:V,premultipliedAlpha:J,preserveDrawingBuffer:oa};m=M||U.getContext("webgl",Yb)||U.getContext("experimental-webgl",Yb);if(null===m){if(null!==U.getContext("webgl"))throw"Error creating WebGL context with your selected attributes."; +throw"Error creating WebGL context.";}U.addEventListener("webglcontextlost",function(a){a.preventDefault();Zb();lc();ba={}},!1)}catch(rc){THREE.error("THREE.WebGLRenderer: "+rc)}var W=new THREE.WebGLState(m,I);void 0===m.getShaderPrecisionFormat&&(m.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var da=new THREE.WebGLExtensions(m);da.get("OES_texture_float");da.get("OES_texture_float_linear");da.get("OES_texture_half_float");da.get("OES_texture_half_float_linear"); +da.get("OES_standard_derivatives");ja&&da.get("EXT_frag_depth");var rb=function(a,b,c,d){!0===J&&(a*=d,b*=d,c*=d);m.clearColor(a,b,c,d)},lc=function(){m.clearColor(0,0,0,1);m.clearDepth(1);m.clearStencil(0);m.enable(m.DEPTH_TEST);m.depthFunc(m.LEQUAL);m.frontFace(m.CCW);m.cullFace(m.BACK);m.enable(m.CULL_FACE);m.enable(m.BLEND);m.blendEquation(m.FUNC_ADD);m.blendFunc(m.SRC_ALPHA,m.ONE_MINUS_SRC_ALPHA);m.viewport(ib,bb,pb,qb);rb(ha.r,ha.g,ha.b,O)},Zb=function(){vb=ob=null;ta="";ub=-1;Ob=!0;W.reset()}; +lc();this.context=m;this.state=W;var Wb=m.getParameter(m.MAX_TEXTURE_IMAGE_UNITS),sc=m.getParameter(m.MAX_VERTEX_TEXTURE_IMAGE_UNITS),tc=m.getParameter(m.MAX_TEXTURE_SIZE),qc=m.getParameter(m.MAX_CUBE_MAP_TEXTURE_SIZE),Vb=0<sc,Nb=Vb&&da.get("OES_texture_float"),uc=m.getShaderPrecisionFormat(m.VERTEX_SHADER,m.HIGH_FLOAT),vc=m.getShaderPrecisionFormat(m.VERTEX_SHADER,m.MEDIUM_FLOAT),wc=m.getShaderPrecisionFormat(m.FRAGMENT_SHADER,m.HIGH_FLOAT),xc=m.getShaderPrecisionFormat(m.FRAGMENT_SHADER,m.MEDIUM_FLOAT), +kc=function(){var a;return function(){if(void 0!==a)return a;a=[];if(da.get("WEBGL_compressed_texture_pvrtc")||da.get("WEBGL_compressed_texture_s3tc"))for(var b=m.getParameter(m.COMPRESSED_TEXTURE_FORMATS),c=0;c<b.length;c++)a.push(b[c]);return a}}(),yc=0<uc.precision&&0<wc.precision,mc=0<vc.precision&&0<xc.precision;"highp"!==L||yc||(mc?(L="mediump",THREE.warn("THREE.WebGLRenderer: highp not supported, using mediump.")):(L="lowp",THREE.warn("THREE.WebGLRenderer: highp and mediump not supported, using lowp."))); +"mediump"!==L||mc||(L="lowp",THREE.warn("THREE.WebGLRenderer: mediump not supported, using lowp."));var zc=new THREE.ShadowMapPlugin(this,ca,ba,qa),Ac=new THREE.SpritePlugin(this,Xa),Bc=new THREE.LensFlarePlugin(this,Ya);this.getContext=function(){return m};this.forceContextLoss=function(){da.get("WEBGL_lose_context").loseContext()};this.supportsVertexTextures=function(){return Vb};this.supportsFloatTextures=function(){return da.get("OES_texture_float")};this.supportsHalfFloatTextures=function(){return da.get("OES_texture_half_float")}; +this.supportsStandardDerivatives=function(){return da.get("OES_standard_derivatives")};this.supportsCompressedTextureS3TC=function(){return da.get("WEBGL_compressed_texture_s3tc")};this.supportsCompressedTexturePVRTC=function(){return da.get("WEBGL_compressed_texture_pvrtc")};this.supportsBlendMinMax=function(){return da.get("EXT_blend_minmax")};this.getMaxAnisotropy=function(){var a;return function(){if(void 0!==a)return a;var b=da.get("EXT_texture_filter_anisotropic");return a=null!==b?m.getParameter(b.MAX_TEXTURE_MAX_ANISOTROPY_EXT): +0}}();this.getPrecision=function(){return L};this.getPixelRatio=function(){return H};this.setPixelRatio=function(a){H=a};this.setSize=function(a,b,c){U.width=a*H;U.height=b*H;!1!==c&&(U.style.width=a+"px",U.style.height=b+"px");this.setViewport(0,0,a,b)};this.setViewport=function(a,b,c,d){ib=a*H;bb=b*H;pb=c*H;qb=d*H;m.viewport(ib,bb,pb,qb)};this.setScissor=function(a,b,c,d){m.scissor(a*H,b*H,c*H,d*H)};this.enableScissorTest=function(a){a?m.enable(m.SCISSOR_TEST):m.disable(m.SCISSOR_TEST)};this.getClearColor= +function(){return ha};this.setClearColor=function(a,b){ha.set(a);O=void 0!==b?b:1;rb(ha.r,ha.g,ha.b,O)};this.getClearAlpha=function(){return O};this.setClearAlpha=function(a){O=a;rb(ha.r,ha.g,ha.b,O)};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=m.COLOR_BUFFER_BIT;if(void 0===b||b)d|=m.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=m.STENCIL_BUFFER_BIT;m.clear(d)};this.clearColor=function(){m.clear(m.COLOR_BUFFER_BIT)};this.clearDepth=function(){m.clear(m.DEPTH_BUFFER_BIT)};this.clearStencil=function(){m.clear(m.STENCIL_BUFFER_BIT)}; +this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.resetGLState=Zb;var wb=function(a){a.target.traverse(function(a){a.removeEventListener("remove",wb);if(a instanceof THREE.Mesh||a instanceof THREE.PointCloud||a instanceof THREE.Line)delete ba[a.id];else if(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)for(var b=qa,c=b.length-1;0<=c;c--)b[c].object===a&&b.splice(c,1);delete a.__webglInit;delete a._modelViewMatrix;delete a._normalMatrix;delete a.__webglActive})}, +jb=function(a){a=a.target;a.removeEventListener("dispose",jb);delete a.__webglInit;if(a instanceof THREE.BufferGeometry){for(var b in a.attributes){var c=a.attributes[b];void 0!==c.buffer&&(m.deleteBuffer(c.buffer),delete c.buffer)}B.info.memory.geometries--}else if(b=Ua[a.id],void 0!==b){for(var c=0,d=b.length;c<d;c++){var e=b[c];if(void 0!==e.numMorphTargets){for(var f=0,g=e.numMorphTargets;f<g;f++)m.deleteBuffer(e.__webglMorphTargetsBuffers[f]);delete e.__webglMorphTargetsBuffers}if(void 0!==e.numMorphNormals){f= +0;for(g=e.numMorphNormals;f<g;f++)m.deleteBuffer(e.__webglMorphNormalsBuffers[f]);delete e.__webglMorphNormalsBuffers}nc(e)}delete Ua[a.id]}else nc(a);ta=""},Pb=function(a){a=a.target;a.removeEventListener("dispose",Pb);a.image&&a.image.__webglTextureCube?(m.deleteTexture(a.image.__webglTextureCube),delete a.image.__webglTextureCube):void 0!==a.__webglInit&&(m.deleteTexture(a.__webglTexture),delete a.__webglTexture,delete a.__webglInit);B.info.memory.textures--},oc=function(a){a=a.target;a.removeEventListener("dispose", +oc);if(a&&void 0!==a.__webglTexture){m.deleteTexture(a.__webglTexture);delete a.__webglTexture;if(a instanceof THREE.WebGLRenderTargetCube)for(var b=0;6>b;b++)m.deleteFramebuffer(a.__webglFramebuffer[b]),m.deleteRenderbuffer(a.__webglRenderbuffer[b]);else m.deleteFramebuffer(a.__webglFramebuffer),m.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}B.info.memory.textures--},ic=function(a){a=a.target;a.removeEventListener("dispose",ic);hc(a)},nc=function(a){for(var b= +"__webglVertexBuffer __webglNormalBuffer __webglTangentBuffer __webglColorBuffer __webglUVBuffer __webglUV2Buffer __webglSkinIndicesBuffer __webglSkinWeightsBuffer __webglFaceBuffer __webglLineBuffer __webglLineDistanceBuffer".split(" "),c=0,d=b.length;c<d;c++){var e=b[c];void 0!==a[e]&&(m.deleteBuffer(a[e]),delete a[e])}if(void 0!==a.__webglCustomAttributesList){for(e in a.__webglCustomAttributesList)m.deleteBuffer(a.__webglCustomAttributesList[e].buffer);delete a.__webglCustomAttributesList}B.info.memory.geometries--}, +hc=function(a){var b=a.program.program;if(void 0!==b){a.program=void 0;var c,d,e=!1;a=0;for(c=Pa.length;a<c;a++)if(d=Pa[a],d.program===b){d.usedTimes--;0===d.usedTimes&&(e=!0);break}if(!0===e){e=[];a=0;for(c=Pa.length;a<c;a++)d=Pa[a],d.program!==b&&e.push(d);Pa=e;m.deleteProgram(b);B.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){W.initAttributes();a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=m.createBuffer());a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer= +m.createBuffer());a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=m.createBuffer());a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=m.createBuffer());a.hasPositions&&(m.bindBuffer(m.ARRAY_BUFFER,a.__webglVertexBuffer),m.bufferData(m.ARRAY_BUFFER,a.positionArray,m.DYNAMIC_DRAW),W.enableAttribute(b.attributes.position),m.vertexAttribPointer(b.attributes.position,3,m.FLOAT,!1,0,0));if(a.hasNormals){m.bindBuffer(m.ARRAY_BUFFER,a.__webglNormalBuffer);if(!1===c instanceof THREE.MeshPhongMaterial&& +c.shading===THREE.FlatShading){var d,e,f,g,h,k,n,l,p,q,r,s=3*a.count;for(r=0;r<s;r+=9)q=a.normalArray,d=q[r],e=q[r+1],f=q[r+2],g=q[r+3],k=q[r+4],l=q[r+5],h=q[r+6],n=q[r+7],p=q[r+8],d=(d+g+h)/3,e=(e+k+n)/3,f=(f+l+p)/3,q[r]=d,q[r+1]=e,q[r+2]=f,q[r+3]=d,q[r+4]=e,q[r+5]=f,q[r+6]=d,q[r+7]=e,q[r+8]=f}m.bufferData(m.ARRAY_BUFFER,a.normalArray,m.DYNAMIC_DRAW);W.enableAttribute(b.attributes.normal);m.vertexAttribPointer(b.attributes.normal,3,m.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(m.bindBuffer(m.ARRAY_BUFFER,a.__webglUvBuffer), +m.bufferData(m.ARRAY_BUFFER,a.uvArray,m.DYNAMIC_DRAW),W.enableAttribute(b.attributes.uv),m.vertexAttribPointer(b.attributes.uv,2,m.FLOAT,!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(m.bindBuffer(m.ARRAY_BUFFER,a.__webglColorBuffer),m.bufferData(m.ARRAY_BUFFER,a.colorArray,m.DYNAMIC_DRAW),W.enableAttribute(b.attributes.color),m.vertexAttribPointer(b.attributes.color,3,m.FLOAT,!1,0,0));W.disableUnusedAttributes();m.drawArrays(m.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a, +b,c,e,f,g){if(!1!==e.visible)if(t(g),a=v(a,b,c,e,g),b=!1,c="direct_"+f.id+"_"+a.id+"_"+(e.wireframe?1:0),c!==ta&&(ta=c,b=!0),b&&W.initAttributes(),g instanceof THREE.Mesh){g=!0===e.wireframe?m.LINES:m.TRIANGLES;var h=f.attributes.index;if(h){var k,n;h.array instanceof Uint32Array&&da.get("OES_element_index_uint")?(k=m.UNSIGNED_INT,n=4):(k=m.UNSIGNED_SHORT,n=2);c=f.offsets;if(0===c.length)b&&(d(e,a,f,0),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,h.buffer)),m.drawElements(g,h.array.length,k,0),B.info.render.calls++, +B.info.render.vertices+=h.array.length,B.info.render.faces+=h.array.length/3;else{b=!0;for(var l=0,p=c.length;l<p;l++){var q=c[l].index;b&&(d(e,a,f,q),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,h.buffer));m.drawElements(g,c[l].count,k,c[l].start*n);B.info.render.calls++;B.info.render.vertices+=c[l].count;B.info.render.faces+=c[l].count/3}}}else b&&d(e,a,f,0),e=f.attributes.position,m.drawArrays(g,0,e.array.length/e.itemSize),B.info.render.calls++,B.info.render.vertices+=e.array.length/e.itemSize,B.info.render.faces+= +e.array.length/(3*e.itemSize)}else if(g instanceof THREE.PointCloud)if(g=m.POINTS,h=f.attributes.index)if(h.array instanceof Uint32Array&&da.get("OES_element_index_uint")?(k=m.UNSIGNED_INT,n=4):(k=m.UNSIGNED_SHORT,n=2),c=f.offsets,0===c.length)b&&(d(e,a,f,0),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,h.buffer)),m.drawElements(g,h.array.length,k,0),B.info.render.calls++,B.info.render.points+=h.array.length;else for(1<c.length&&(b=!0),l=0,p=c.length;l<p;l++)q=c[l].index,b&&(d(e,a,f,q),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER, +h.buffer)),m.drawElements(g,c[l].count,k,c[l].start*n),B.info.render.calls++,B.info.render.points+=c[l].count;else if(b&&d(e,a,f,0),e=f.attributes.position,c=f.offsets,0===c.length)m.drawArrays(g,0,e.array.length/3),B.info.render.calls++,B.info.render.points+=e.array.length/3;else for(l=0,p=c.length;l<p;l++)m.drawArrays(g,c[l].index,c[l].count),B.info.render.calls++,B.info.render.points+=c[l].count;else if(g instanceof THREE.Line)if(g=g.mode===THREE.LineStrip?m.LINE_STRIP:m.LINES,W.setLineWidth(e.linewidth* +H),h=f.attributes.index)if(h.array instanceof Uint32Array?(k=m.UNSIGNED_INT,n=4):(k=m.UNSIGNED_SHORT,n=2),c=f.offsets,0===c.length)b&&(d(e,a,f,0),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,h.buffer)),m.drawElements(g,h.array.length,k,0),B.info.render.calls++,B.info.render.vertices+=h.array.length;else for(1<c.length&&(b=!0),l=0,p=c.length;l<p;l++)q=c[l].index,b&&(d(e,a,f,q),m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,h.buffer)),m.drawElements(g,c[l].count,k,c[l].start*n),B.info.render.calls++,B.info.render.vertices+= +c[l].count;else if(b&&d(e,a,f,0),e=f.attributes.position,c=f.offsets,0===c.length)m.drawArrays(g,0,e.array.length/3),B.info.render.calls++,B.info.render.vertices+=e.array.length/3;else for(l=0,p=c.length;l<p;l++)m.drawArrays(g,c[l].index,c[l].count),B.info.render.calls++,B.info.render.vertices+=c[l].count};this.renderBuffer=function(a,b,c,d,e,f){if(!1!==d.visible){t(f);c=v(a,b,c,d,f);b=c.attributes;a=!1;c=e.id+"_"+c.id+"_"+(d.wireframe?1:0);c!==ta&&(ta=c,a=!0);a&&W.initAttributes();if(!d.morphTargets&& +0<=b.position)a&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglVertexBuffer),W.enableAttribute(b.position),m.vertexAttribPointer(b.position,3,m.FLOAT,!1,0,0));else if(f.morphTargetBase){c=d.program.attributes;-1!==f.morphTargetBase&&0<=c.position?(m.bindBuffer(m.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]),W.enableAttribute(c.position),m.vertexAttribPointer(c.position,3,m.FLOAT,!1,0,0)):0<=c.position&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglVertexBuffer),W.enableAttribute(c.position),m.vertexAttribPointer(c.position, +3,m.FLOAT,!1,0,0));if(f.morphTargetForcedOrder.length)for(var h=0,k=f.morphTargetForcedOrder,n=f.morphTargetInfluences,l;h<d.numSupportedMorphTargets&&h<k.length;)l=c["morphTarget"+h],0<=l&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[k[h]]),W.enableAttribute(l),m.vertexAttribPointer(l,3,m.FLOAT,!1,0,0)),l=c["morphNormal"+h],0<=l&&d.morphNormals&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[k[h]]),W.enableAttribute(l),m.vertexAttribPointer(l,3,m.FLOAT,!1,0,0)),f.__webglMorphTargetInfluences[h]= +n[k[h]],h++;else{k=[];n=f.morphTargetInfluences;h=f.geometry.morphTargets;n.length>h.length&&(console.warn("THREE.WebGLRenderer: Influences array is bigger than morphTargets array."),n.length=h.length);h=0;for(l=n.length;h<l;h++)k.push([n[h],h]);k.length>d.numSupportedMorphTargets?(k.sort(g),k.length=d.numSupportedMorphTargets):k.length>d.numSupportedMorphNormals?k.sort(g):0===k.length&&k.push([0,0]);for(var h=0,p=d.numSupportedMorphTargets;h<p;h++)if(k[h]){var q=k[h][1];l=c["morphTarget"+h];0<=l&& +(m.bindBuffer(m.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[q]),W.enableAttribute(l),m.vertexAttribPointer(l,3,m.FLOAT,!1,0,0));l=c["morphNormal"+h];0<=l&&d.morphNormals&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[q]),W.enableAttribute(l),m.vertexAttribPointer(l,3,m.FLOAT,!1,0,0));f.__webglMorphTargetInfluences[h]=n[q]}else f.__webglMorphTargetInfluences[h]=0}null!==d.program.uniforms.morphTargetInfluences&&m.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList)for(c= +0,n=e.__webglCustomAttributesList.length;c<n;c++)k=e.__webglCustomAttributesList[c],0<=b[k.buffer.belongsToAttribute]&&(m.bindBuffer(m.ARRAY_BUFFER,k.buffer),W.enableAttribute(b[k.buffer.belongsToAttribute]),m.vertexAttribPointer(b[k.buffer.belongsToAttribute],k.size,m.FLOAT,!1,0,0));0<=b.color&&(0<f.geometry.colors.length||0<f.geometry.faces.length?(m.bindBuffer(m.ARRAY_BUFFER,e.__webglColorBuffer),W.enableAttribute(b.color),m.vertexAttribPointer(b.color,3,m.FLOAT,!1,0,0)):void 0!==d.defaultAttributeValues&& +m.vertexAttrib3fv(b.color,d.defaultAttributeValues.color));0<=b.normal&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglNormalBuffer),W.enableAttribute(b.normal),m.vertexAttribPointer(b.normal,3,m.FLOAT,!1,0,0));0<=b.tangent&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglTangentBuffer),W.enableAttribute(b.tangent),m.vertexAttribPointer(b.tangent,4,m.FLOAT,!1,0,0));0<=b.uv&&(f.geometry.faceVertexUvs[0]?(m.bindBuffer(m.ARRAY_BUFFER,e.__webglUVBuffer),W.enableAttribute(b.uv),m.vertexAttribPointer(b.uv,2,m.FLOAT,!1,0, +0)):void 0!==d.defaultAttributeValues&&m.vertexAttrib2fv(b.uv,d.defaultAttributeValues.uv));0<=b.uv2&&(f.geometry.faceVertexUvs[1]?(m.bindBuffer(m.ARRAY_BUFFER,e.__webglUV2Buffer),W.enableAttribute(b.uv2),m.vertexAttribPointer(b.uv2,2,m.FLOAT,!1,0,0)):void 0!==d.defaultAttributeValues&&m.vertexAttrib2fv(b.uv2,d.defaultAttributeValues.uv2));d.skinning&&0<=b.skinIndex&&0<=b.skinWeight&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglSkinIndicesBuffer),W.enableAttribute(b.skinIndex),m.vertexAttribPointer(b.skinIndex, +4,m.FLOAT,!1,0,0),m.bindBuffer(m.ARRAY_BUFFER,e.__webglSkinWeightsBuffer),W.enableAttribute(b.skinWeight),m.vertexAttribPointer(b.skinWeight,4,m.FLOAT,!1,0,0));0<=b.lineDistance&&(m.bindBuffer(m.ARRAY_BUFFER,e.__webglLineDistanceBuffer),W.enableAttribute(b.lineDistance),m.vertexAttribPointer(b.lineDistance,1,m.FLOAT,!1,0,0))}W.disableUnusedAttributes();f instanceof THREE.Mesh?(f=e.__typeArray===Uint32Array?m.UNSIGNED_INT:m.UNSIGNED_SHORT,d.wireframe?(W.setLineWidth(d.wireframeLinewidth*H),a&&m.bindBuffer(m.ELEMENT_ARRAY_BUFFER, +e.__webglLineBuffer),m.drawElements(m.LINES,e.__webglLineCount,f,0)):(a&&m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer),m.drawElements(m.TRIANGLES,e.__webglFaceCount,f,0)),B.info.render.calls++,B.info.render.vertices+=e.__webglFaceCount,B.info.render.faces+=e.__webglFaceCount/3):f instanceof THREE.Line?(f=f.mode===THREE.LineStrip?m.LINE_STRIP:m.LINES,W.setLineWidth(d.linewidth*H),m.drawArrays(f,0,e.__webglLineCount),B.info.render.calls++):f instanceof THREE.PointCloud&&(m.drawArrays(m.POINTS, +0,e.__webglParticleCount),B.info.render.calls++,B.info.render.points+=e.__webglParticleCount)}};this.render=function(a,b,c,d){if(!1===b instanceof THREE.Camera)THREE.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var g=a.fog;ta="";ub=-1;vb=null;Ob=!0;!0===a.autoUpdate&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();a.traverse(function(a){a instanceof THREE.SkinnedMesh&&a.skeleton.update()});b.matrixWorldInverse.getInverse(b.matrixWorld);db.multiplyMatrices(b.projectionMatrix, +b.matrixWorldInverse);cb.setFromMatrix(db);ca.length=0;Ka.length=0;Qa.length=0;Xa.length=0;Ya.length=0;h(a);!0===B.sortObjects&&(Ka.sort(e),Qa.sort(f));zc.render(a,b);B.info.render.calls=0;B.info.render.vertices=0;B.info.render.faces=0;B.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);d=0;for(var n=qa.length;d<n;d++){var m=qa[d],q=m.object;q.visible&&(w(q,b),p(m))}a.overrideMaterial?(d=a.overrideMaterial,u(d), +k(Ka,b,ca,g,d),k(Qa,b,ca,g,d),l(qa,"",b,ca,g,d)):(W.setBlending(THREE.NoBlending),k(Ka,b,ca,g,null),l(qa,"opaque",b,ca,g,null),k(Qa,b,ca,g,null),l(qa,"transparent",b,ca,g,null));Ac.render(a,b);Bc.render(a,b,Xb,fc);c&&c.generateMipmaps&&c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter&&F(c);W.setDepthTest(!0);W.setDepthWrite(!0);W.setColorWrite(!0)}};this.renderImmediateObject=function(a,b,c,d,e){var f=v(a,b,c,d,e);ta="";B.setMaterialFaces(d);e.immediateRenderCallback?e.immediateRenderCallback(f, +m,cb):e.render(function(a){B.renderBufferImmediate(a,f,d)})};var Ua={},Qb=0,pc={MeshDepthMaterial:"depth",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointCloudMaterial:"particle_basic"};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?m.disable(m.CULL_FACE):(b===THREE.FrontFaceDirectionCW?m.frontFace(m.CW):m.frontFace(m.CCW),a===THREE.CullFaceBack?m.cullFace(m.BACK):a=== +THREE.CullFaceFront?m.cullFace(m.FRONT):m.cullFace(m.FRONT_AND_BACK),m.enable(m.CULL_FACE))};this.setMaterialFaces=function(a){W.setDoubleSided(a.side===THREE.DoubleSide);W.setFlipSided(a.side===THREE.BackSide)};this.uploadTexture=function(a){void 0===a.__webglInit&&(a.__webglInit=!0,a.addEventListener("dispose",Pb),a.__webglTexture=m.createTexture(),B.info.memory.textures++);m.bindTexture(m.TEXTURE_2D,a.__webglTexture);m.pixelStorei(m.UNPACK_FLIP_Y_WEBGL,a.flipY);m.pixelStorei(m.UNPACK_PREMULTIPLY_ALPHA_WEBGL, +a.premultiplyAlpha);m.pixelStorei(m.UNPACK_ALIGNMENT,a.unpackAlignment);a.image=E(a.image,tc);var b=a.image,c=THREE.Math.isPowerOfTwo(b.width)&&THREE.Math.isPowerOfTwo(b.height),d=I(a.format),e=I(a.type);A(m.TEXTURE_2D,a,c);var f=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<f.length&&c){for(var g=0,h=f.length;g<h;g++)b=f[g],m.texImage2D(m.TEXTURE_2D,g,d,b.width,b.height,0,d,e,b.data);a.generateMipmaps=!1}else m.texImage2D(m.TEXTURE_2D,0,d,b.width,b.height,0,d,e,b.data);else if(a instanceof THREE.CompressedTexture)for(g= +0,h=f.length;g<h;g++)b=f[g],a.format!==THREE.RGBAFormat&&a.format!==THREE.RGBFormat?-1<kc().indexOf(d)?m.compressedTexImage2D(m.TEXTURE_2D,g,d,b.width,b.height,0,b.data):THREE.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):m.texImage2D(m.TEXTURE_2D,g,d,b.width,b.height,0,d,e,b.data);else if(0<f.length&&c){g=0;for(h=f.length;g<h;g++)b=f[g],m.texImage2D(m.TEXTURE_2D,g,d,d,e,b);a.generateMipmaps=!1}else m.texImage2D(m.TEXTURE_2D,0,d,d,e,a.image); +a.generateMipmaps&&c&&m.generateMipmap(m.TEXTURE_2D);a.needsUpdate=!1;if(a.onUpdate)a.onUpdate()};this.setTexture=function(a,b){m.activeTexture(m.TEXTURE0+b);a.needsUpdate?B.uploadTexture(a):m.bindTexture(m.TEXTURE_2D,a.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&void 0===a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",oc);a.__webglTexture=m.createTexture(); +B.info.memory.textures++;var c=THREE.Math.isPowerOfTwo(a.width)&&THREE.Math.isPowerOfTwo(a.height),d=I(a.format),e=I(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];m.bindTexture(m.TEXTURE_CUBE_MAP,a.__webglTexture);A(m.TEXTURE_CUBE_MAP,a,c);for(var f=0;6>f;f++){a.__webglFramebuffer[f]=m.createFramebuffer();a.__webglRenderbuffer[f]=m.createRenderbuffer();m.texImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=m.TEXTURE_CUBE_MAP_POSITIVE_X+f;m.bindFramebuffer(m.FRAMEBUFFER, +a.__webglFramebuffer[f]);m.framebufferTexture2D(m.FRAMEBUFFER,m.COLOR_ATTACHMENT0,h,g.__webglTexture,0);G(a.__webglRenderbuffer[f],a)}c&&m.generateMipmap(m.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=m.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:m.createRenderbuffer(),m.bindTexture(m.TEXTURE_2D,a.__webglTexture),A(m.TEXTURE_2D,a,c),m.texImage2D(m.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=m.TEXTURE_2D,m.bindFramebuffer(m.FRAMEBUFFER,a.__webglFramebuffer), +m.framebufferTexture2D(m.FRAMEBUFFER,m.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_ATTACHMENT,m.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_STENCIL_ATTACHMENT,m.RENDERBUFFER,a.__webglRenderbuffer):G(a.__webglRenderbuffer,a),c&&m.generateMipmap(m.TEXTURE_2D);b?m.bindTexture(m.TEXTURE_CUBE_MAP,null):m.bindTexture(m.TEXTURE_2D,null);m.bindRenderbuffer(m.RENDERBUFFER, +null);m.bindFramebuffer(m.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=pb,a=qb,d=ib,e=bb);b!==ab&&(m.bindFramebuffer(m.FRAMEBUFFER,b),m.viewport(d,e,c,a),ab=b);Xb=c;fc=a};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!(a instanceof THREE.WebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else if(a.__webglFramebuffer)if(a.format!==THREE.RGBAFormat)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format."); +else{var g=!1;a.__webglFramebuffer!==ab&&(m.bindFramebuffer(m.FRAMEBUFFER,a.__webglFramebuffer),g=!0);m.checkFramebufferStatus(m.FRAMEBUFFER)===m.FRAMEBUFFER_COMPLETE?m.readPixels(b,c,d,e,m.RGBA,m.UNSIGNED_BYTE,f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.");g&&m.bindFramebuffer(m.FRAMEBUFFER,ab)}};this.initMaterial=function(){THREE.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){THREE.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")}; +this.addPostPlugin=function(){THREE.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){THREE.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}}; +THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: +THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=void 0!==c.shareDepthFrom?c.shareDepthFrom:null}; +THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){this.width=a;this.height=b},clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps; +a.shareDepthFrom=this.shareDepthFrom;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube; +THREE.WebGLExtensions=function(a){var b={};this.get=function(c){if(void 0!==b[c])return b[c];var d;switch(c){case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case "WEBGL_compressed_texture_s3tc":d=a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"); +break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;default:d=a.getExtension(c)}null===d&&THREE.warn("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}}; +THREE.WebGLProgram=function(){var a=0;return function(b,c,d,e){var f=b.context,g=d.defines,h=d.__webglShader.uniforms,k=d.attributes,l=d.__webglShader.vertexShader,p=d.__webglShader.fragmentShader,q=d.index0AttributeName;void 0===q&&!0===e.morphTargets&&(q="position");var n="SHADOWMAP_TYPE_BASIC";e.shadowMapType===THREE.PCFShadowMap?n="SHADOWMAP_TYPE_PCF":e.shadowMapType===THREE.PCFSoftShadowMap&&(n="SHADOWMAP_TYPE_PCF_SOFT");var t="ENVMAP_TYPE_CUBE",r="ENVMAP_MODE_REFLECTION",s="ENVMAP_BLENDING_MULTIPLY"; +if(e.envMap){switch(d.envMap.mapping){case THREE.CubeReflectionMapping:case THREE.CubeRefractionMapping:t="ENVMAP_TYPE_CUBE";break;case THREE.EquirectangularReflectionMapping:case THREE.EquirectangularRefractionMapping:t="ENVMAP_TYPE_EQUIREC";break;case THREE.SphericalReflectionMapping:t="ENVMAP_TYPE_SPHERE"}switch(d.envMap.mapping){case THREE.CubeRefractionMapping:case THREE.EquirectangularRefractionMapping:r="ENVMAP_MODE_REFRACTION"}switch(d.combine){case THREE.MultiplyOperation:s="ENVMAP_BLENDING_MULTIPLY"; +break;case THREE.MixOperation:s="ENVMAP_BLENDING_MIX";break;case THREE.AddOperation:s="ENVMAP_BLENDING_ADD"}}var u=0<b.gammaFactor?b.gammaFactor:1,v,x;v=[];for(var D in g)x=g[D],!1!==x&&(x="#define "+D+" "+x,v.push(x));v=v.join("\n");g=f.createProgram();d instanceof THREE.RawShaderMaterial?b=d="":(d=["precision "+e.precision+" float;","precision "+e.precision+" int;",v,e.supportsVertexTextures?"#define VERTEX_TEXTURES":"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT": +"","#define GAMMA_FACTOR "+u,"#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,"#define MAX_BONES "+e.maxBones,e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+r:"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP": +"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.flatShading?"#define FLAT_SHADED":"",e.skinning?"#define USE_SKINNING":"",e.useVertexTexture?"#define BONE_TEXTURE":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals?"#define USE_MORPHNORMALS":"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+n:"",e.shadowMapDebug? +"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.sizeAttenuation?"#define USE_SIZEATTENUATION":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;\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\n\tattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\n\tattribute vec3 morphTarget0;\n\tattribute vec3 morphTarget1;\n\tattribute vec3 morphTarget2;\n\tattribute vec3 morphTarget3;\n\t#ifdef USE_MORPHNORMALS\n\t\tattribute vec3 morphNormal0;\n\t\tattribute vec3 morphNormal1;\n\t\tattribute vec3 morphNormal2;\n\t\tattribute vec3 morphNormal3;\n\t#else\n\t\tattribute vec3 morphTarget4;\n\t\tattribute vec3 morphTarget5;\n\t\tattribute vec3 morphTarget6;\n\t\tattribute vec3 morphTarget7;\n\t#endif\n#endif\n#ifdef USE_SKINNING\n\tattribute vec4 skinIndex;\n\tattribute vec4 skinWeight;\n#endif\n"].join("\n"), +b=["precision "+e.precision+" float;","precision "+e.precision+" int;",e.bumpMap||e.normalMap||e.flatShading?"#extension GL_OES_standard_derivatives : enable":"",v,"#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,e.alphaTest?"#define ALPHATEST "+e.alphaTest:"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+ +u,e.useFog&&e.fog?"#define USE_FOG":"",e.useFog&&e.fogExp?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+t:"",e.envMap?"#define "+r:"",e.envMap?"#define "+s:"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.flatShading?"#define FLAT_SHADED":"",e.metal?"#define METAL": +"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+n:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n"));l=new THREE.WebGLShader(f,f.VERTEX_SHADER,d+l);p=new THREE.WebGLShader(f,f.FRAGMENT_SHADER, +b+p);f.attachShader(g,l);f.attachShader(g,p);void 0!==q&&f.bindAttribLocation(g,0,q);f.linkProgram(g);q=f.getProgramInfoLog(g);!1===f.getProgramParameter(g,f.LINK_STATUS)&&THREE.error("THREE.WebGLProgram: shader error: "+f.getError(),"gl.VALIDATE_STATUS",f.getProgramParameter(g,f.VALIDATE_STATUS),"gl.getPRogramInfoLog",q);""!==q&&THREE.warn("THREE.WebGLProgram: gl.getProgramInfoLog()"+q);f.deleteShader(l);f.deleteShader(p);q="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences bindMatrix bindMatrixInverse".split(" "); +e.useVertexTexture?(q.push("boneTexture"),q.push("boneTextureWidth"),q.push("boneTextureHeight")):q.push("boneGlobalMatrices");e.logarithmicDepthBuffer&&q.push("logDepthBufFC");for(var w in h)q.push(w);h=q;w={};q=0;for(b=h.length;q<b;q++)n=h[q],w[n]=f.getUniformLocation(g,n);this.uniforms=w;q="position normal uv uv2 tangent color skinIndex skinWeight lineDistance".split(" ");for(h=0;h<e.maxMorphTargets;h++)q.push("morphTarget"+h);for(h=0;h<e.maxMorphNormals;h++)q.push("morphNormal"+h);for(var y in k)q.push(y); +e=q;k={};y=0;for(h=e.length;y<h;y++)w=e[y],k[w]=f.getAttribLocation(g,w);this.attributes=k;this.attributesKeys=Object.keys(this.attributes);this.id=a++;this.code=c;this.usedTimes=1;this.program=g;this.vertexShader=l;this.fragmentShader=p;return this}}(); +THREE.WebGLShader=function(){var a=function(a){a=a.split("\n");for(var c=0;c<a.length;c++)a[c]=c+1+": "+a[c];return a.join("\n")};return function(b,c,d){c=b.createShader(c);b.shaderSource(c,d);b.compileShader(c);!1===b.getShaderParameter(c,b.COMPILE_STATUS)&&THREE.error("THREE.WebGLShader: Shader couldn't compile.");""!==b.getShaderInfoLog(c)&&THREE.warn("THREE.WebGLShader: gl.getShaderInfoLog()",b.getShaderInfoLog(c),a(d));return c}}(); +THREE.WebGLState=function(a,b){var c=new Uint8Array(16),d=new Uint8Array(16),e=null,f=null,g=null,h=null,k=null,l=null,p=null,q=null,n=null,t=null,r=null,s=null,u=null,v=null,x=null,D=null;this.initAttributes=function(){for(var a=0,b=c.length;a<b;a++)c[a]=0};this.enableAttribute=function(b){c[b]=1;0===d[b]&&(a.enableVertexAttribArray(b),d[b]=1)};this.disableUnusedAttributes=function(){for(var b=0,e=d.length;b<e;b++)d[b]!==c[b]&&(a.disableVertexAttribArray(b),d[b]=0)};this.setBlending=function(c,d, +n,q,r,s,t){c!==e&&(c===THREE.NoBlending?a.disable(a.BLEND):c===THREE.AdditiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.SRC_ALPHA,a.ONE)):c===THREE.SubtractiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.ONE_MINUS_SRC_COLOR)):c===THREE.MultiplyBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.SRC_COLOR)):c===THREE.CustomBlending?a.enable(a.BLEND):(a.enable(a.BLEND),a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD), +a.blendFuncSeparate(a.SRC_ALPHA,a.ONE_MINUS_SRC_ALPHA,a.ONE,a.ONE_MINUS_SRC_ALPHA)),e=c);if(c===THREE.CustomBlending){r=r||d;s=s||n;t=t||q;if(d!==f||r!==k)a.blendEquationSeparate(b(d),b(r)),f=d,k=r;if(n!==g||q!==h||s!==l||t!==p)a.blendFuncSeparate(b(n),b(q),b(s),b(t)),g=n,h=q,l=s,p=t}else p=l=k=h=g=f=null};this.setDepthTest=function(b){q!==b&&(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST),q=b)};this.setDepthWrite=function(b){n!==b&&(a.depthMask(b),n=b)};this.setColorWrite=function(b){t!==b&&(a.colorMask(b, +b,b,b),t=b)};this.setDoubleSided=function(b){r!==b&&(b?a.disable(a.CULL_FACE):a.enable(a.CULL_FACE),r=b)};this.setFlipSided=function(b){s!==b&&(b?a.frontFace(a.CW):a.frontFace(a.CCW),s=b)};this.setLineWidth=function(b){b!==u&&(a.lineWidth(b),u=b)};this.setPolygonOffset=function(b,c,d){v!==b&&(b?a.enable(a.POLYGON_OFFSET_FILL):a.disable(a.POLYGON_OFFSET_FILL),v=b);!b||x===c&&D===d||(a.polygonOffset(c,d),x=c,D=d)};this.reset=function(){for(var a=0;a<d.length;a++)d[a]=0;s=r=t=n=q=e=null}}; +THREE.LensFlarePlugin=function(a,b){var c,d,e,f,g,h,k,l,p,q,n=a.context,t,r,s,u,v,x;this.render=function(D,w,y,A){if(0!==b.length){D=new THREE.Vector3;var E=A/y,G=.5*y,F=.5*A,z=16/A,I=new THREE.Vector2(z*E,z),U=new THREE.Vector3(1,1,0),M=new THREE.Vector2(1,1);if(void 0===s){var z=new Float32Array([-1,-1,0,0,1,-1,1,0,1,1,1,1,-1,1,0,1]),H=new Uint16Array([0,1,2,0,2,3]);t=n.createBuffer();r=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,t);n.bufferData(n.ARRAY_BUFFER,z,n.STATIC_DRAW);n.bindBuffer(n.ELEMENT_ARRAY_BUFFER, +r);n.bufferData(n.ELEMENT_ARRAY_BUFFER,H,n.STATIC_DRAW);v=n.createTexture();x=n.createTexture();n.bindTexture(n.TEXTURE_2D,v);n.texImage2D(n.TEXTURE_2D,0,n.RGB,16,16,0,n.RGB,n.UNSIGNED_BYTE,null);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST);n.bindTexture(n.TEXTURE_2D,x);n.texImage2D(n.TEXTURE_2D,0, +n.RGBA,16,16,0,n.RGBA,n.UNSIGNED_BYTE,null);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST);n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST);var z=(u=0<n.getParameter(n.MAX_VERTEX_TEXTURE_IMAGE_UNITS))?{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility = visibility.r / 9.0;\nvVisibility *= 1.0 - visibility.g / 9.0;\nvVisibility *= visibility.b / 9.0;\nvVisibility *= 1.0 - visibility.a / 9.0;\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", +fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", +fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}, +H=n.createProgram(),L=n.createShader(n.FRAGMENT_SHADER),P=n.createShader(n.VERTEX_SHADER),N="precision "+a.getPrecision()+" float;\n";n.shaderSource(L,N+z.fragmentShader);n.shaderSource(P,N+z.vertexShader);n.compileShader(L);n.compileShader(P);n.attachShader(H,L);n.attachShader(H,P);n.linkProgram(H);s=H;p=n.getAttribLocation(s,"position");q=n.getAttribLocation(s,"uv");c=n.getUniformLocation(s,"renderType");d=n.getUniformLocation(s,"map");e=n.getUniformLocation(s,"occlusionMap");f=n.getUniformLocation(s, +"opacity");g=n.getUniformLocation(s,"color");h=n.getUniformLocation(s,"scale");k=n.getUniformLocation(s,"rotation");l=n.getUniformLocation(s,"screenPosition")}n.useProgram(s);n.enableVertexAttribArray(p);n.enableVertexAttribArray(q);n.uniform1i(e,0);n.uniform1i(d,1);n.bindBuffer(n.ARRAY_BUFFER,t);n.vertexAttribPointer(p,2,n.FLOAT,!1,16,0);n.vertexAttribPointer(q,2,n.FLOAT,!1,16,8);n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,r);n.disable(n.CULL_FACE);n.depthMask(!1);H=0;for(L=b.length;H<L;H++)if(z=16/A,I.set(z* +E,z),P=b[H],D.set(P.matrixWorld.elements[12],P.matrixWorld.elements[13],P.matrixWorld.elements[14]),D.applyMatrix4(w.matrixWorldInverse),D.applyProjection(w.projectionMatrix),U.copy(D),M.x=U.x*G+G,M.y=U.y*F+F,u||0<M.x&&M.x<y&&0<M.y&&M.y<A){n.activeTexture(n.TEXTURE1);n.bindTexture(n.TEXTURE_2D,v);n.copyTexImage2D(n.TEXTURE_2D,0,n.RGB,M.x-8,M.y-8,16,16,0);n.uniform1i(c,0);n.uniform2f(h,I.x,I.y);n.uniform3f(l,U.x,U.y,U.z);n.disable(n.BLEND);n.enable(n.DEPTH_TEST);n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT, +0);n.activeTexture(n.TEXTURE0);n.bindTexture(n.TEXTURE_2D,x);n.copyTexImage2D(n.TEXTURE_2D,0,n.RGBA,M.x-8,M.y-8,16,16,0);n.uniform1i(c,1);n.disable(n.DEPTH_TEST);n.activeTexture(n.TEXTURE1);n.bindTexture(n.TEXTURE_2D,v);n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT,0);P.positionScreen.copy(U);P.customUpdateCallback?P.customUpdateCallback(P):P.updateLensFlares();n.uniform1i(c,2);n.enable(n.BLEND);for(var N=0,R=P.lensFlares.length;N<R;N++){var V=P.lensFlares[N];.001<V.opacity&&.001<V.scale&&(U.x=V.x, +U.y=V.y,U.z=V.z,z=V.size*V.scale/A,I.x=z*E,I.y=z,n.uniform3f(l,U.x,U.y,U.z),n.uniform2f(h,I.x,I.y),n.uniform1f(k,V.rotation),n.uniform1f(f,V.opacity),n.uniform3f(g,V.color.r,V.color.g,V.color.b),a.state.setBlending(V.blending,V.blendEquation,V.blendSrc,V.blendDst),a.setTexture(V.texture,1),n.drawElements(n.TRIANGLES,6,n.UNSIGNED_SHORT,0))}}n.enable(n.CULL_FACE);n.enable(n.DEPTH_TEST);n.depthMask(!0);a.resetGLState()}}}; +THREE.ShadowMapPlugin=function(a,b,c,d){function e(a,b,d){if(b.visible){var f=c[b.id];if(f&&b.castShadow&&(!1===b.frustumCulled||!0===p.intersectsObject(b)))for(var g=0,h=f.length;g<h;g++){var k=f[g];b._modelViewMatrix.multiplyMatrices(d.matrixWorldInverse,b.matrixWorld);s.push(k)}g=0;for(h=b.children.length;g<h;g++)e(a,b.children[g],d)}}var f=a.context,g,h,k,l,p=new THREE.Frustum,q=new THREE.Matrix4,n=new THREE.Vector3,t=new THREE.Vector3,r=new THREE.Vector3,s=[],u=THREE.ShaderLib.depthRGBA,v=THREE.UniformsUtils.clone(u.uniforms); +g=new THREE.ShaderMaterial({uniforms:v,vertexShader:u.vertexShader,fragmentShader:u.fragmentShader});h=new THREE.ShaderMaterial({uniforms:v,vertexShader:u.vertexShader,fragmentShader:u.fragmentShader,morphTargets:!0});k=new THREE.ShaderMaterial({uniforms:v,vertexShader:u.vertexShader,fragmentShader:u.fragmentShader,skinning:!0});l=new THREE.ShaderMaterial({uniforms:v,vertexShader:u.vertexShader,fragmentShader:u.fragmentShader,morphTargets:!0,skinning:!0});g._shadowPass=!0;h._shadowPass=!0;k._shadowPass= +!0;l._shadowPass=!0;this.render=function(c,v){if(!1!==a.shadowMapEnabled){var u,y,A,E,G,F,z,I,U=[];E=0;f.clearColor(1,1,1,1);f.disable(f.BLEND);f.enable(f.CULL_FACE);f.frontFace(f.CCW);a.shadowMapCullFace===THREE.CullFaceFront?f.cullFace(f.FRONT):f.cullFace(f.BACK);a.state.setDepthTest(!0);u=0;for(y=b.length;u<y;u++)if(A=b[u],A.castShadow)if(A instanceof THREE.DirectionalLight&&A.shadowCascade)for(G=0;G<A.shadowCascadeCount;G++){var M;if(A.shadowCascadeArray[G])M=A.shadowCascadeArray[G];else{z=A; +var H=G;M=new THREE.DirectionalLight;M.isVirtual=!0;M.onlyShadow=!0;M.castShadow=!0;M.shadowCameraNear=z.shadowCameraNear;M.shadowCameraFar=z.shadowCameraFar;M.shadowCameraLeft=z.shadowCameraLeft;M.shadowCameraRight=z.shadowCameraRight;M.shadowCameraBottom=z.shadowCameraBottom;M.shadowCameraTop=z.shadowCameraTop;M.shadowCameraVisible=z.shadowCameraVisible;M.shadowDarkness=z.shadowDarkness;M.shadowBias=z.shadowCascadeBias[H];M.shadowMapWidth=z.shadowCascadeWidth[H];M.shadowMapHeight=z.shadowCascadeHeight[H]; +M.pointsWorld=[];M.pointsFrustum=[];I=M.pointsWorld;F=M.pointsFrustum;for(var L=0;8>L;L++)I[L]=new THREE.Vector3,F[L]=new THREE.Vector3;I=z.shadowCascadeNearZ[H];z=z.shadowCascadeFarZ[H];F[0].set(-1,-1,I);F[1].set(1,-1,I);F[2].set(-1,1,I);F[3].set(1,1,I);F[4].set(-1,-1,z);F[5].set(1,-1,z);F[6].set(-1,1,z);F[7].set(1,1,z);M.originalCamera=v;F=new THREE.Gyroscope;F.position.copy(A.shadowCascadeOffset);F.add(M);F.add(M.target);v.add(F);A.shadowCascadeArray[G]=M}H=A;I=G;z=H.shadowCascadeArray[I];z.position.copy(H.position); +z.target.position.copy(H.target.position);z.lookAt(z.target);z.shadowCameraVisible=H.shadowCameraVisible;z.shadowDarkness=H.shadowDarkness;z.shadowBias=H.shadowCascadeBias[I];F=H.shadowCascadeNearZ[I];H=H.shadowCascadeFarZ[I];z=z.pointsFrustum;z[0].z=F;z[1].z=F;z[2].z=F;z[3].z=F;z[4].z=H;z[5].z=H;z[6].z=H;z[7].z=H;U[E]=M;E++}else U[E]=A,E++;u=0;for(y=U.length;u<y;u++){A=U[u];A.shadowMap||(G=THREE.LinearFilter,a.shadowMapType===THREE.PCFSoftShadowMap&&(G=THREE.NearestFilter),A.shadowMap=new THREE.WebGLRenderTarget(A.shadowMapWidth, +A.shadowMapHeight,{minFilter:G,magFilter:G,format:THREE.RGBAFormat}),A.shadowMapSize=new THREE.Vector2(A.shadowMapWidth,A.shadowMapHeight),A.shadowMatrix=new THREE.Matrix4);if(!A.shadowCamera){if(A instanceof THREE.SpotLight)A.shadowCamera=new THREE.PerspectiveCamera(A.shadowCameraFov,A.shadowMapWidth/A.shadowMapHeight,A.shadowCameraNear,A.shadowCameraFar);else if(A instanceof THREE.DirectionalLight)A.shadowCamera=new THREE.OrthographicCamera(A.shadowCameraLeft,A.shadowCameraRight,A.shadowCameraTop, +A.shadowCameraBottom,A.shadowCameraNear,A.shadowCameraFar);else{THREE.error("THREE.ShadowMapPlugin: Unsupported light type for shadow",A);continue}c.add(A.shadowCamera);!0===c.autoUpdate&&c.updateMatrixWorld()}A.shadowCameraVisible&&!A.cameraHelper&&(A.cameraHelper=new THREE.CameraHelper(A.shadowCamera),c.add(A.cameraHelper));if(A.isVirtual&&M.originalCamera==v){G=v;E=A.shadowCamera;F=A.pointsFrustum;z=A.pointsWorld;n.set(Infinity,Infinity,Infinity);t.set(-Infinity,-Infinity,-Infinity);for(H=0;8> +H;H++)I=z[H],I.copy(F[H]),I.unproject(G),I.applyMatrix4(E.matrixWorldInverse),I.x<n.x&&(n.x=I.x),I.x>t.x&&(t.x=I.x),I.y<n.y&&(n.y=I.y),I.y>t.y&&(t.y=I.y),I.z<n.z&&(n.z=I.z),I.z>t.z&&(t.z=I.z);E.left=n.x;E.right=t.x;E.top=t.y;E.bottom=n.y;E.updateProjectionMatrix()}E=A.shadowMap;F=A.shadowMatrix;G=A.shadowCamera;G.position.setFromMatrixPosition(A.matrixWorld);r.setFromMatrixPosition(A.target.matrixWorld);G.lookAt(r);G.updateMatrixWorld();G.matrixWorldInverse.getInverse(G.matrixWorld);A.cameraHelper&& +(A.cameraHelper.visible=A.shadowCameraVisible);A.shadowCameraVisible&&A.cameraHelper.update();F.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);F.multiply(G.projectionMatrix);F.multiply(G.matrixWorldInverse);q.multiplyMatrices(G.projectionMatrix,G.matrixWorldInverse);p.setFromMatrix(q);a.setRenderTarget(E);a.clear();s.length=0;e(c,c,G);A=0;for(E=s.length;A<E;A++)z=s[A],F=z.object,z=z.buffer,H=F.material instanceof THREE.MeshFaceMaterial?F.material.materials[0]:F.material,I=void 0!==F.geometry.morphTargets&& +0<F.geometry.morphTargets.length&&H.morphTargets,L=F instanceof THREE.SkinnedMesh&&H.skinning,I=F.customDepthMaterial?F.customDepthMaterial:L?I?l:k:I?h:g,a.setMaterialFaces(H),z instanceof THREE.BufferGeometry?a.renderBufferDirect(G,b,null,I,z,F):a.renderBuffer(G,b,null,I,z,F);A=0;for(E=d.length;A<E;A++)z=d[A],F=z.object,F.visible&&F.castShadow&&(F._modelViewMatrix.multiplyMatrices(G.matrixWorldInverse,F.matrixWorld),a.renderImmediateObject(G,b,null,g,F))}u=a.getClearColor();y=a.getClearAlpha();f.clearColor(u.r, +u.g,u.b,y);f.enable(f.BLEND);a.shadowMapCullFace===THREE.CullFaceFront&&f.cullFace(f.BACK);a.resetGLState()}}}; +THREE.SpritePlugin=function(a,b){var c,d,e,f,g,h,k,l,p,q,n,t,r,s,u,v,x;function D(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var w=a.context,y,A,E,G,F=new THREE.Vector3,z=new THREE.Quaternion,I=new THREE.Vector3;this.render=function(U,M){if(0!==b.length){if(void 0===E){var H=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),L=new Uint16Array([0,1,2,0,2,3]);y=w.createBuffer();A=w.createBuffer();w.bindBuffer(w.ARRAY_BUFFER,y);w.bufferData(w.ARRAY_BUFFER,H,w.STATIC_DRAW);w.bindBuffer(w.ELEMENT_ARRAY_BUFFER, +A);w.bufferData(w.ELEMENT_ARRAY_BUFFER,L,w.STATIC_DRAW);var H=w.createProgram(),L=w.createShader(w.VERTEX_SHADER),P=w.createShader(w.FRAGMENT_SHADER);w.shaderSource(L,["precision "+a.getPrecision()+" float;","uniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = position * scale;\nvec2 rotatedPosition;\nrotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\nrotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\nvec4 finalPosition;\nfinalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition;\nfinalPosition = projectionMatrix * finalPosition;\ngl_Position = finalPosition;\n}"].join("\n")); +w.shaderSource(P,["precision "+a.getPrecision()+" float;","uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); +w.compileShader(L);w.compileShader(P);w.attachShader(H,L);w.attachShader(H,P);w.linkProgram(H);E=H;v=w.getAttribLocation(E,"position");x=w.getAttribLocation(E,"uv");c=w.getUniformLocation(E,"uvOffset");d=w.getUniformLocation(E,"uvScale");e=w.getUniformLocation(E,"rotation");f=w.getUniformLocation(E,"scale");g=w.getUniformLocation(E,"color");h=w.getUniformLocation(E,"map");k=w.getUniformLocation(E,"opacity");l=w.getUniformLocation(E,"modelViewMatrix");p=w.getUniformLocation(E,"projectionMatrix");q= +w.getUniformLocation(E,"fogType");n=w.getUniformLocation(E,"fogDensity");t=w.getUniformLocation(E,"fogNear");r=w.getUniformLocation(E,"fogFar");s=w.getUniformLocation(E,"fogColor");u=w.getUniformLocation(E,"alphaTest");H=document.createElement("canvas");H.width=8;H.height=8;L=H.getContext("2d");L.fillStyle="white";L.fillRect(0,0,8,8);G=new THREE.Texture(H);G.needsUpdate=!0}w.useProgram(E);w.enableVertexAttribArray(v);w.enableVertexAttribArray(x);w.disable(w.CULL_FACE);w.enable(w.BLEND);w.bindBuffer(w.ARRAY_BUFFER, +y);w.vertexAttribPointer(v,2,w.FLOAT,!1,16,0);w.vertexAttribPointer(x,2,w.FLOAT,!1,16,8);w.bindBuffer(w.ELEMENT_ARRAY_BUFFER,A);w.uniformMatrix4fv(p,!1,M.projectionMatrix.elements);w.activeTexture(w.TEXTURE0);w.uniform1i(h,0);L=H=0;(P=U.fog)?(w.uniform3f(s,P.color.r,P.color.g,P.color.b),P instanceof THREE.Fog?(w.uniform1f(t,P.near),w.uniform1f(r,P.far),w.uniform1i(q,1),L=H=1):P instanceof THREE.FogExp2&&(w.uniform1f(n,P.density),w.uniform1i(q,2),L=H=2)):(w.uniform1i(q,0),L=H=0);for(var P=0,N=b.length;P< +N;P++){var R=b[P];R._modelViewMatrix.multiplyMatrices(M.matrixWorldInverse,R.matrixWorld);R.z=-R._modelViewMatrix.elements[14]}b.sort(D);for(var V=[],P=0,N=b.length;P<N;P++){var R=b[P],J=R.material;w.uniform1f(u,J.alphaTest);w.uniformMatrix4fv(l,!1,R._modelViewMatrix.elements);R.matrixWorld.decompose(F,z,I);V[0]=I.x;V[1]=I.y;R=0;U.fog&&J.fog&&(R=L);H!==R&&(w.uniform1i(q,R),H=R);null!==J.map?(w.uniform2f(c,J.map.offset.x,J.map.offset.y),w.uniform2f(d,J.map.repeat.x,J.map.repeat.y)):(w.uniform2f(c, +0,0),w.uniform2f(d,1,1));w.uniform1f(k,J.opacity);w.uniform3f(g,J.color.r,J.color.g,J.color.b);w.uniform1f(e,J.rotation);w.uniform2fv(f,V);a.state.setBlending(J.blending,J.blendEquation,J.blendSrc,J.blendDst);a.state.setDepthTest(J.depthTest);a.state.setDepthWrite(J.depthWrite);J.map&&J.map.image&&J.map.image.width?a.setTexture(J.map,0):a.setTexture(G,0);w.drawElements(w.TRIANGLES,6,w.UNSIGNED_SHORT,0)}w.enable(w.CULL_FACE);a.resetGLState()}}}; +THREE.GeometryUtils={merge:function(a,b,c){THREE.warn("THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.");var d;b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,b=b.geometry);a.merge(b,d,c)},center:function(a){THREE.warn("THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.");return a.center()}}; +THREE.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.Texture(void 0,b);e.load(a,function(a){f.image=a;f.needsUpdate=!0;c&&c(f)},void 0,function(a){d&&d(a)});f.sourceFile=a;return f},loadTextureCube:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.CubeTexture([],b);f.flipY=!1;var g=0;b=function(b){e.load(a[b],function(a){f.images[b]=a;g+=1;6===g&&(f.needsUpdate=!0,c&& +c(f))},void 0,d)};for(var h=0,k=a.length;h<k;++h)b(h);return f},loadCompressedTexture:function(){THREE.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")},loadCompressedTextureCube:function(){THREE.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")},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|=1;var 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,k=g.createImageData(d,e),l=k.data,p=0;p<d;p++)for(var q=0;q<e;q++){var n=0>q-1?0:q-1,t=q+1>e-1?e-1:q+1,r=0>p-1?0:p-1,s=p+1>d-1?d-1:p+1,u=[],v=[0,0,h[4*(q*d+p)]/255*b];u.push([-1,0,h[4*(q*d+r)]/255*b]);u.push([-1,-1,h[4*(n*d+r)]/255*b]);u.push([0,-1,h[4*(n*d+p)]/255*b]);u.push([1,-1,h[4*(n*d+s)]/255*b]);u.push([1,0,h[4*(q*d+s)]/255*b]);u.push([1,1,h[4*(t*d+s)]/255*b]);u.push([0,1,h[4*(t*d+p)]/255* +b]);u.push([-1,1,h[4*(t*d+r)]/255*b]);n=[];r=u.length;for(t=0;t<r;t++){var s=u[t],x=u[(t+1)%r],s=[s[0]-v[0],s[1]-v[1],s[2]-v[2]],x=[x[0]-v[0],x[1]-v[1],x[2]-v[2]];n.push(c([s[1]*x[2]-s[2]*x[1],s[2]*x[0]-s[0]*x[2],s[0]*x[1]-s[1]*x[0]]))}u=[0,0,0];for(t=0;t<n.length;t++)u[0]+=n[t][0],u[1]+=n[t][1],u[2]+=n[t][2];u[0]/=n.length;u[1]/=n.length;u[2]/=n.length;v=4*(q*d+p);l[v]=(u[0]+1)/2*255|0;l[v+1]=(u[1]+1)/2*255|0;l[v+2]=255*u[2]|0;l[v+3]=255}g.putImageData(k,0,0);return f},generateDataTexture:function(a, +b,c){var d=a*b,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g);c=Math.floor(255*c.b);for(var h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}}; +THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}}; +THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){try{return this.faces[this.face][this.weight][this.style]}catch(a){throw"The font "+this.face+" with "+this.weight+" weight and "+this.style+" style is missing.";}},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]= +a},drawText:function(a){var b=this.getFace(),c=this.size/b.resolution,d=0,e=String(a).split(""),f=e.length,g=[];for(a=0;a<f;a++){var h=new THREE.Path,h=this.extractGlyphPoints(e[a],b,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(a,b,c,d,e){var f=[],g,h,k,l,p,q,n,t,r,s,u,v=b.glyphs[a]||b.glyphs["?"];if(v){if(v.o)for(b=v._cachedOutline||(v._cachedOutline=v.o.split(" ")),l=b.length,a=0;a<l;)switch(k=b[a++],k){case "m":k=b[a++]*c+d;p=b[a++]*c;e.moveTo(k,p); +break;case "l":k=b[a++]*c+d;p=b[a++]*c;e.lineTo(k,p);break;case "q":k=b[a++]*c+d;p=b[a++]*c;t=b[a++]*c+d;r=b[a++]*c;e.quadraticCurveTo(t,r,k,p);if(g=f[f.length-1])for(q=g.x,n=g.y,g=1,h=this.divisions;g<=h;g++){var x=g/h;THREE.Shape.Utils.b2(x,q,t,k);THREE.Shape.Utils.b2(x,n,r,p)}break;case "b":if(k=b[a++]*c+d,p=b[a++]*c,t=b[a++]*c+d,r=b[a++]*c,s=b[a++]*c+d,u=b[a++]*c,e.bezierCurveTo(t,r,s,u,k,p),g=f[f.length-1])for(q=g.x,n=g.y,g=1,h=this.divisions;g<=h;g++)x=g/h,THREE.Shape.Utils.b3(x,q,t,s,k),THREE.Shape.Utils.b3(x, +n,r,u,p)}return{offset:v.ha*c,path:e}}}}; +THREE.FontUtils.generateShapes=function(a,b){b=b||{};var c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",e=void 0!==b.weight?b.weight:"normal",f=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(a).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d}; +(function(a){var b=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e+=a[f].x*a[g].y-a[g].x*a[f].y;return.5*e};a.Triangulate=function(a,d){var e=a.length;if(3>e)return null;var f=[],g=[],h=[],k,l,p;if(0<b(a))for(l=0;l<e;l++)g[l]=l;else for(l=0;l<e;l++)g[l]=e-1-l;var q=2*e;for(l=e-1;2<e;){if(0>=q--){THREE.warn("THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()");break}k=l;e<=k&&(k=0);l=k+1;e<=l&&(l=0);p=l+1;e<=p&&(p=0);var n;a:{var t=n=void 0,r=void 0,s=void 0, +u=void 0,v=void 0,x=void 0,D=void 0,w=void 0,t=a[g[k]].x,r=a[g[k]].y,s=a[g[l]].x,u=a[g[l]].y,v=a[g[p]].x,x=a[g[p]].y;if(1E-10>(s-t)*(x-r)-(u-r)*(v-t))n=!1;else{var y=void 0,A=void 0,E=void 0,G=void 0,F=void 0,z=void 0,I=void 0,U=void 0,M=void 0,H=void 0,M=U=I=w=D=void 0,y=v-s,A=x-u,E=t-v,G=r-x,F=s-t,z=u-r;for(n=0;n<e;n++)if(D=a[g[n]].x,w=a[g[n]].y,!(D===t&&w===r||D===s&&w===u||D===v&&w===x)&&(I=D-t,U=w-r,M=D-s,H=w-u,D-=v,w-=x,M=y*H-A*M,I=F*U-z*I,U=E*w-G*D,-1E-10<=M&&-1E-10<=U&&-1E-10<=I)){n=!1;break a}n= +!0}}if(n){f.push([a[g[k]],a[g[l]],a[g[p]]]);h.push([g[k],g[l],g[p]]);k=l;for(p=l+1;p<e;k++,p++)g[k]=g[p];e--;q=2*e}}return d?h:f};a.Triangulate.area=b;return a})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};THREE.typeface_js=self._typeface_js; +THREE.Audio=function(a){THREE.Object3D.call(this);this.type="Audio";this.context=a.context;this.source=this.context.createBufferSource();this.source.onended=this.onEnded.bind(this);this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.panner=this.context.createPanner();this.panner.connect(this.gain);this.autoplay=!1;this.startTime=0;this.isPlaying=!1};THREE.Audio.prototype=Object.create(THREE.Object3D.prototype);THREE.Audio.prototype.constructor=THREE.Audio; +THREE.Audio.prototype.load=function(a){var b=this,c=new XMLHttpRequest;c.open("GET",a,!0);c.responseType="arraybuffer";c.onload=function(a){b.context.decodeAudioData(this.response,function(a){b.source.buffer=a;b.autoplay&&b.play()})};c.send();return this}; +THREE.Audio.prototype.play=function(){if(!0===this.isPlaying)THREE.warn("THREE.Audio: Audio is already playing.");else{var a=this.context.createBufferSource();a.buffer=this.source.buffer;a.loop=this.source.loop;a.onended=this.source.onended;a.connect(this.panner);a.start(0,this.startTime);this.isPlaying=!0;this.source=a}};THREE.Audio.prototype.pause=function(){this.source.stop();this.startTime=this.context.currentTime};THREE.Audio.prototype.stop=function(){this.source.stop();this.startTime=0}; +THREE.Audio.prototype.onEnded=function(){this.isPlaying=!1};THREE.Audio.prototype.setLoop=function(a){this.source.loop=a};THREE.Audio.prototype.setRefDistance=function(a){this.panner.refDistance=a};THREE.Audio.prototype.setRolloffFactor=function(a){this.panner.rolloffFactor=a};THREE.Audio.prototype.setVolume=function(a){this.gain.gain.value=a}; +THREE.Audio.prototype.updateMatrixWorld=function(){var a=new THREE.Vector3;return function(b){THREE.Object3D.prototype.updateMatrixWorld.call(this,b);a.setFromMatrixPosition(this.matrixWorld);this.panner.setPosition(a.x,a.y,a.z)}}();THREE.AudioListener=function(){THREE.Object3D.call(this);this.type="AudioListener";this.context=new (window.AudioContext||window.webkitAudioContext)};THREE.AudioListener.prototype=Object.create(THREE.Object3D.prototype);THREE.AudioListener.prototype.constructor=THREE.AudioListener; +THREE.AudioListener.prototype.updateMatrixWorld=function(){var a=new THREE.Vector3,b=new THREE.Quaternion,c=new THREE.Vector3,d=new THREE.Vector3,e=new THREE.Vector3,f=new THREE.Vector3;return function(g){THREE.Object3D.prototype.updateMatrixWorld.call(this,g);g=this.context.listener;var h=this.up;this.matrixWorld.decompose(a,b,c);d.set(0,0,-1).applyQuaternion(b);e.subVectors(a,f);g.setPosition(a.x,a.y,a.z);g.setOrientation(d.x,d.y,d.z,h.x,h.y,h.z);g.setVelocity(e.x,e.y,e.z);f.copy(a)}}(); +THREE.Curve=function(){};THREE.Curve.prototype.getPoint=function(a){THREE.warn("THREE.Curve: Warning, getPoint() not implemented!");return null};THREE.Curve.prototype.getPointAt=function(a){a=this.getUtoTmapping(a);return this.getPoint(a)};THREE.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPoint(b/a));return c};THREE.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPointAt(b/a));return c}; THREE.Curve.prototype.getLength=function(){var a=this.getLengths();return a[a.length-1]};THREE.Curve.prototype.getLengths=function(a){a||(a=this.__arcLengthDivisions?this.__arcLengthDivisions:200);if(this.cacheArcLengths&&this.cacheArcLengths.length==a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b=[],c,d=this.getPoint(0),e,f=0;b.push(0);for(e=1;e<=a;e++)c=this.getPoint(e/a),f+=c.distanceTo(d),b.push(f),d=c;return this.cacheArcLengths=b}; -THREE.Curve.prototype.updateArcLengths=function(){this.needsUpdate=!0;this.getLengths()};THREE.Curve.prototype.getUtoTmapping=function(a,b){var c=this.getLengths(),d=0,e=c.length,f;f=b?b:a*c[e-1];for(var h=0,g=e-1,i;h<=g;)if(d=Math.floor(h+(g-h)/2),i=c[d]-f,0>i)h=d+1;else if(0<i)g=d-1;else{g=d;break}d=g;if(c[d]==f)return d/(e-1);h=c[d];return c=(d+(f-h)/(c[d+1]-h))/(e-1)};THREE.Curve.prototype.getTangent=function(a){var b=a-1E-4,a=a+1E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);return this.getPoint(a).clone().sub(b).normalize()}; +THREE.Curve.prototype.updateArcLengths=function(){this.needsUpdate=!0;this.getLengths()};THREE.Curve.prototype.getUtoTmapping=function(a,b){var c=this.getLengths(),d=0,e=c.length,f;f=b?b:a*c[e-1];for(var g=0,h=e-1,k;g<=h;)if(d=Math.floor(g+(h-g)/2),k=c[d]-f,0>k)g=d+1;else if(0<k)h=d-1;else{h=d;break}d=h;if(c[d]==f)return d/(e-1);g=c[d];return c=(d+(f-g)/(c[d+1]-g))/(e-1)};THREE.Curve.prototype.getTangent=function(a){var b=a-1E-4;a+=1E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);return this.getPoint(a).clone().sub(b).normalize()}; THREE.Curve.prototype.getTangentAt=function(a){a=this.getUtoTmapping(a);return this.getTangent(a)}; -THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){var a=0.5*(c-a),d=0.5*(d-b),f=e*e;return(2*b-2*c+a+d)*e*f+(-3*b+3*c-2*a-d)*f+a*e+b}}; -THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.getPoint=b;return a};THREE.CurvePath=function(){this.curves=[];this.bends=[];this.autoClose=!1};THREE.CurvePath.prototype=Object.create(THREE.Curve.prototype);THREE.CurvePath.prototype.add=function(a){this.curves.push(a)};THREE.CurvePath.prototype.checkConnection=function(){};THREE.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new THREE.LineCurve(b,a))}; -THREE.CurvePath.prototype.getPoint=function(a){for(var b=a*this.getLength(),c=this.getCurveLengths(),a=0;a<c.length;){if(c[a]>=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; +THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a,b,c,d,e){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){a=.5*(c-a);d=.5*(d-b);var f=e*e;return(2*b-2*c+a+d)*e*f+(-3*b+3*c-2*a-d)*f+a*e+b}}; +THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};THREE.CurvePath=function(){this.curves=[];this.bends=[];this.autoClose=!1};THREE.CurvePath.prototype=Object.create(THREE.Curve.prototype);THREE.CurvePath.prototype.constructor=THREE.CurvePath;THREE.CurvePath.prototype.add=function(a){this.curves.push(a)};THREE.CurvePath.prototype.checkConnection=function(){}; +THREE.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new THREE.LineCurve(b,a))};THREE.CurvePath.prototype.getPoint=function(a){var b=a*this.getLength(),c=this.getCurveLengths();for(a=0;a<c.length;){if(c[a]>=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;c<d;c++)b+=this.curves[c].getLength(),a.push(b);return this.cacheLengths=a}; -THREE.CurvePath.prototype.getBoundingBox=function(){var a=this.getPoints(),b,c,d,e,f,h;b=c=Number.NEGATIVE_INFINITY;e=f=Number.POSITIVE_INFINITY;var g,i,k,m,l=a[0]instanceof THREE.Vector3;m=l?new THREE.Vector3:new THREE.Vector2;i=0;for(k=a.length;i<k;i++)g=a[i],g.x>b?b=g.x:g.x<e&&(e=g.x),g.y>c?c=g.y:g.y<f&&(f=g.y),l&&(g.z>d?d=g.z:g.z<h&&(h=g.z)),m.add(g);a={minX:e,minY:f,maxX:b,maxY:c,centroid:m.divideScalar(k)};l&&(a.maxZ=d,a.minZ=h);return a}; +THREE.CurvePath.prototype.getBoundingBox=function(){var a=this.getPoints(),b,c,d,e,f,g;b=c=Number.NEGATIVE_INFINITY;e=f=Number.POSITIVE_INFINITY;var h,k,l,p,q=a[0]instanceof THREE.Vector3;p=q?new THREE.Vector3:new THREE.Vector2;k=0;for(l=a.length;k<l;k++)h=a[k],h.x>b?b=h.x:h.x<e&&(e=h.x),h.y>c?c=h.y:h.y<f&&(f=h.y),q&&(h.z>d?d=h.z:h.z<g&&(g=h.z)),p.add(h);a={minX:e,minY:f,maxX:b,maxY:c};q&&(a.maxZ=d,a.minZ=g);return a}; THREE.CurvePath.prototype.createPointsGeometry=function(a){a=this.getPoints(a,!0);return this.createGeometry(a)};THREE.CurvePath.prototype.createSpacedPointsGeometry=function(a){a=this.getSpacedPoints(a,!0);return this.createGeometry(a)};THREE.CurvePath.prototype.createGeometry=function(a){for(var b=new THREE.Geometry,c=0;c<a.length;c++)b.vertices.push(new THREE.Vector3(a[c].x,a[c].y,a[c].z||0));return b};THREE.CurvePath.prototype.addWrapPath=function(a){this.bends.push(a)}; THREE.CurvePath.prototype.getTransformedPoints=function(a,b){var c=this.getPoints(a),d,e;b||(b=this.bends);d=0;for(e=b.length;d<e;d++)c=this.getWrapPoints(c,b[d]);return c};THREE.CurvePath.prototype.getTransformedSpacedPoints=function(a,b){var c=this.getSpacedPoints(a),d,e;b||(b=this.bends);d=0;for(e=b.length;d<e;d++)c=this.getWrapPoints(c,b[d]);return c}; -THREE.CurvePath.prototype.getWrapPoints=function(a,b){var c=this.getBoundingBox(),d,e,f,h,g,i;d=0;for(e=a.length;d<e;d++)f=a[d],h=f.x,g=f.y,i=h/c.maxX,i=b.getUtoTmapping(i,h),h=b.getPoint(i),g=b.getNormalVector(i).multiplyScalar(g),f.x=h.x+g.x,f.y=h.y+g.y;return a};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=Object.create(THREE.Object3D.prototype); -THREE.Gyroscope.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?(this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(this.translationWorld,this.quaternionWorld,this.scaleWorld),this.matrix.decompose(this.translationObject,this.quaternionObject,this.scaleObject),this.matrixWorld.compose(this.translationWorld,this.quaternionObject,this.scaleWorld)):this.matrixWorld.copy(this.matrix), -this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)};THREE.Gyroscope.prototype.translationWorld=new THREE.Vector3;THREE.Gyroscope.prototype.translationObject=new THREE.Vector3;THREE.Gyroscope.prototype.quaternionWorld=new THREE.Quaternion;THREE.Gyroscope.prototype.quaternionObject=new THREE.Quaternion;THREE.Gyroscope.prototype.scaleWorld=new THREE.Vector3;THREE.Gyroscope.prototype.scaleObject=new THREE.Vector3;THREE.Path=function(a){THREE.CurvePath.call(this);this.actions=[];a&&this.fromPoints(a)};THREE.Path.prototype=Object.create(THREE.CurvePath.prototype);THREE.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc",ELLIPSE:"ellipse"};THREE.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b].x,a[b].y)}; -THREE.Path.prototype.moveTo=function(a,b){var c=Array.prototype.slice.call(arguments);this.actions.push({action:THREE.PathActions.MOVE_TO,args:c})};THREE.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args,d=new THREE.LineCurve(new THREE.Vector2(d[d.length-2],d[d.length-1]),new THREE.Vector2(a,b));this.curves.push(d);this.actions.push({action:THREE.PathActions.LINE_TO,args:c})}; +THREE.CurvePath.prototype.getWrapPoints=function(a,b){var c=this.getBoundingBox(),d,e,f,g,h,k;d=0;for(e=a.length;d<e;d++)f=a[d],g=f.x,h=f.y,k=g/c.maxX,k=b.getUtoTmapping(k,g),g=b.getPoint(k),k=b.getTangent(k),k.set(-k.y,k.x).multiplyScalar(h),f.x=g.x+k.x,f.y=g.y+k.y;return a};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=Object.create(THREE.Object3D.prototype);THREE.Gyroscope.prototype.constructor=THREE.Gyroscope; +THREE.Gyroscope.prototype.updateMatrixWorld=function(){var a=new THREE.Vector3,b=new THREE.Quaternion,c=new THREE.Vector3,d=new THREE.Vector3,e=new THREE.Quaternion,f=new THREE.Vector3;return function(g){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||g)this.parent?(this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(d,e,f),this.matrix.decompose(a,b,c),this.matrixWorld.compose(d,b,f)):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate= +!1,g=!0;for(var h=0,k=this.children.length;h<k;h++)this.children[h].updateMatrixWorld(g)}}();THREE.Path=function(a){THREE.CurvePath.call(this);this.actions=[];a&&this.fromPoints(a)};THREE.Path.prototype=Object.create(THREE.CurvePath.prototype);THREE.Path.prototype.constructor=THREE.Path;THREE.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc",ELLIPSE:"ellipse"}; +THREE.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b].x,a[b].y)};THREE.Path.prototype.moveTo=function(a,b){var c=Array.prototype.slice.call(arguments);this.actions.push({action:THREE.PathActions.MOVE_TO,args:c})}; +THREE.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args,d=new THREE.LineCurve(new THREE.Vector2(d[d.length-2],d[d.length-1]),new THREE.Vector2(a,b));this.curves.push(d);this.actions.push({action:THREE.PathActions.LINE_TO,args:c})}; THREE.Path.prototype.quadraticCurveTo=function(a,b,c,d){var e=Array.prototype.slice.call(arguments),f=this.actions[this.actions.length-1].args,f=new THREE.QuadraticBezierCurve(new THREE.Vector2(f[f.length-2],f[f.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d));this.curves.push(f);this.actions.push({action:THREE.PathActions.QUADRATIC_CURVE_TO,args:e})}; -THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,e,f){var h=Array.prototype.slice.call(arguments),g=this.actions[this.actions.length-1].args,g=new THREE.CubicBezierCurve(new THREE.Vector2(g[g.length-2],g[g.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d),new THREE.Vector2(e,f));this.curves.push(g);this.actions.push({action:THREE.PathActions.BEZIER_CURVE_TO,args:h})}; -THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,f){var h=this.actions[this.actions.length-1].args;this.absarc(a+h[h.length-2],b+h[h.length-1],c,d,e,f)}; -THREE.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,f,h){var g=this.actions[this.actions.length-1].args;this.absellipse(a+g[g.length-2],b+g[g.length-1],c,d,e,f,h)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,f,h){var g=Array.prototype.slice.call(arguments),i=new THREE.EllipseCurve(a,b,c,d,e,f,h);this.curves.push(i);i=i.getPoint(1);g.push(i.x);g.push(i.y);this.actions.push({action:THREE.PathActions.ELLIPSE,args:g})}; -THREE.Path.prototype.getSpacedPoints=function(a){a||(a=40);for(var b=[],c=0;c<a;c++)b.push(this.getPoint(c/a));return b}; -THREE.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);var a=a||12,c=[],d,e,f,h,g,i,k,m,l,p,s,t,n;d=0;for(e=this.actions.length;d<e;d++)switch(f=this.actions[d],h=f.action,f=f.args,h){case THREE.PathActions.MOVE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:g=f[2];i=f[3];l=f[0];p=f[1];0<c.length?(h=c[c.length-1],s=h.x, -t=h.y):(h=this.actions[d-1].args,s=h[h.length-2],t=h[h.length-1]);for(f=1;f<=a;f++)n=f/a,h=THREE.Shape.Utils.b2(n,s,l,g),n=THREE.Shape.Utils.b2(n,t,p,i),c.push(new THREE.Vector2(h,n));break;case THREE.PathActions.BEZIER_CURVE_TO:g=f[4];i=f[5];l=f[0];p=f[1];k=f[2];m=f[3];0<c.length?(h=c[c.length-1],s=h.x,t=h.y):(h=this.actions[d-1].args,s=h[h.length-2],t=h[h.length-1]);for(f=1;f<=a;f++)n=f/a,h=THREE.Shape.Utils.b3(n,s,l,k,g),n=THREE.Shape.Utils.b3(n,t,p,m,i),c.push(new THREE.Vector2(h,n));break;case THREE.PathActions.CSPLINE_THRU:h= -this.actions[d-1].args;n=[new THREE.Vector2(h[h.length-2],h[h.length-1])];h=a*f[0].length;n=n.concat(f[0]);n=new THREE.SplineCurve(n);for(f=1;f<=h;f++)c.push(n.getPointAt(f/h));break;case THREE.PathActions.ARC:g=f[0];i=f[1];p=f[2];k=f[3];h=f[4];l=!!f[5];s=h-k;t=2*a;for(f=1;f<=t;f++)n=f/t,l||(n=1-n),n=k+n*s,h=g+p*Math.cos(n),n=i+p*Math.sin(n),c.push(new THREE.Vector2(h,n));break;case THREE.PathActions.ELLIPSE:g=f[0];i=f[1];p=f[2];m=f[3];k=f[4];h=f[5];l=!!f[6];s=h-k;t=2*a;for(f=1;f<=t;f++)n=f/t,l|| -(n=1-n),n=k+n*s,h=g+p*Math.cos(n),n=i+m*Math.sin(n),c.push(new THREE.Vector2(h,n))}d=c[c.length-1];1E-10>Math.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; -THREE.Path.prototype.toShapes=function(a){var b,c,d,e,f=[],h=new THREE.Path;b=0;for(c=this.actions.length;b<c;b++)d=this.actions[b],e=d.args,d=d.action,d==THREE.PathActions.MOVE_TO&&0!=h.actions.length&&(f.push(h),h=new THREE.Path),h[d].apply(h,e);0!=h.actions.length&&f.push(h);if(0==f.length)return[];var g;e=[];if(1==f.length)return d=f[0],g=new THREE.Shape,g.actions=d.actions,g.curves=d.curves,e.push(g),e;b=!THREE.Shape.Utils.isClockWise(f[0].getPoints());if(a?!b:b){g=new THREE.Shape;b=0;for(c= -f.length;b<c;b++)d=f[b],h=THREE.Shape.Utils.isClockWise(d.getPoints()),(h=a?!h:h)?(g.actions=d.actions,g.curves=d.curves,e.push(g),g=new THREE.Shape):g.holes.push(d)}else{g=void 0;b=0;for(c=f.length;b<c;b++)d=f[b],h=THREE.Shape.Utils.isClockWise(d.getPoints()),(h=a?!h:h)?(g&&e.push(g),g=new THREE.Shape,g.actions=d.actions,g.curves=d.curves):g.holes.push(d);e.push(g)}return e};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d}; -THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d};THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)}; -THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}}; -THREE.Shape.Utils={removeHoles:function(a,b){var c=a.concat(),d=c.concat(),e,f,h,g,i,k,m,l,p,s,t=[];for(i=0;i<b.length;i++){k=b[i];Array.prototype.push.apply(d,k);f=Number.POSITIVE_INFINITY;for(e=0;e<k.length;e++){p=k[e];s=[];for(l=0;l<c.length;l++)m=c[l],m=p.distanceToSquared(m),s.push(m),m<f&&(f=m,h=e,g=l)}e=0<=g-1?g-1:c.length-1;f=0<=h-1?h-1:k.length-1;var n=[k[h],c[g],c[e]];l=THREE.FontUtils.Triangulate.area(n);var r=[k[h],k[f],c[g]];p=THREE.FontUtils.Triangulate.area(r);s=g;m=h;g+=1;h+=-1;0> -g&&(g+=c.length);g%=c.length;0>h&&(h+=k.length);h%=k.length;e=0<=g-1?g-1:c.length-1;f=0<=h-1?h-1:k.length-1;n=[k[h],c[g],c[e]];n=THREE.FontUtils.Triangulate.area(n);r=[k[h],k[f],c[g]];r=THREE.FontUtils.Triangulate.area(r);l+p>n+r&&(g=s,h=m,0>g&&(g+=c.length),g%=c.length,0>h&&(h+=k.length),h%=k.length,e=0<=g-1?g-1:c.length-1,f=0<=h-1?h-1:k.length-1);l=c.slice(0,g);p=c.slice(g);s=k.slice(h);m=k.slice(0,h);f=[k[h],k[f],c[g]];t.push([k[h],c[g],c[e]]);t.push(f);c=l.concat(s).concat(m).concat(p)}return{shape:c, -isolatedPts:t,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),f,h,g,i,k={};f=0;for(h=d.length;f<h;f++)i=d[f].x+":"+d[f].y,void 0!==k[i]&&console.log("Duplicate point",i),k[i]=f;f=0;for(h=c.length;f<h;f++){g=c[f];for(d=0;3>d;d++)i=g[d].x+":"+g[d].y,i=k[i],void 0!==i&&(g[d]=i)}f=0;for(h=e.length;f<h;f++){g=e[f];for(d=0;3>d;d++)i=g[d].x+":"+g[d].y,i=k[i],void 0!==i&&(g[d]=i)}return c.concat(e)}, -isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+ -this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return new THREE.Vector2(b,a)}; -THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)}; -THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.getPoint=function(a){var b=new THREE.Vector2,c=[],d=this.points,e;e=(d.length-1)*a;a=Math.floor(e);e-=a;c[0]=0==a?a:a-1;c[1]=a;c[2]=a>d.length-2?d.length-1:a+1;c[3]=a>d.length-3?d.length-1:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return b};THREE.EllipseCurve=function(a,b,c,d,e,f,h){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=h};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype); -THREE.EllipseCurve.prototype.getPoint=function(a){var b;b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);b=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);b=this.aY+this.yRadius*Math.sin(b);return new THREE.Vector2(a,b)};THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype);THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)});THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)});THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e,a=(d.length-1)*a;e=Math.floor(a);a-=e;c[0]=0==e?e:e-1;c[1]=e;c[2]=e>d.length-2?d.length-1:e+1;c[3]=e>d.length-3?d.length-1:e+2;e=d[c[0]];var f=d[c[1]],h=d[c[2]],c=d[c[3]];b.x=THREE.Curve.Utils.interpolate(e.x,f.x,h.x,c.x,a);b.y=THREE.Curve.Utils.interpolate(e.y,f.y,h.y,c.y,a);b.z=THREE.Curve.Utils.interpolate(e.z,f.z,h.z,c.z,a);return b});THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e;e=(d.length-0)*a;a=Math.floor(e);e-=a;a+=0<a?0:(Math.floor(Math.abs(a)/d.length)+1)*d.length;c[0]=(a-1)%d.length;c[1]=a%d.length;c[2]=(a+1)%d.length;c[3]=(a+2)%d.length;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);b.z=THREE.Curve.Utils.interpolate(d[c[0]].z, -d[c[1]].z,d[c[2]].z,d[c[3]].z,e);return b});THREE.AnimationHandler=function(){var a=[],b={},c={update:function(b){for(var c=0;c<a.length;c++)a[c].update(b)},addToUpdate:function(b){-1===a.indexOf(b)&&a.push(b)},removeFromUpdate:function(b){b=a.indexOf(b);-1!==b&&a.splice(b,1)},add:function(a){void 0!==b[a.name]&&console.log("THREE.AnimationHandler.add: Warning! "+a.name+" already exists in library. Overwriting.");b[a.name]=a;if(!0!==a.initialized){for(var c=0;c<a.hierarchy.length;c++){for(var d=0;d<a.hierarchy[c].keys.length;d++)if(0>a.hierarchy[c].keys[d].time&& -(a.hierarchy[c].keys[d].time=0),void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var g=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(g[0],g[1],g[2],g[3])}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){g={};for(d=0;d<a.hierarchy[c].keys.length;d++)for(var i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++){var k=a.hierarchy[c].keys[d].morphTargets[i];g[k]=-1}a.hierarchy[c].usedMorphTargets=g; -for(d=0;d<a.hierarchy[c].keys.length;d++){var m={};for(k in g){for(i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++)if(a.hierarchy[c].keys[d].morphTargets[i]===k){m[k]=a.hierarchy[c].keys[d].morphTargetsInfluences[i];break}i===a.hierarchy[c].keys[d].morphTargets.length&&(m[k]=0)}a.hierarchy[c].keys[d].morphTargetsInfluences=m}}for(d=1;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].time===a.hierarchy[c].keys[d-1].time&&(a.hierarchy[c].keys.splice(d,1),d--);for(d=0;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].index= -d}d=parseInt(a.length*a.fps,10);a.JIT={};a.JIT.hierarchy=[];for(c=0;c<a.hierarchy.length;c++)a.JIT.hierarchy.push(Array(d));a.initialized=!0}},get:function(a){if("string"===typeof a){if(b[a])return b[a];console.log("THREE.AnimationHandler.get: Couldn't find animation "+a);return null}},parse:function(a){var b=[];if(a instanceof THREE.SkinnedMesh)for(var c=0;c<a.bones.length;c++)b.push(a.bones[c]);else d(a,b);return b}},d=function(a,b){b.push(a);for(var c=0;c<a.children.length;c++)d(a.children[c], -b)};c.LINEAR=0;c.CATMULLROM=1;c.CATMULLROM_FORWARD=2;return c}();THREE.Animation=function(a,b,c){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=this.isPaused=!0;this.interpolationType=void 0!==c?c:THREE.AnimationHandler.LINEAR;this.points=[];this.target=new THREE.Vector3}; -THREE.Animation.prototype.play=function(a,b){if(!1===this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;var c,d=this.hierarchy.length,e;for(c=0;c<d;c++){e=this.hierarchy[c];e.matrixAutoUpdate=!0;void 0===e.animationCache&&(e.animationCache={},e.animationCache.prevKey={pos:0,rot:0,scl:0},e.animationCache.nextKey={pos:0,rot:0,scl:0},e.animationCache.originalMatrix=e instanceof THREE.Bone?e.skinMatrix:e.matrix);var f=e.animationCache.prevKey;e=e.animationCache.nextKey; -f.pos=this.data.hierarchy[c].keys[0];f.rot=this.data.hierarchy[c].keys[0];f.scl=this.data.hierarchy[c].keys[0];e.pos=this.getNextKeyWith("pos",c,1);e.rot=this.getNextKeyWith("rot",c,1);e.scl=this.getNextKeyWith("scl",c,1)}this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)};THREE.Animation.prototype.pause=function(){!0===this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused}; -THREE.Animation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this)}; -THREE.Animation.prototype.update=function(a){if(!1!==this.isPlaying){var b=["pos","rot","scl"],c,d,e,f,h,g,i,k,m;m=this.currentTime+=a*this.timeScale;k=this.currentTime%=this.data.length;parseInt(Math.min(k*this.data.fps,this.data.length*this.data.fps),10);for(var l=0,p=this.hierarchy.length;l<p;l++){a=this.hierarchy[l];i=a.animationCache;for(var s=0;3>s;s++){c=b[s];h=i.prevKey[c];g=i.nextKey[c];if(g.time<=m){if(k<m)if(this.loop){h=this.data.hierarchy[l].keys[0];for(g=this.getNextKeyWith(c,l,1);g.time< -k;)h=g,g=this.getNextKeyWith(c,l,g.index+1)}else{this.stop();return}else{do h=g,g=this.getNextKeyWith(c,l,g.index+1);while(g.time<k)}i.prevKey[c]=h;i.nextKey[c]=g}a.matrixAutoUpdate=!0;a.matrixWorldNeedsUpdate=!0;d=(k-h.time)/(g.time-h.time);e=h[c];f=g[c];if(0>d||1<d)console.log("THREE.Animation.update: Warning! Scale out of bounds:"+d+" on bone "+l),d=0>d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+ -(f[2]-e[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)this.points[0]=this.getPrevKeyWith("pos",l,h.index-1).pos,this.points[1]=e,this.points[2]=f,this.points[3]=this.getNextKeyWith("pos",l,g.index+1).pos,d=0.33*d+0.33,e=this.interpolateCatmullRom(this.points,d),c.x=e[0],c.y=e[1],c.z=e[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(d=this.interpolateCatmullRom(this.points,1.01*d), -this.target.set(d[0],d[1],d[2]),this.target.sub(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0))}else"rot"===c?THREE.Quaternion.slerp(e,f,a.quaternion,d):"scl"===c&&(c=a.scale,c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+(f[2]-e[2])*d)}}}}; -THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],e,f,h,g,i,k;e=(a.length-1)*b;f=Math.floor(e);e-=f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>a.length-2?f:f+1;c[3]=f>a.length-3?f:f+2;f=a[c[0]];g=a[c[1]];i=a[c[2]];k=a[c[3]];c=e*e;h=e*c;d[0]=this.interpolate(f[0],g[0],i[0],k[0],e,c,h);d[1]=this.interpolate(f[1],g[1],i[1],k[1],e,c,h);d[2]=this.interpolate(f[2],g[2],i[2],k[2],e,c,h);return d}; -THREE.Animation.prototype.interpolate=function(a,b,c,d,e,f,h){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*h+(-3*(b-c)-2*a-d)*f+a*e+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]}; -THREE.Animation.prototype.getPrevKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]};THREE.KeyFrameAnimation=function(a,b,c){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=0.001;this.isPlaying=!1;this.loop=this.isPaused=!0;this.JITCompile=void 0!==c?c:!0;a=0;for(b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],h=this.getNextKeyWith(f,a,0);h&&h.apply(f)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix(); +THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,e,f){var g=Array.prototype.slice.call(arguments),h=this.actions[this.actions.length-1].args,h=new THREE.CubicBezierCurve(new THREE.Vector2(h[h.length-2],h[h.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d),new THREE.Vector2(e,f));this.curves.push(h);this.actions.push({action:THREE.PathActions.BEZIER_CURVE_TO,args:g})}; +THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args;this.absarc(a+g[g.length-2],b+g[g.length-1],c,d,e,f)}; +THREE.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args;this.absellipse(a+h[h.length-2],b+h[h.length-1],c,d,e,f,g)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,f,g){var h=Array.prototype.slice.call(arguments),k=new THREE.EllipseCurve(a,b,c,d,e,f,g);this.curves.push(k);k=k.getPoint(1);h.push(k.x);h.push(k.y);this.actions.push({action:THREE.PathActions.ELLIPSE,args:h})}; +THREE.Path.prototype.getSpacedPoints=function(a,b){a||(a=40);for(var c=[],d=0;d<a;d++)c.push(this.getPoint(d/a));return c}; +THREE.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);a=a||12;var c=[],d,e,f,g,h,k,l,p,q,n,t,r,s;d=0;for(e=this.actions.length;d<e;d++)switch(f=this.actions[d],g=f.action,f=f.args,g){case THREE.PathActions.MOVE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:h=f[2];k=f[3];q=f[0];n=f[1];0<c.length?(g=c[c.length-1],t=g.x, +r=g.y):(g=this.actions[d-1].args,t=g[g.length-2],r=g[g.length-1]);for(f=1;f<=a;f++)s=f/a,g=THREE.Shape.Utils.b2(s,t,q,h),s=THREE.Shape.Utils.b2(s,r,n,k),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.BEZIER_CURVE_TO:h=f[4];k=f[5];q=f[0];n=f[1];l=f[2];p=f[3];0<c.length?(g=c[c.length-1],t=g.x,r=g.y):(g=this.actions[d-1].args,t=g[g.length-2],r=g[g.length-1]);for(f=1;f<=a;f++)s=f/a,g=THREE.Shape.Utils.b3(s,t,q,l,h),s=THREE.Shape.Utils.b3(s,r,n,p,k),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.CSPLINE_THRU:g= +this.actions[d-1].args;s=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=a*f[0].length;s=s.concat(f[0]);s=new THREE.SplineCurve(s);for(f=1;f<=g;f++)c.push(s.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];k=f[1];n=f[2];l=f[3];g=f[4];q=!!f[5];t=g-l;r=2*a;for(f=1;f<=r;f++)s=f/r,q||(s=1-s),s=l+s*t,g=h+n*Math.cos(s),s=k+n*Math.sin(s),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.ELLIPSE:for(h=f[0],k=f[1],n=f[2],p=f[3],l=f[4],g=f[5],q=!!f[6],t=g-l,r=2*a,f=1;f<=r;f++)s=f/r,q|| +(s=1-s),s=l+s*t,g=h+n*Math.cos(s),s=k+p*Math.sin(s),c.push(new THREE.Vector2(g,s))}d=c[c.length-1];1E-10>Math.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new THREE.Shape;f.actions=e.actions;f.curves=e.curves;b.push(f)}return b}function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],h=b[f],k=h.x-g.x,n=h.y-g.y;if(1E-10<Math.abs(n)){if(0>n&&(g=b[f],k=-k,h=b[e],n=-n),!(a.y<g.y||a.y>h.y))if(a.y==g.y){if(a.x==g.x)return!0}else{e=n*(a.x-g.x)-k*(a.y-g.y);if(0==e)return!0;0>e||(d=!d)}}else if(a.y==g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<= +h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;b<c;b++)d=a[b],e=d.args,d=d.action,d==THREE.PathActions.MOVE_TO&&0!=g.actions.length&&(f.push(g),g=new THREE.Path),g[d].apply(g,e);0!=g.actions.length&&f.push(g);return f}(this.actions);if(0==e.length)return[];if(!0===b)return c(e);var f,g,h,k=[];if(1==e.length)return g=e[0],h=new THREE.Shape,h.actions=g.actions,h.curves=g.curves,k.push(h),k;var l=!THREE.Shape.Utils.isClockWise(e[0].getPoints()),l=a?!l:l; +h=[];var p=[],q=[],n=0,t;p[n]=void 0;q[n]=[];var r,s;r=0;for(s=e.length;r<s;r++)g=e[r],t=g.getPoints(),f=THREE.Shape.Utils.isClockWise(t),(f=a?!f:f)?(!l&&p[n]&&n++,p[n]={s:new THREE.Shape,p:t},p[n].s.actions=g.actions,p[n].s.curves=g.curves,l&&n++,q[n]=[]):q[n].push({h:g,p:t[0]});if(!p[0])return c(e);if(1<p.length){r=!1;s=[];g=0;for(e=p.length;g<e;g++)h[g]=[];g=0;for(e=p.length;g<e;g++)for(f=q[g],l=0;l<f.length;l++){n=f[l];t=!0;for(var u=0;u<p.length;u++)d(n.p,p[u].p)&&(g!=u&&s.push({froms:g,tos:u, +hole:l}),t?(t=!1,h[u].push(n)):r=!0);t&&h[g].push(n)}0<s.length&&(r||(q=h))}r=0;for(s=p.length;r<s;r++)for(h=p[r].s,k.push(h),g=q[r],e=0,f=g.length;e<f;e++)h.holes.push(g[e].h);return k};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.constructor=THREE.Shape;THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)}; +THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d};THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d}; +THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)};THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}}; +THREE.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.x<b.x?a.x<=c.x&&c.x<=b.x:b.x<=c.x&&c.x<=a.x:a.y<b.y?a.y<=c.y&&c.y<=b.y:b.y<=c.y&&c.y<=a.y}function d(a,b,d,e,f){var g=b.x-a.x,h=b.y-a.y,k=e.x-d.x,l=e.y-d.y,p=a.x-d.x,q=a.y-d.y,E=h*k-g*l,G=h*p-g*q;if(1E-10<Math.abs(E)){if(0<E){if(0>G||G>E)return[];k=l*p-k*q;if(0>k||k>E)return[]}else{if(0<G||G<E)return[];k=l*p-k*q;if(0<k||k<E)return[]}if(0==k)return!f||0!=G&&G!=E?[a]:[];if(k==E)return!f||0!=G&&G!=E?[b]:[];if(0==G)return[d]; +if(G==E)return[e];f=k/E;return[{x:a.x+f*g,y:a.y+f*h}]}if(0!=G||l*p!=k*q)return[];h=0==g&&0==h;k=0==k&&0==l;if(h&&k)return a.x!=d.x||a.y!=d.y?[]:[a];if(h)return c(d,e,a)?[a]:[];if(k)return c(a,b,d)?[d]:[];0!=g?(a.x<b.x?(g=a,k=a.x,h=b,a=b.x):(g=b,k=b.x,h=a,a=a.x),d.x<e.x?(b=d,E=d.x,l=e,d=e.x):(b=e,E=e.x,l=d,d=d.x)):(a.y<b.y?(g=a,k=a.y,h=b,a=b.y):(g=b,k=b.y,h=a,a=a.y),d.y<e.y?(b=d,E=d.y,l=e,d=e.y):(b=e,E=e.y,l=d,d=d.y));return k<=E?a<E?[]:a==E?f?[]:[b]:a<=d?[b,h]:[b,l]:k>d?[]:k==d?f?[]:[g]:a<=d?[g,h]: +[g,l]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10<Math.abs(a)?(b=g*c-d*b,0<a?0<=e&&0<=b:0<=e||0<=b):0<e}var f,g,h,k,l,p={};h=a.concat();f=0;for(g=b.length;f<g;f++)Array.prototype.push.apply(h,b[f]);f=0;for(g=h.length;f<g;f++)l=h[f].x+":"+h[f].y,void 0!==p[l]&&THREE.warn("THREE.Shape: Duplicate point",l),p[l]=f;f=function(a,b){function c(a,b){var d=h.length-1,f=a-1;0>f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]); +if(!d)return!1;d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;c<h.length;c++)if(e=c+1,e%=h.length,e=d(a,b,h[c],h[e],!0),0<e.length)return!0;return!1}function g(a,c){var e,f,h,k;for(e=0;e<l.length;e++)for(f=b[l[e]],h=0;h<f.length;h++)if(k=h+1,k%=f.length,k=d(a,c,f[h],f[k],!0),0<k.length)return!0;return!1}var h=a.concat(),k,l=[],p,q,A,E,G,F=[],z,I,U,M=0;for(p=b.length;M<p;M++)l.push(M);z=0;for(var H=2*l.length;0<l.length;){H--;if(0> +H){console.log("Infinite Loop! Holes left:"+l.length+", Probably Hole outside Shape!");break}for(q=z;q<h.length;q++){A=h[q];p=-1;for(M=0;M<l.length;M++)if(E=l[M],G=A.x+":"+A.y+":"+E,void 0===F[G]){k=b[E];for(I=0;I<k.length;I++)if(E=k[I],c(q,I)&&!f(A,E)&&!g(A,E)){p=I;l.splice(M,1);z=h.slice(0,q+1);E=h.slice(q);I=k.slice(p);U=k.slice(0,p+1);h=z.concat(I).concat(U).concat(E);z=q;break}if(0<=p)break;F[G]=!0}if(0<=p)break}}return h}(a,b);var q=THREE.FontUtils.Triangulate(f,!1);f=0;for(g=q.length;f<g;f++)for(k= +q[f],h=0;3>h;h++)l=k[h].x+":"+k[h].y,l=p[l],void 0!==l&&(k[h]=l);return q.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a* +a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)}; +THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve; +THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return b};THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=new THREE.Vector2;b.x=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);return b.normalize()}; +THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve;THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)}; +THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.constructor=THREE.SplineCurve; +THREE.SplineCurve.prototype.getPoint=function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector2;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);return c};THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g}; +THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype);THREE.EllipseCurve.prototype.constructor=THREE.EllipseCurve;THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);a=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;b=new THREE.Vector2;b.x=this.aX+this.xRadius*Math.cos(a);b.y=this.aY+this.yRadius*Math.sin(a);return b}; +THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype);THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b}); +THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);b.z=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return b}); +THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b.y=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b.z=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return b}); +THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector3;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);c.z=THREE.Curve.Utils.interpolate(d.z,e.z,f.z,b.z,a);return c}); +THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-0;var c=Math.floor(a);a-=c;var c=c+(0<c?0:(Math.floor(Math.abs(c)/b.length)+1)*b.length),d=b[(c-1)%b.length],e=b[c%b.length],f=b[(c+1)%b.length],b=b[(c+2)%b.length],c=new THREE.Vector3;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);c.z=THREE.Curve.Utils.interpolate(d.z,e.z,f.z,b.z,a);return c}); +THREE.AnimationHandler={LINEAR:0,CATMULLROM:1,CATMULLROM_FORWARD:2,add:function(){THREE.warn("THREE.AnimationHandler.add() has been deprecated.")},get:function(){THREE.warn("THREE.AnimationHandler.get() has been deprecated.")},remove:function(){THREE.warn("THREE.AnimationHandler.remove() has been deprecated.")},animations:[],init:function(a){if(!0===a.initialized)return a;for(var b=0;b<a.hierarchy.length;b++){for(var c=0;c<a.hierarchy[b].keys.length;c++)if(0>a.hierarchy[b].keys[c].time&&(a.hierarchy[b].keys[c].time= +0),void 0!==a.hierarchy[b].keys[c].rot&&!(a.hierarchy[b].keys[c].rot instanceof THREE.Quaternion)){var d=a.hierarchy[b].keys[c].rot;a.hierarchy[b].keys[c].rot=(new THREE.Quaternion).fromArray(d)}if(a.hierarchy[b].keys.length&&void 0!==a.hierarchy[b].keys[0].morphTargets){d={};for(c=0;c<a.hierarchy[b].keys.length;c++)for(var e=0;e<a.hierarchy[b].keys[c].morphTargets.length;e++){var f=a.hierarchy[b].keys[c].morphTargets[e];d[f]=-1}a.hierarchy[b].usedMorphTargets=d;for(c=0;c<a.hierarchy[b].keys.length;c++){var g= +{};for(f in d){for(e=0;e<a.hierarchy[b].keys[c].morphTargets.length;e++)if(a.hierarchy[b].keys[c].morphTargets[e]===f){g[f]=a.hierarchy[b].keys[c].morphTargetsInfluences[e];break}e===a.hierarchy[b].keys[c].morphTargets.length&&(g[f]=0)}a.hierarchy[b].keys[c].morphTargetsInfluences=g}}for(c=1;c<a.hierarchy[b].keys.length;c++)a.hierarchy[b].keys[c].time===a.hierarchy[b].keys[c-1].time&&(a.hierarchy[b].keys.splice(c,1),c--);for(c=0;c<a.hierarchy[b].keys.length;c++)a.hierarchy[b].keys[c].index=c}a.initialized= +!0;return a},parse:function(a){var b=function(a,c){c.push(a);for(var d=0;d<a.children.length;d++)b(a.children[d],c)},c=[];if(a instanceof THREE.SkinnedMesh)for(var d=0;d<a.skeleton.bones.length;d++)c.push(a.skeleton.bones[d]);else b(a,c);return c},play:function(a){-1===this.animations.indexOf(a)&&this.animations.push(a)},stop:function(a){a=this.animations.indexOf(a);-1!==a&&this.animations.splice(a,1)},update:function(a){for(var b=0;b<this.animations.length;b++)this.animations[b].resetBlendWeights(); +for(b=0;b<this.animations.length;b++)this.animations[b].update(a)}};THREE.Animation=function(a,b){this.root=a;this.data=THREE.AnimationHandler.init(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=!0;this.weight=0;this.interpolationType=THREE.AnimationHandler.LINEAR}; +THREE.Animation.prototype={constructor:THREE.Animation,keyTypes:["pos","rot","scl"],play:function(a,b){this.currentTime=void 0!==a?a:0;this.weight=void 0!==b?b:1;this.isPlaying=!0;this.reset();THREE.AnimationHandler.play(this)},stop:function(){this.isPlaying=!1;THREE.AnimationHandler.stop(this)},reset:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a];void 0===c.animationCache&&(c.animationCache={animations:{},blending:{positionWeight:0,quaternionWeight:0,scaleWeight:0}}); +var d=this.data.name,e=c.animationCache.animations,f=e[d];void 0===f&&(f={prevKey:{pos:0,rot:0,scl:0},nextKey:{pos:0,rot:0,scl:0},originalMatrix:c.matrix},e[d]=f);for(c=0;3>c;c++){for(var d=this.keyTypes[c],e=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(d,a,1);g.time<this.currentTime&&g.index>e.index;)e=g,g=this.getNextKeyWith(d,a,g.index+1);f.prevKey[d]=e;f.nextKey[d]=g}}},resetBlendWeights:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a].animationCache;void 0!== +c&&(c=c.blending,c.positionWeight=0,c.quaternionWeight=0,c.scaleWeight=0)}},update:function(){var a=[],b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Quaternion,e=function(a,b){var c=[],d=[],e,q,n,t,r,s;e=(a.length-1)*b;q=Math.floor(e);e-=q;c[0]=0===q?q:q-1;c[1]=q;c[2]=q>a.length-2?q:q+1;c[3]=q>a.length-3?q:q+2;q=a[c[0]];t=a[c[1]];r=a[c[2]];s=a[c[3]];c=e*e;n=e*c;d[0]=f(q[0],t[0],r[0],s[0],e,c,n);d[1]=f(q[1],t[1],r[1],s[1],e,c,n);d[2]=f(q[2],t[2],r[2],s[2],e,c,n);return d},f=function(a,b,c,d, +e,f,n){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*n+(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)this.loop?(this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset()):this.stop();f=0;for(var h=this.hierarchy.length;f<h;f++)for(var k=this.hierarchy[f],l=k.animationCache.animations[this.data.name],p=k.animationCache.blending,q=0;3>q;q++){var n=this.keyTypes[q], +t=l.prevKey[n],r=l.nextKey[n];if(0<this.timeScale&&r.time<=this.currentTime||0>this.timeScale&&t.time>=this.currentTime){t=this.data.hierarchy[f].keys[0];for(r=this.getNextKeyWith(n,f,1);r.time<this.currentTime&&r.index>t.index;)t=r,r=this.getNextKeyWith(n,f,r.index+1);l.prevKey[n]=t;l.nextKey[n]=r}var s=(this.currentTime-t.time)/(r.time-t.time),u=t[n],v=r[n];0>s&&(s=0);1<s&&(s=1);if("pos"===n)if(this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=u[0]+(v[0]-u[0])*s,c.y=u[1]+(v[1]-u[1])*s, +c.z=u[2]+(v[2]-u[2])*s,t=this.weight/(this.weight+p.positionWeight),k.position.lerp(c,t),p.positionWeight+=this.weight;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)a[0]=this.getPrevKeyWith("pos",f,t.index-1).pos,a[1]=u,a[2]=v,a[3]=this.getNextKeyWith("pos",f,r.index+1).pos,s=.33*s+.33,r=e(a,s),t=this.weight/(this.weight+p.positionWeight),p.positionWeight+=this.weight,n=k.position,n.x+=(r[0]-n.x)*t,n.y+=(r[1]- +n.y)*t,n.z+=(r[2]-n.z)*t,this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(s=e(a,1.01*s),b.set(s[0],s[1],s[2]),b.sub(n),b.y=0,b.normalize(),s=Math.atan2(b.x,b.z),k.rotation.set(0,s,0))}else"rot"===n?(THREE.Quaternion.slerp(u,v,d,s),0===p.quaternionWeight?(k.quaternion.copy(d),p.quaternionWeight=this.weight):(t=this.weight/(this.weight+p.quaternionWeight),THREE.Quaternion.slerp(k.quaternion,d,k.quaternion,t),p.quaternionWeight+=this.weight)):"scl"===n&&(c.x=u[0]+(v[0]-u[0])*s,c.y= +u[1]+(v[1]-u[1])*s,c.z=u[2]+(v[2]-u[2])*s,t=this.weight/(this.weight+p.scaleWeight),k.scale.lerp(c,t),p.scaleWeight+=this.weight)}return!0}}}(),getNextKeyWith:function(a,b,c){var d=this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]},getPrevKeyWith:function(a,b,c){var d= +this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]}}; +THREE.KeyFrameAnimation=function(a){this.root=a.node;this.data=THREE.AnimationHandler.init(a);this.hierarchy=THREE.AnimationHandler.parse(this.root);this.currentTime=0;this.timeScale=.001;this.isPlaying=!1;this.loop=this.isPaused=!0;a=0;for(var b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,a,0);g&&g.apply(f)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix(); d.matrixWorldNeedsUpdate=!0}}}; -THREE.KeyFrameAnimation.prototype.play=function(a,b){if(!this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;this.startTimeMs=b;this.startTime=1E7;this.endTime=-this.startTime;var c,d=this.hierarchy.length,e,f;for(c=0;c<d;c++)e=this.hierarchy[c],f=this.data.hierarchy[c],void 0===f.animationCache&&(f.animationCache={},f.animationCache.prevKey=null,f.animationCache.nextKey=null,f.animationCache.originalMatrix=e instanceof THREE.Bone?e.skinMatrix:e.matrix),e=this.data.hierarchy[c].keys, -e.length&&(f.animationCache.prevKey=e[0],f.animationCache.nextKey=e[1],this.startTime=Math.min(e[0].time,this.startTime),this.endTime=Math.max(e[e.length-1].time,this.endTime));this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)};THREE.KeyFrameAnimation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused}; -THREE.KeyFrameAnimation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this);for(var a=0;a<this.data.hierarchy.length;a++){var b=this.hierarchy[a],c=this.data.hierarchy[a];if(void 0!==c.animationCache){var d=c.animationCache.originalMatrix;b instanceof THREE.Bone?(d.copy(b.skinMatrix),b.skinMatrix=d):(d.copy(b.matrix),b.matrix=d);delete c.animationCache}}}; -THREE.KeyFrameAnimation.prototype.update=function(a){if(this.isPlaying){var b,c,d,e,f=this.data.JIT.hierarchy,h,g,i;g=this.currentTime+=a*this.timeScale;h=this.currentTime%=this.data.length;h<this.startTimeMs&&(h=this.currentTime=this.startTimeMs+h);e=parseInt(Math.min(h*this.data.fps,this.data.length*this.data.fps),10);if((i=h<g)&&!this.loop){for(var a=0,k=this.hierarchy.length;a<k;a++){var m=this.data.hierarchy[a].keys,f=this.data.hierarchy[a].sids;d=m.length-1;e=this.hierarchy[a];if(m.length){for(m= -0;m<f.length;m++)h=f[m],(g=this.getPrevKeyWith(h,a,d))&&g.apply(h);this.data.hierarchy[a].node.updateMatrix();e.matrixWorldNeedsUpdate=!0}}this.stop()}else if(!(h<this.startTime)){a=0;for(k=this.hierarchy.length;a<k;a++){d=this.hierarchy[a];b=this.data.hierarchy[a];var m=b.keys,l=b.animationCache;if(this.JITCompile&&void 0!==f[a][e])d instanceof THREE.Bone?(d.skinMatrix=f[a][e],d.matrixWorldNeedsUpdate=!1):(d.matrix=f[a][e],d.matrixWorldNeedsUpdate=!0);else if(m.length){this.JITCompile&&l&&(d instanceof -THREE.Bone?d.skinMatrix=l.originalMatrix:d.matrix=l.originalMatrix);b=l.prevKey;c=l.nextKey;if(b&&c){if(c.time<=g){if(i&&this.loop){b=m[0];for(c=m[1];c.time<h;)b=c,c=m[b.index+1]}else if(!i)for(var p=m.length-1;c.time<h&&c.index!==p;)b=c,c=m[b.index+1];l.prevKey=b;l.nextKey=c}c.time>=h?b.interpolate(c,h):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===f[0][e]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;a<this.hierarchy.length;a++)f[a][e]= -this.hierarchy[a]instanceof THREE.Bone?this.hierarchy[a].skinMatrix.clone():this.hierarchy[a].matrix.clone()}}}};THREE.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;c<b.length;c++)if(b[c].hasTarget(a))return b[c];return b[0]};THREE.KeyFrameAnimation.prototype.getPrevKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c=0<=c?c:c+b.length;0<=c;c--)if(b[c].hasTarget(a))return b[c];return b[b.length-1]};THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,1);f.lookAt(new THREE.Vector3(0,1,0));this.add(f);var h=new THREE.PerspectiveCamera(90,1,a,b);h.up.set(0,0,-1);h.lookAt(new THREE.Vector3(0,-1,0));this.add(h);var g=new THREE.PerspectiveCamera(90, -1,a,b);g.up.set(0,-1,0);g.lookAt(new THREE.Vector3(0,0,1));this.add(g);var i=new THREE.PerspectiveCamera(90,1,a,b);i.up.set(0,-1,0);i.lookAt(new THREE.Vector3(0,0,-1));this.add(i);this.renderTarget=new THREE.WebGLRenderTargetCube(c,c,{format:THREE.RGBFormat,magFilter:THREE.LinearFilter,minFilter:THREE.LinearFilter});this.updateCubeMap=function(a,b){var c=this.renderTarget,p=c.generateMipmaps;c.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace= -2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,h,c);c.activeCubeFace=4;a.render(b,g,c);c.generateMipmaps=p;c.activeCubeFace=5;a.render(b,i,c)}};THREE.CubeCamera.prototype=Object.create(THREE.Object3D.prototype);THREE.CombinedCamera=function(a,b,c,d,e,f,h){THREE.Camera.call(this);this.fov=c;this.left=-a/2;this.right=a/2;this.top=b/2;this.bottom=-b/2;this.cameraO=new THREE.OrthographicCamera(a/-2,a/2,b/2,b/-2,f,h);this.cameraP=new THREE.PerspectiveCamera(c,a/b,d,e);this.zoom=1;this.toPerspective()};THREE.CombinedCamera.prototype=Object.create(THREE.Camera.prototype); -THREE.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near;this.far=this.cameraP.far;this.cameraP.fov=this.fov/this.zoom;this.cameraP.updateProjectionMatrix();this.projectionMatrix=this.cameraP.projectionMatrix;this.inPerspectiveMode=!0;this.inOrthographicMode=!1}; -THREE.CombinedCamera.prototype.toOrthographic=function(){var a=this.cameraP.aspect,b=(this.cameraP.near+this.cameraP.far)/2,b=Math.tan(this.fov/2)*b,a=2*b*a/2,b=b/this.zoom,a=a/this.zoom;this.cameraO.left=-a;this.cameraO.right=a;this.cameraO.top=b;this.cameraO.bottom=-b;this.cameraO.updateProjectionMatrix();this.near=this.cameraO.near;this.far=this.cameraO.far;this.projectionMatrix=this.cameraO.projectionMatrix;this.inPerspectiveMode=!1;this.inOrthographicMode=!0}; -THREE.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b;this.left=-a/2;this.right=a/2;this.top=b/2;this.bottom=-b/2};THREE.CombinedCamera.prototype.setFov=function(a){this.fov=a;this.inPerspectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())}; -THREE.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*THREE.Math.radToDeg(Math.atan(b/(2*a)));this.setFov(c);return c};THREE.CombinedCamera.prototype.setZoom=function(a){this.zoom=a;this.inPerspectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1}; -THREE.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0;this.rotation.y=Math.PI;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0;this.rotation.y=-Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0;this.rotation.y=Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1}; -THREE.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.radius=a=a||50;this.segments=b=void 0!==b?Math.max(3,b):8;this.thetaStart=c=void 0!==c?c:0;this.thetaLength=d=void 0!==d?d:2*Math.PI;var e,f=[];e=new THREE.Vector3;var h=new THREE.Vector2(0.5,0.5);this.vertices.push(e);f.push(h);for(e=0;e<=b;e++){var g=new THREE.Vector3,i=c+e/b*d;g.x=a*Math.cos(i);g.y=a*Math.sin(i);this.vertices.push(g);f.push(new THREE.Vector2((g.x/a+1)/2,(g.y/a+1)/2))}c=new THREE.Vector3(0,0,1);for(e=1;e<=b;e++)this.faces.push(new THREE.Face3(e, -e+1,0,[c,c,c])),this.faceVertexUvs[0].push([f[e],f[e+1],h]);this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CubeGeometry=function(a,b,c,d,e,f){function h(a,b,c,d,e,f,h,n){var r,q=g.widthSegments,u=g.heightSegments,w=e/2,z=f/2,B=g.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)r="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)r="y",u=g.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)r="x",q=g.depthSegments;var D=q+1,x=u+1,F=e/q,A=f/u,O=new THREE.Vector3;O[r]=0<h?1:-1;for(e=0;e<x;e++)for(f=0;f<D;f++){var C=new THREE.Vector3;C[a]=(f*F-w)*c;C[b]=(e*A-z)*d;C[r]=h;g.vertices.push(C)}for(e= -0;e<u;e++)for(f=0;f<q;f++)z=f+D*e,a=f+D*(e+1),b=f+1+D*(e+1),c=f+1+D*e,d=new THREE.Vector2(f/q,1-e/u),h=new THREE.Vector2(f/q,1-(e+1)/u),r=new THREE.Vector2((f+1)/q,1-(e+1)/u),w=new THREE.Vector2((f+1)/q,1-e/u),z=new THREE.Face3(z+B,a+B,c+B),z.normal.copy(O),z.vertexNormals.push(O.clone(),O.clone(),O.clone()),z.materialIndex=n,g.faces.push(z),g.faceVertexUvs[0].push([d,h,w]),z=new THREE.Face3(a+B,b+B,c+B),z.normal.copy(O),z.vertexNormals.push(O.clone(),O.clone(),O.clone()),z.materialIndex=n,g.faces.push(z), -g.faceVertexUvs[0].push([h.clone(),r,w.clone()])}THREE.Geometry.call(this);var g=this;this.width=a;this.height=b;this.depth=c;this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments=f||1;a=this.width/2;b=this.height/2;c=this.depth/2;h("z","y",-1,-1,this.depth,this.height,a,0);h("z","y",1,-1,this.depth,this.height,-a,1);h("x","z",1,1,this.width,this.depth,b,2);h("x","z",1,-1,this.width,this.depth,-b,3);h("x","y",1,-1,this.width,this.height,c,4);h("x","y",-1,-1,this.width,this.height,-c, -5);this.computeCentroids();this.mergeVertices()};THREE.CubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.radiusTop=a=void 0!==a?a:20;this.radiusBottom=b=void 0!==b?b:20;this.height=c=void 0!==c?c:100;this.radialSegments=d=d||8;this.heightSegments=e=e||1;this.openEnded=f=void 0!==f?f:!1;var h=c/2,g,i,k=[],m=[];for(i=0;i<=e;i++){var l=[],p=[],s=i/e,t=s*(b-a)+a;for(g=0;g<=d;g++){var n=g/d,r=new THREE.Vector3;r.x=t*Math.sin(2*n*Math.PI);r.y=-s*c+h;r.z=t*Math.cos(2*n*Math.PI);this.vertices.push(r);l.push(this.vertices.length-1);p.push(new THREE.Vector2(n, -1-s))}k.push(l);m.push(p)}c=(b-a)/c;for(g=0;g<d;g++){0!==a?(l=this.vertices[k[0][g]].clone(),p=this.vertices[k[0][g+1]].clone()):(l=this.vertices[k[1][g]].clone(),p=this.vertices[k[1][g+1]].clone());l.setY(Math.sqrt(l.x*l.x+l.z*l.z)*c).normalize();p.setY(Math.sqrt(p.x*p.x+p.z*p.z)*c).normalize();for(i=0;i<e;i++){var s=k[i][g],t=k[i+1][g],n=k[i+1][g+1],r=k[i][g+1],q=l.clone(),u=l.clone(),w=p.clone(),z=p.clone(),B=m[i][g].clone(),D=m[i+1][g].clone(),x=m[i+1][g+1].clone(),F=m[i][g+1].clone();this.faces.push(new THREE.Face3(s, -t,r,[q,u,z]));this.faceVertexUvs[0].push([B,D,F]);this.faces.push(new THREE.Face3(t,n,r,[u,w,z]));this.faceVertexUvs[0].push([D,x,F])}}if(!1===f&&0<a){this.vertices.push(new THREE.Vector3(0,h,0));for(g=0;g<d;g++)s=k[0][g],t=k[0][g+1],n=this.vertices.length-1,q=new THREE.Vector3(0,1,0),u=new THREE.Vector3(0,1,0),w=new THREE.Vector3(0,1,0),B=m[0][g].clone(),D=m[0][g+1].clone(),x=new THREE.Vector2(D.u,0),this.faces.push(new THREE.Face3(s,t,n,[q,u,w])),this.faceVertexUvs[0].push([B,D,x])}if(!1===f&&0< -b){this.vertices.push(new THREE.Vector3(0,-h,0));for(g=0;g<d;g++)s=k[i][g+1],t=k[i][g],n=this.vertices.length-1,q=new THREE.Vector3(0,-1,0),u=new THREE.Vector3(0,-1,0),w=new THREE.Vector3(0,-1,0),B=m[i][g+1].clone(),D=m[i][g].clone(),x=new THREE.Vector2(D.u,1),this.faces.push(new THREE.Face3(s,t,n,[q,u,w])),this.faceVertexUvs[0].push([B,D,x])}this.computeCentroids();this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)}; -THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.log("die");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=THREE.ExtrudeGeometry.__v1,e=THREE.ExtrudeGeometry.__v2,f=THREE.ExtrudeGeometry.__v3,g=THREE.ExtrudeGeometry.__v4,h=THREE.ExtrudeGeometry.__v5,i=THREE.ExtrudeGeometry.__v6;d.set(a.x-b.x,a.y-b.y);e.set(a.x-c.x,a.y-c.y);d=d.normalize();e=e.normalize();f.set(-d.y,d.x);g.set(e.y,-e.x);h.copy(a).add(f);i.copy(a).add(g);if(h.equals(i))return g.clone(); -h.copy(b).add(f);i.copy(c).add(g);f=d.dot(g);g=i.sub(h).dot(g);0===f&&(console.log("Either infinite or no solutions!"),0===g?console.log("Its finite solutions."):console.log("Too bad, no solutions."));g/=f;return 0>g?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).add(h).sub(a).clone()}function e(c,d){var e,f;for(N=c.length;0<=--N;){e=N;f=N-1;0>f&&(f=c.length-1);for(var g=0,h=s+2*m, -g=0;g<h;g++){var i=ba*g,k=ba*(g+1),l=d+e+i,i=d+f+i,p=d+f+k,k=d+e+k,n=c,q=g,r=h,t=e,v=f,l=l+E,i=i+E,p=p+E,k=k+E;C.faces.push(new THREE.Face3(l,i,k,null,null,u));C.faces.push(new THREE.Face3(i,p,k,null,null,u));l=w.generateSideWallUV(C,a,n,b,l,i,p,k,q,r,t,v);C.faceVertexUvs[0].push([l[0],l[1],l[3]]);C.faceVertexUvs[0].push([l[1],l[2],l[3]])}}}function f(a,b,c){C.vertices.push(new THREE.Vector3(a,b,c))}function h(c,d,e,f){c+=E;d+=E;e+=E;C.faces.push(new THREE.Face3(c,d,e,null,null,q));c=f?w.generateBottomUV(C, -a,b,c,d,e):w.generateTopUV(C,a,b,c,d,e);C.faceVertexUvs[0].push(c)}var g=void 0!==b.amount?b.amount:100,i=void 0!==b.bevelThickness?b.bevelThickness:6,k=void 0!==b.bevelSize?b.bevelSize:i-2,m=void 0!==b.bevelSegments?b.bevelSegments:3,l=void 0!==b.bevelEnabled?b.bevelEnabled:!0,p=void 0!==b.curveSegments?b.curveSegments:12,s=void 0!==b.steps?b.steps:1,t=b.extrudePath,n,r=!1,q=b.material,u=b.extrudeMaterial,w=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,z,B,D,x;t&&(n= -t.getSpacedPoints(s),r=!0,l=!1,z=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(t,s,!1),B=new THREE.Vector3,D=new THREE.Vector3,x=new THREE.Vector3);l||(k=i=m=0);var F,A,O,C=this,E=this.vertices.length,p=a.extractPoints(p),I=p.shape,p=p.holes;if(t=!THREE.Shape.Utils.isClockWise(I)){I=I.reverse();A=0;for(O=p.length;A<O;A++)F=p[A],THREE.Shape.Utils.isClockWise(F)&&(p[A]=F.reverse());t=!1}var y=THREE.Shape.Utils.triangulateShape(I,p),t=I;A=0;for(O=p.length;A<O;A++)F=p[A],I=I.concat(F); -var v,G,R,J,ba=I.length,oa=y.length,pa=[],N=0,M=t.length;v=M-1;for(G=N+1;N<M;N++,v++,G++)v===M&&(v=0),G===M&&(G=0),pa[N]=d(t[N],t[v],t[G]);var Q=[],K,ca=pa.concat();A=0;for(O=p.length;A<O;A++){F=p[A];K=[];N=0;M=F.length;v=M-1;for(G=N+1;N<M;N++,v++,G++)v===M&&(v=0),G===M&&(G=0),K[N]=d(F[N],F[v],F[G]);Q.push(K);ca=ca.concat(K)}for(v=0;v<m;v++){F=v/m;R=i*(1-F);G=k*Math.sin(F*Math.PI/2);N=0;for(M=t.length;N<M;N++)J=c(t[N],pa[N],G),f(J.x,J.y,-R);A=0;for(O=p.length;A<O;A++){F=p[A];K=Q[A];N=0;for(M=F.length;N< -M;N++)J=c(F[N],K[N],G),f(J.x,J.y,-R)}}G=k;for(N=0;N<ba;N++)J=l?c(I[N],ca[N],G):I[N],r?(D.copy(z.normals[0]).multiplyScalar(J.x),B.copy(z.binormals[0]).multiplyScalar(J.y),x.copy(n[0]).add(D).add(B),f(x.x,x.y,x.z)):f(J.x,J.y,0);for(F=1;F<=s;F++)for(N=0;N<ba;N++)J=l?c(I[N],ca[N],G):I[N],r?(D.copy(z.normals[F]).multiplyScalar(J.x),B.copy(z.binormals[F]).multiplyScalar(J.y),x.copy(n[F]).add(D).add(B),f(x.x,x.y,x.z)):f(J.x,J.y,g/s*F);for(v=m-1;0<=v;v--){F=v/m;R=i*(1-F);G=k*Math.sin(F*Math.PI/2);N=0;for(M= -t.length;N<M;N++)J=c(t[N],pa[N],G),f(J.x,J.y,g+R);A=0;for(O=p.length;A<O;A++){F=p[A];K=Q[A];N=0;for(M=F.length;N<M;N++)J=c(F[N],K[N],G),r?f(J.x,J.y+n[s-1].y,n[s-1].x+R):f(J.x,J.y,g+R)}}if(l){i=0*ba;for(N=0;N<oa;N++)g=y[N],h(g[2]+i,g[1]+i,g[0]+i,!0);i=ba*(s+2*m);for(N=0;N<oa;N++)g=y[N],h(g[0]+i,g[1]+i,g[2]+i,!1)}else{for(N=0;N<oa;N++)g=y[N],h(g[2],g[1],g[0],!0);for(N=0;N<oa;N++)g=y[N],h(g[0]+ba*s,g[1]+ba*s,g[2]+ba*s,!1)}g=0;e(t,g);g+=t.length;A=0;for(O=p.length;A<O;A++)F=p[A],e(F,g),g+=F.length}; -THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,e,f){b=a.vertices[e].x;e=a.vertices[e].y;c=a.vertices[f].x;f=a.vertices[f].y;return[new THREE.Vector2(a.vertices[d].x,a.vertices[d].y),new THREE.Vector2(b,e),new THREE.Vector2(c,f)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,e,f,h,g){var b=a.vertices[e].x,c=a.vertices[e].y,e=a.vertices[e].z,d=a.vertices[f].x,i=a.vertices[f].y,f=a.vertices[f].z,k=a.vertices[h].x, -m=a.vertices[h].y,h=a.vertices[h].z,l=a.vertices[g].x,p=a.vertices[g].y,a=a.vertices[g].z;return 0.01>Math.abs(c-i)?[new THREE.Vector2(b,1-e),new THREE.Vector2(d,1-f),new THREE.Vector2(k,1-h),new THREE.Vector2(l,1-a)]:[new THREE.Vector2(c,1-e),new THREE.Vector2(i,1-f),new THREE.Vector2(m,1-h),new THREE.Vector2(p,1-a)]}};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2; -THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);!1===a instanceof Array&&(a=[a]);this.shapebb=a[a.length-1].getBoundingBox();this.addShapeList(a,b);this.computeCentroids();this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this}; -THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,f,h,g=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var i=e.shape,k=e.holes;if(!THREE.Shape.Utils.isClockWise(i)){i=i.reverse();e=0;for(f=k.length;e<f;e++)h=k[e],THREE.Shape.Utils.isClockWise(h)&&(k[e]=h.reverse())}var m=THREE.Shape.Utils.triangulateShape(i,k);e=0;for(f=k.length;e<f;e++)h=k[e], -i=i.concat(h);k=i.length;f=m.length;for(e=0;e<k;e++)h=i[e],this.vertices.push(new THREE.Vector3(h.x,h.y,0));for(e=0;e<f;e++)k=m[e],i=k[0]+g,h=k[1]+g,k=k[2]+g,this.faces.push(new THREE.Face3(i,h,k,null,null,c)),this.faceVertexUvs[0].push(d.generateBottomUV(this,a,b,i,h,k))};THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);for(var b=b||12,c=c||0,d=d||2*Math.PI,e=1/(a.length-1),f=1/b,h=0,g=b;h<=g;h++)for(var i=c+h*f*d,k=Math.cos(i),m=Math.sin(i),i=0,l=a.length;i<l;i++){var p=a[i],s=new THREE.Vector3;s.x=k*p.x-m*p.y;s.y=m*p.x+k*p.y;s.z=p.z;this.vertices.push(s)}c=a.length;h=0;for(g=b;h<g;h++){i=0;for(l=a.length-1;i<l;i++){var b=m=i+c*h,d=m+c,k=m+1+c,m=m+1,p=h*f,s=i*e,t=p+f,n=s+e;this.faces.push(new THREE.Face3(b,d,m));this.faceVertexUvs[0].push([new THREE.Vector2(p, -s),new THREE.Vector2(t,s),new THREE.Vector2(p,n)]);this.faces.push(new THREE.Face3(d,k,m));this.faceVertexUvs[0].push([new THREE.Vector2(t,s),new THREE.Vector2(t,n),new THREE.Vector2(p,n)])}}this.mergeVertices();this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.width=a;this.height=b;this.widthSegments=c||1;this.heightSegments=d||1;for(var e=a/2,f=b/2,c=this.widthSegments,d=this.heightSegments,h=c+1,g=d+1,i=this.width/c,k=this.height/d,m=new THREE.Vector3(0,0,1),a=0;a<g;a++)for(b=0;b<h;b++)this.vertices.push(new THREE.Vector3(b*i-e,-(a*k-f),0));for(a=0;a<d;a++)for(b=0;b<c;b++){var l=b+h*a,e=b+h*(a+1),f=b+1+h*(a+1),g=b+1+h*a,i=new THREE.Vector2(b/c,1-a/d),k=new THREE.Vector2(b/c,1-(a+1)/ -d),p=new THREE.Vector2((b+1)/c,1-(a+1)/d),s=new THREE.Vector2((b+1)/c,1-a/d),l=new THREE.Face3(l,e,g);l.normal.copy(m);l.vertexNormals.push(m.clone(),m.clone(),m.clone());this.faces.push(l);this.faceVertexUvs[0].push([i,k,s]);l=new THREE.Face3(e,f,g);l.normal.copy(m);l.vertexNormals.push(m.clone(),m.clone(),m.clone());this.faces.push(l);this.faceVertexUvs[0].push([k.clone(),p,s.clone()])}this.computeCentroids()};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.RingGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);for(var a=a||0,b=b||50,e=void 0!==e?e:0,f=void 0!==f?f:2*Math.PI,c=void 0!==c?Math.max(3,c):8,d=void 0!==d?Math.max(3,d):8,h=[],g=a,i=(b-a)/d,a=0;a<=d;a++){for(b=0;b<=c;b++){var k=new THREE.Vector3,m=e+b/c*f;k.x=g*Math.cos(m);k.y=g*Math.sin(m);this.vertices.push(k);h.push(new THREE.Vector2((k.x/g+1)/2,-(k.y/g+1)/2+1))}g+=i}e=new THREE.Vector3(0,0,1);for(a=0;a<d;a++){f=a*c;for(b=0;b<=c;b++){var m=b+f,i=m+a,k=m+c+a,l=m+c+1+a;this.faces.push(new THREE.Face3(i, -k,l,[e,e,e]));this.faceVertexUvs[0].push([h[i],h[k],h[l]]);i=m+a;k=m+c+1+a;l=m+1+a;this.faces.push(new THREE.Face3(i,k,l,[e,e,e]));this.faceVertexUvs[0].push([h[i],h[k],h[l]])}}this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,g)};THREE.RingGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry=function(a,b,c,d,e,f,h){THREE.Geometry.call(this);this.radius=a=a||50;this.widthSegments=b=Math.max(3,Math.floor(b)||8);this.heightSegments=c=Math.max(2,Math.floor(c)||6);this.phiStart=d=void 0!==d?d:0;this.phiLength=e=void 0!==e?e:2*Math.PI;this.thetaStart=f=void 0!==f?f:0;this.thetaLength=h=void 0!==h?h:Math.PI;var g,i,k=[],m=[];for(i=0;i<=c;i++){var l=[],p=[];for(g=0;g<=b;g++){var s=g/b,t=i/c,n=new THREE.Vector3;n.x=-a*Math.cos(d+s*e)*Math.sin(f+t*h);n.y=a*Math.cos(f+t*h); -n.z=a*Math.sin(d+s*e)*Math.sin(f+t*h);this.vertices.push(n);l.push(this.vertices.length-1);p.push(new THREE.Vector2(s,1-t))}k.push(l);m.push(p)}for(i=0;i<this.heightSegments;i++)for(g=0;g<this.widthSegments;g++){var b=k[i][g+1],c=k[i][g],d=k[i+1][g],e=k[i+1][g+1],f=this.vertices[b].clone().normalize(),h=this.vertices[c].clone().normalize(),l=this.vertices[d].clone().normalize(),p=this.vertices[e].clone().normalize(),s=m[i][g+1].clone(),t=m[i][g].clone(),n=m[i+1][g].clone(),r=m[i+1][g+1].clone();Math.abs(this.vertices[b].y)=== -this.radius?(this.faces.push(new THREE.Face3(b,d,e,[f,l,p])),this.faceVertexUvs[0].push([s,n,r])):Math.abs(this.vertices[d].y)===this.radius?(this.faces.push(new THREE.Face3(b,c,d,[f,h,l])),this.faceVertexUvs[0].push([s,t,n])):(this.faces.push(new THREE.Face3(b,c,e,[f,h,p])),this.faceVertexUvs[0].push([s,t,r]),this.faces.push(new THREE.Face3(c,d,e,[h,l,p])),this.faceVertexUvs[0].push([t.clone(),n,r.clone()]))}this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3, -a)};THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TextGeometry=function(a,b){var b=b||{},c=THREE.FontUtils.generateShapes(a,b);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);THREE.ExtrudeGeometry.call(this,c,b)};THREE.TextGeometry.prototype=Object.create(THREE.ExtrudeGeometry.prototype);THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.radius=a||100;this.tube=b||40;this.radialSegments=c||8;this.tubularSegments=d||6;this.arc=e||2*Math.PI;e=new THREE.Vector3;a=[];b=[];for(c=0;c<=this.radialSegments;c++)for(d=0;d<=this.tubularSegments;d++){var f=d/this.tubularSegments*this.arc,h=2*c/this.radialSegments*Math.PI;e.x=this.radius*Math.cos(f);e.y=this.radius*Math.sin(f);var g=new THREE.Vector3;g.x=(this.radius+this.tube*Math.cos(h))*Math.cos(f);g.y=(this.radius+this.tube* -Math.cos(h))*Math.sin(f);g.z=this.tube*Math.sin(h);this.vertices.push(g);a.push(new THREE.Vector2(d/this.tubularSegments,c/this.radialSegments));b.push(g.clone().sub(e).normalize())}for(c=1;c<=this.radialSegments;c++)for(d=1;d<=this.tubularSegments;d++){var e=(this.tubularSegments+1)*c+d-1,f=(this.tubularSegments+1)*(c-1)+d-1,h=(this.tubularSegments+1)*(c-1)+d,g=(this.tubularSegments+1)*c+d,i=new THREE.Face3(e,f,g,[b[e],b[f],b[g]]);i.normal.add(b[e]);i.normal.add(b[f]);i.normal.add(b[g]);i.normal.normalize(); -this.faces.push(i);this.faceVertexUvs[0].push([a[e].clone(),a[f].clone(),a[g].clone()]);i=new THREE.Face3(f,h,g,[b[f],b[h],b[g]]);i.normal.add(b[f]);i.normal.add(b[h]);i.normal.add(b[g]);i.normal.normalize();this.faces.push(i);this.faceVertexUvs[0].push([a[f].clone(),a[h].clone(),a[g].clone()])}this.computeCentroids()};THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry=function(a,b,c,d,e,f,h){function g(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a),a=b/c*a,b=Math.cos(a),f=0.5*(d*(2+b))*f,g=0.5*d*(2+b)*g,d=0.5*e*d*Math.sin(a);return new THREE.Vector3(f,g,d)}THREE.Geometry.call(this);this.radius=a||100;this.tube=b||40;this.radialSegments=c||64;this.tubularSegments=d||8;this.p=e||2;this.q=f||3;this.heightScale=h||1;this.grid=Array(this.radialSegments);c=new THREE.Vector3;d=new THREE.Vector3;e=new THREE.Vector3;for(a=0;a<this.radialSegments;++a){this.grid[a]= -Array(this.tubularSegments);b=2*(a/this.radialSegments)*this.p*Math.PI;f=g(b,this.q,this.p,this.radius,this.heightScale);b=g(b+0.01,this.q,this.p,this.radius,this.heightScale);c.subVectors(b,f);d.addVectors(b,f);e.crossVectors(c,d);d.crossVectors(e,c);e.normalize();d.normalize();for(b=0;b<this.tubularSegments;++b){var i=2*(b/this.tubularSegments)*Math.PI,h=-this.tube*Math.cos(i),i=this.tube*Math.sin(i),k=new THREE.Vector3;k.x=f.x+h*d.x+i*e.x;k.y=f.y+h*d.y+i*e.y;k.z=f.z+h*d.z+i*e.z;this.grid[a][b]= -this.vertices.push(k)-1}}for(a=0;a<this.radialSegments;++a)for(b=0;b<this.tubularSegments;++b){var e=(a+1)%this.radialSegments,f=(b+1)%this.tubularSegments,c=this.grid[a][b],d=this.grid[e][b],e=this.grid[e][f],f=this.grid[a][f],h=new THREE.Vector2(a/this.radialSegments,b/this.tubularSegments),i=new THREE.Vector2((a+1)/this.radialSegments,b/this.tubularSegments),k=new THREE.Vector2((a+1)/this.radialSegments,(b+1)/this.tubularSegments),m=new THREE.Vector2(a/this.radialSegments,(b+1)/this.tubularSegments); -this.faces.push(new THREE.Face3(c,d,f));this.faceVertexUvs[0].push([h,i,m]);this.faces.push(new THREE.Face3(d,e,f));this.faceVertexUvs[0].push([i.clone(),k,m.clone()])}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.path=a;this.segments=b||64;this.radius=c||1;this.radialSegments=d||8;this.closed=e||!1;this.grid=[];var f,h,d=this.segments+1,g,i,k,e=new THREE.Vector3,m,l,b=new THREE.TubeGeometry.FrenetFrames(this.path,this.segments,this.closed);m=b.normals;l=b.binormals;this.tangents=b.tangents;this.normals=m;this.binormals=l;for(b=0;b<d;b++){this.grid[b]=[];c=b/(d-1);k=a.getPointAt(c);f=m[b];h=l[b];for(c=0;c<this.radialSegments;c++)g=2*(c/this.radialSegments)* -Math.PI,i=-this.radius*Math.cos(g),g=this.radius*Math.sin(g),e.copy(k),e.x+=i*f.x+g*h.x,e.y+=i*f.y+g*h.y,e.z+=i*f.z+g*h.z,this.grid[b][c]=this.vertices.push(new THREE.Vector3(e.x,e.y,e.z))-1}for(b=0;b<this.segments;b++)for(c=0;c<this.radialSegments;c++)e=this.closed?(b+1)%this.segments:b+1,m=(c+1)%this.radialSegments,a=this.grid[b][c],d=this.grid[e][c],e=this.grid[e][m],m=this.grid[b][m],l=new THREE.Vector2(b/this.segments,c/this.radialSegments),f=new THREE.Vector2((b+1)/this.segments,c/this.radialSegments), -h=new THREE.Vector2((b+1)/this.segments,(c+1)/this.radialSegments),i=new THREE.Vector2(b/this.segments,(c+1)/this.radialSegments),this.faces.push(new THREE.Face3(a,d,m)),this.faceVertexUvs[0].push([l,f,i]),this.faces.push(new THREE.Face3(d,e,m)),this.faceVertexUvs[0].push([f.clone(),h,i.clone()]);this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype); -THREE.TubeGeometry.FrenetFrames=function(a,b,c){new THREE.Vector3;var d=new THREE.Vector3;new THREE.Vector3;var e=[],f=[],h=[],g=new THREE.Vector3,i=new THREE.Matrix4,b=b+1,k,m,l;this.tangents=e;this.normals=f;this.binormals=h;for(k=0;k<b;k++)m=k/(b-1),e[k]=a.getTangentAt(m),e[k].normalize();f[0]=new THREE.Vector3;h[0]=new THREE.Vector3;a=Number.MAX_VALUE;k=Math.abs(e[0].x);m=Math.abs(e[0].y);l=Math.abs(e[0].z);k<=a&&(a=k,d.set(1,0,0));m<=a&&(a=m,d.set(0,1,0));l<=a&&d.set(0,0,1);g.crossVectors(e[0], -d).normalize();f[0].crossVectors(e[0],g);h[0].crossVectors(e[0],f[0]);for(k=1;k<b;k++)f[k]=f[k-1].clone(),h[k]=h[k-1].clone(),g.crossVectors(e[k-1],e[k]),1E-4<g.length()&&(g.normalize(),d=Math.acos(THREE.Math.clamp(e[k-1].dot(e[k]),-1,1)),f[k].applyMatrix4(i.makeRotationAxis(g,d))),h[k].crossVectors(e[k],f[k]);if(c){d=Math.acos(THREE.Math.clamp(f[0].dot(f[b-1]),-1,1));d/=b-1;0<e[0].dot(g.crossVectors(f[0],f[b-1]))&&(d=-d);for(k=1;k<b;k++)f[k].applyMatrix4(i.makeRotationAxis(e[k],d*k)),h[k].crossVectors(e[k], -f[k])}};THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=g.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+0.5,a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+0.5;b.uv=new THREE.Vector2(c,1-a);return b}function f(a,b,c){var d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);d.centroid.add(a).add(b).add(c).divideScalar(3);g.faces.push(d);d=Math.atan2(d.centroid.z,-d.centroid.x);g.faceVertexUvs[0].push([h(a.uv,a,d),h(b.uv,b,d), -h(c.uv,c,d)])}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+0.5,a.y));return a.clone()}THREE.Geometry.call(this);for(var c=c||1,d=d||0,g=this,i=0,k=a.length;i<k;i++)e(new THREE.Vector3(a[i][0],a[i][1],a[i][2]));for(var m=this.vertices,a=[],i=0,k=b.length;i<k;i++){var l=m[b[i][0]],p=m[b[i][1]],s=m[b[i][2]];a[i]=new THREE.Face3(l.index,p.index,s.index,[l.clone(),p.clone(),s.clone()])}i=0;for(k=a.length;i<k;i++){p=a[i];m=d;b=Math.pow(2, -m);Math.pow(4,m);for(var m=e(g.vertices[p.a]),l=e(g.vertices[p.b]),t=e(g.vertices[p.c]),p=[],s=0;s<=b;s++){p[s]=[];for(var n=e(m.clone().lerp(t,s/b)),r=e(l.clone().lerp(t,s/b)),q=b-s,u=0;u<=q;u++)p[s][u]=0==u&&s==b?n:e(n.clone().lerp(r,u/q))}for(s=0;s<b;s++)for(u=0;u<2*(b-s)-1;u++)m=Math.floor(u/2),0==u%2?f(p[s][m+1],p[s+1][m],p[s][m]):f(p[s][m+1],p[s+1][m+1],p[s+1][m])}i=0;for(k=this.faceVertexUvs[0].length;i<k;i++)d=this.faceVertexUvs[0][i],a=d[0].x,b=d[1].x,m=d[2].x,l=Math.max(a,Math.max(b,m)), -p=Math.min(a,Math.min(b,m)),0.9<l&&0.1>p&&(0.2>a&&(d[0].x+=1),0.2>b&&(d[1].x+=1),0.2>m&&(d[2].x+=1));i=0;for(k=this.vertices.length;i<k;i++)this.vertices[i].multiplyScalar(c);this.mergeVertices();this.computeCentroids();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.IcosahedronGeometry=function(a,b){this.radius=a;this.detail=b;var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]],a,b)};THREE.IcosahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.OctahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]],a,b)};THREE.OctahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],[[2,1,0],[0,3,2],[1,3,0],[2,3,1]],a,b)};THREE.TetrahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry=function(a,b,c){THREE.Geometry.call(this);var d=this.vertices,e=this.faces,f=this.faceVertexUvs[0],h,g,i,k,m=b+1;for(h=0;h<=c;h++){k=h/c;for(g=0;g<=b;g++)i=g/b,i=a(i,k),d.push(i)}var l,p,s,t;for(h=0;h<c;h++)for(g=0;g<b;g++)a=h*m+g,d=h*m+g+1,k=(h+1)*m+g+1,i=(h+1)*m+g,l=new THREE.Vector2(g/b,h/c),p=new THREE.Vector2((g+1)/b,h/c),s=new THREE.Vector2((g+1)/b,(h+1)/c),t=new THREE.Vector2(g/b,(h+1)/c),e.push(new THREE.Face3(a,d,i)),f.push([l,p,t]),e.push(new THREE.Face3(d,k,i)), -f.push([p.clone(),s,t.clone()]);this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.AxisHelper=function(a){var a=a||1,b=new THREE.Geometry;b.vertices.push(new THREE.Vector3,new THREE.Vector3(a,0,0),new THREE.Vector3,new THREE.Vector3(0,a,0),new THREE.Vector3,new THREE.Vector3(0,0,a));b.colors.push(new THREE.Color(16711680),new THREE.Color(16755200),new THREE.Color(65280),new THREE.Color(11206400),new THREE.Color(255),new THREE.Color(43775));a=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.Line.call(this,b,a,THREE.LinePieces)}; -THREE.AxisHelper.prototype=Object.create(THREE.Line.prototype);THREE.ArrowHelper=function(a,b,c,d){THREE.Object3D.call(this);void 0===d&&(d=16776960);void 0===c&&(c=1);this.position=b;b=new THREE.Geometry;b.vertices.push(new THREE.Vector3(0,0,0));b.vertices.push(new THREE.Vector3(0,1,0));this.line=new THREE.Line(b,new THREE.LineBasicMaterial({color:d}));this.line.matrixAutoUpdate=!1;this.add(this.line);b=new THREE.CylinderGeometry(0,0.05,0.25,5,1);b.applyMatrix((new THREE.Matrix4).makeTranslation(0,0.875,0));this.cone=new THREE.Mesh(b,new THREE.MeshBasicMaterial({color:d})); -this.cone.matrixAutoUpdate=!1;this.add(this.cone);this.setDirection(a);this.setLength(c)};THREE.ArrowHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.ArrowHelper.prototype.setDirection=function(){var a=new THREE.Vector3,b;return function(c){0.99999<c.y?this.quaternion.set(0,0,0,1):-0.99999>c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();THREE.ArrowHelper.prototype.setLength=function(a){this.scale.set(a,a,a)}; -THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a);this.cone.material.color.setHex(a)};THREE.BoxHelper=function(a){var b=[new THREE.Vector3(1,1,1),new THREE.Vector3(-1,1,1),new THREE.Vector3(-1,-1,1),new THREE.Vector3(1,-1,1),new THREE.Vector3(1,1,-1),new THREE.Vector3(-1,1,-1),new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,-1,-1)];this.vertices=b;var c=new THREE.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces); -void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype); -THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.vertices;d[0].set(b.x,b.y,b.z);d[1].set(c.x,b.y,b.z);d[2].set(c.x,c.y,b.z);d[3].set(b.x,c.y,b.z);d[4].set(b.x,b.y,c.z);d[5].set(c.x,b.y,c.z);d[6].set(c.x,c.y,c.z);d[7].set(b.x,c.y,c.z);this.geometry.computeBoundingSphere();this.geometry.verticesNeedUpdate=!0;this.matrixAutoUpdate=!1;this.matrixWorld=a.matrixWorld};THREE.BoundingBoxHelper=function(a,b){var c=b||8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.CubeGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)};THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200); -b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}; -THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); -THREE.CameraHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Camera,c=new THREE.Projector;return function(){function d(d,h,g,i){a.set(h,g,i);c.unprojectVector(a,b);d=e.pointMap[d];if(void 0!==d){h=0;for(g=d.length;h<g;h++)e.geometry.vertices[d[h]].copy(a)}}var e=this;b.projectionMatrix.copy(this.camera.projectionMatrix);d("c",0,0,-1);d("t",0,0,1);d("n1",-1,-1,-1);d("n2",1,-1,-1);d("n3",-1,1,-1);d("n4",1,1,-1);d("f1",-1,-1,1);d("f2",1,-1,1);d("f3",-1,1,1);d("f4",1,1,1);d("u1", -0.7,1.1,-1);d("u2",-0.7,1.1,-1);d("u3",0,2,-1);d("cf1",-1,0,1);d("cf2",1,0,1);d("cf3",0,-1,1);d("cf4",0,1,1);d("cn1",-1,0,-1);d("cn2",1,0,-1);d("cn3",0,-1,-1);d("cn4",0,1,-1);this.geometry.verticesNeedUpdate=!0}}();THREE.DirectionalLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;var c=new THREE.PlaneGeometry(b,b),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.lightPlane=new THREE.Mesh(c,d);this.add(this.lightPlane);c=new THREE.Geometry;c.vertices.push(new THREE.Vector3);c.vertices.push(new THREE.Vector3);c.computeLineDistances(); -d=new THREE.LineBasicMaterial({fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine=new THREE.Line(c,d);this.add(this.targetLine);this.update()};THREE.DirectionalLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose();this.lightPlane.material.dispose();this.targetLine.geometry.dispose();this.targetLine.material.dispose()}; -THREE.DirectionalLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){a.getPositionFromMatrix(this.light.matrixWorld).negate();this.lightPlane.lookAt(a);this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine.geometry.vertices[1].copy(a);this.targetLine.geometry.verticesNeedUpdate=!0;this.targetLine.material.color.copy(this.lightPlane.material.color)}}();THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=b||1;for(var a=c||16776960,d=d||1,b=new THREE.Geometry,c=0,e=this.object.geometry.faces.length;c<e;c++)b.vertices.push(new THREE.Vector3),b.vertices.push(new THREE.Vector3);THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:a,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.normalMatrix=new THREE.Matrix3;this.update()};THREE.FaceNormalsHelper.prototype=Object.create(THREE.Line.prototype); -THREE.FaceNormalsHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.object.updateMatrixWorld(!0);this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var b=this.geometry.vertices,c=this.object.geometry.faces,d=this.object.matrixWorld,e=0,f=c.length;e<f;e++){var h=c[e];a.copy(h.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size);var g=2*e;b[g].copy(h.centroid).applyMatrix4(d);b[g+1].addVectors(b[g],a)}this.geometry.verticesNeedUpdate= -!0;return this}}();THREE.GridHelper=function(a,b){var c=new THREE.Geometry,d=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});this.color1=new THREE.Color(4473924);this.color2=new THREE.Color(8947848);for(var e=-a;e<=a;e+=b){c.vertices.push(new THREE.Vector3(-a,0,e),new THREE.Vector3(a,0,e),new THREE.Vector3(e,0,-a),new THREE.Vector3(e,0,a));var f=0===e?this.color1:this.color2;c.colors.push(f,f,f,f)}THREE.Line.call(this,c,d,THREE.LinePieces)};THREE.GridHelper.prototype=Object.create(THREE.Line.prototype); -THREE.GridHelper.prototype.setColors=function(a,b){this.color1.set(a);this.color2.set(b);this.geometry.colorsNeedUpdate=!0};THREE.HemisphereLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.colors=[new THREE.Color,new THREE.Color];var c=new THREE.SphereGeometry(b,4,2);c.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));for(var d=0;8>d;d++)c.faces[d].color=this.colors[4>d?0:1];d=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(c,d);this.add(this.lightSphere); -this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; -THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.getPositionFromMatrix(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}();THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrixWorld=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()}; -THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)};THREE.SpotLightHelper=function(a){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;a=new THREE.CylinderGeometry(0,1,1,8,1,!0);a.applyMatrix((new THREE.Matrix4).makeTranslation(0,-0.5,0));a.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));var b=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new THREE.Mesh(a,b);this.add(this.cone);this.update()};THREE.SpotLightHelper.prototype=Object.create(THREE.Object3D.prototype); -THREE.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()};THREE.SpotLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){var c=this.light.distance?this.light.distance:1E4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c);a.getPositionFromMatrix(this.light.matrixWorld);b.getPositionFromMatrix(this.light.target.matrixWorld);this.cone.lookAt(b.sub(a));this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}();THREE.VertexNormalsHelper=function(a,b,c,d){this.object=a;this.size=b||1;for(var b=c||16711680,d=d||1,c=new THREE.Geometry,a=a.geometry.faces,e=0,f=a.length;e<f;e++)for(var h=0,g=a[e].vertexNormals.length;h<g;h++)c.vertices.push(new THREE.Vector3),c.vertices.push(new THREE.Vector3);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:b,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.normalMatrix=new THREE.Matrix3;this.update()};THREE.VertexNormalsHelper.prototype=Object.create(THREE.Line.prototype); -THREE.VertexNormalsHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){var b=["a","b","c","d"];this.object.updateMatrixWorld(!0);this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var c=this.geometry.vertices,d=this.object.geometry.vertices,e=this.object.geometry.faces,f=this.object.matrixWorld,h=0,g=0,i=e.length;g<i;g++)for(var k=e[g],m=0,l=k.vertexNormals.length;m<l;m++){var p=k.vertexNormals[m];c[h].copy(d[k[b[m]]]).applyMatrix4(f);a.copy(p).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size); -a.add(c[h]);h+=1;c[h].copy(a);h+=1}this.geometry.verticesNeedUpdate=!0;return this}}();THREE.VertexTangentsHelper=function(a,b,c,d){this.object=a;this.size=b||1;for(var b=c||255,d=d||1,c=new THREE.Geometry,a=a.geometry.faces,e=0,f=a.length;e<f;e++)for(var h=0,g=a[e].vertexTangents.length;h<g;h++)c.vertices.push(new THREE.Vector3),c.vertices.push(new THREE.Vector3);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:b,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.update()};THREE.VertexTangentsHelper.prototype=Object.create(THREE.Line.prototype); -THREE.VertexTangentsHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){var b=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var c=this.geometry.vertices,d=this.object.geometry.vertices,e=this.object.geometry.faces,f=this.object.matrixWorld,h=0,g=0,i=e.length;g<i;g++)for(var k=e[g],m=0,l=k.vertexTangents.length;m<l;m++){var p=k.vertexTangents[m];c[h].copy(d[k[b[m]]]).applyMatrix4(f);a.copy(p).transformDirection(f).multiplyScalar(this.size);a.add(c[h]);h+=1;c[h].copy(a); -h+=1}this.geometry.verticesNeedUpdate=!0;return this}}();THREE.WireframeHelper=function(a){for(var b=[0,0],c={},d=function(a,b){return a-b},e=["a","b","c","d"],f=new THREE.Geometry,h=a.geometry.vertices,g=a.geometry.faces,i=0,k=g.length;i<k;i++)for(var m=g[i],l=0;3>l;l++){b[0]=m[e[l]];b[1]=m[e[(l+1)%3]];b.sort(d);var p=b.toString();void 0===c[p]&&(f.vertices.push(h[b[0]]),f.vertices.push(h[b[1]]),c[p]=!0)}THREE.Line.call(this,f,new THREE.LineBasicMaterial({color:16777215}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.matrixWorld=a.matrixWorld}; -THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype); -THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; -THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;a<b;a++)c=this.lensFlares[a],c.x=this.positionScreen.x+d*c.distance,c.y=this.positionScreen.y+e*c.distance,c.wantedRotation=0.25*c.x*Math.PI,c.rotation+=0.25*(c.wantedRotation-c.rotation)};THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype); +THREE.KeyFrameAnimation.prototype={constructor:THREE.KeyFrameAnimation,play:function(a){this.currentTime=void 0!==a?a:0;if(!1===this.isPlaying){this.isPlaying=!0;var b=this.hierarchy.length,c,d;for(a=0;a<b;a++)c=this.hierarchy[a],d=this.data.hierarchy[a],void 0===d.animationCache&&(d.animationCache={},d.animationCache.prevKey=null,d.animationCache.nextKey=null,d.animationCache.originalMatrix=c.matrix),c=this.data.hierarchy[a].keys,c.length&&(d.animationCache.prevKey=c[0],d.animationCache.nextKey= +c[1],this.startTime=Math.min(c[0].time,this.startTime),this.endTime=Math.max(c[c.length-1].time,this.endTime));this.update(0)}this.isPaused=!1;THREE.AnimationHandler.play(this)},stop:function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.stop(this);for(var a=0;a<this.data.hierarchy.length;a++){var b=this.hierarchy[a],c=this.data.hierarchy[a];if(void 0!==c.animationCache){var d=c.animationCache.originalMatrix;d.copy(b.matrix);b.matrix=d;delete c.animationCache}}},update:function(a){if(!1!== +this.isPlaying){this.currentTime+=a*this.timeScale;a=this.data.length;!0===this.loop&&this.currentTime>a&&(this.currentTime%=a);this.currentTime=Math.min(this.currentTime,a);a=0;for(var b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a],d=this.data.hierarchy[a],e=d.keys,d=d.animationCache;if(e.length){var f=d.prevKey,g=d.nextKey;if(g.time<=this.currentTime){for(;g.time<this.currentTime&&g.index>f.index;)f=g,g=e[f.index+1];d.prevKey=f;d.nextKey=g}g.time>=this.currentTime?f.interpolate(g,this.currentTime): +f.interpolate(g,g.time);this.data.hierarchy[a].node.updateMatrix();c.matrixWorldNeedsUpdate=!0}}}},getNextKeyWith:function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;c<b.length;c++)if(b[c].hasTarget(a))return b[c];return b[0]},getPrevKeyWith:function(a,b,c){b=this.data.hierarchy[b].keys;for(c=0<=c?c:c+b.length;0<=c;c--)if(b[c].hasTarget(a))return b[c];return b[b.length-1]}}; +THREE.MorphAnimation=function(a){this.mesh=a;this.frames=a.morphTargetInfluences.length;this.currentTime=0;this.duration=1E3;this.loop=!0;this.currentFrame=this.lastFrame=0;this.isPlaying=!1}; +THREE.MorphAnimation.prototype={constructor:THREE.MorphAnimation,play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(a){if(!1!==this.isPlaying){this.currentTime+=a;!0===this.loop&&this.currentTime>this.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);a=this.duration/this.frames;var b=Math.floor(this.currentTime/a),c=this.mesh.morphTargetInfluences;b!=this.currentFrame&&(c[this.lastFrame]=0,c[this.currentFrame]= +1,c[b]=0,this.lastFrame=this.currentFrame,this.currentFrame=b);c[b]=this.currentTime%a/a;c[this.lastFrame]=1-c[b]}}}; +THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,s){var u,v=h.widthSegments,x=h.heightSegments,D=e/2,w=f/2,y=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)u="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)u="y",x=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)u="x",v=h.depthSegments;var A=v+1,E=x+1,G=e/v,F=f/x,z=new THREE.Vector3;z[u]=0<g?1:-1;for(e=0;e<E;e++)for(f=0;f<A;f++){var I=new THREE.Vector3;I[a]=(f*G-D)*c;I[b]=(e*F-w)*d;I[u]=g;h.vertices.push(I)}for(e= +0;e<x;e++)for(f=0;f<v;f++)w=f+A*e,a=f+A*(e+1),b=f+1+A*(e+1),c=f+1+A*e,d=new THREE.Vector2(f/v,1-e/x),g=new THREE.Vector2(f/v,1-(e+1)/x),u=new THREE.Vector2((f+1)/v,1-(e+1)/x),D=new THREE.Vector2((f+1)/v,1-e/x),w=new THREE.Face3(w+y,a+y,c+y),w.normal.copy(z),w.vertexNormals.push(z.clone(),z.clone(),z.clone()),w.materialIndex=s,h.faces.push(w),h.faceVertexUvs[0].push([d,g,D]),w=new THREE.Face3(a+y,b+y,c+y),w.normal.copy(z),w.vertexNormals.push(z.clone(),z.clone(),z.clone()),w.materialIndex=s,h.faces.push(w), +h.faceVertexUvs[0].push([g.clone(),u,D.clone()])}THREE.Geometry.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments=f||1;var h=this;d=a/2;e=b/2;f=c/2;g("z","y",-1,-1,c,b,d,0);g("z","y",1,-1,c,b,-d,1);g("x","z",1,1,a,c,e,2);g("x","z",1,-1,a,c,-e,3);g("x","y",1,-1,a,b,f,4);g("x","y",-1,-1,a,b,-f,5);this.mergeVertices()};THREE.BoxGeometry.prototype=Object.create(THREE.Geometry.prototype); +THREE.BoxGeometry.prototype.constructor=THREE.BoxGeometry; +THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="CircleGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e,f=[];e=new THREE.Vector3;var g=new THREE.Vector2(.5,.5);this.vertices.push(e);f.push(g);for(e=0;e<=b;e++){var h=new THREE.Vector3,k=c+e/b*d;h.x=a*Math.cos(k);h.y=a*Math.sin(k);this.vertices.push(h);f.push(new THREE.Vector2((h.x/a+1)/2,(h.y/a+1)/2))}c=new THREE.Vector3(0, +0,1);for(e=1;e<=b;e++)this.faces.push(new THREE.Face3(e,e+1,0,[c.clone(),c.clone(),c.clone()])),this.faceVertexUvs[0].push([f[e].clone(),f[e+1].clone(),g.clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CircleGeometry.prototype.constructor=THREE.CircleGeometry; +THREE.CubeGeometry=function(a,b,c,d,e,f){THREE.warn("THREE.CubeGeometry has been renamed to THREE.BoxGeometry.");return new THREE.BoxGeometry(a,b,c,d,e,f)}; +THREE.CylinderGeometry=function(a,b,c,d,e,f,g,h){THREE.Geometry.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};a=void 0!==a?a:20;b=void 0!==b?b:20;c=void 0!==c?c:100;d=d||8;e=e||1;f=void 0!==f?f:!1;g=void 0!==g?g:0;h=void 0!==h?h:2*Math.PI;var k=c/2,l,p,q=[],n=[];for(p=0;p<=e;p++){var t=[],r=[],s=p/e,u=s*(b-a)+a;for(l=0;l<=d;l++){var v=l/d,x=new THREE.Vector3;x.x=u*Math.sin(v*h+ +g);x.y=-s*c+k;x.z=u*Math.cos(v*h+g);this.vertices.push(x);t.push(this.vertices.length-1);r.push(new THREE.Vector2(v,1-s))}q.push(t);n.push(r)}c=(b-a)/c;for(l=0;l<d;l++)for(0!==a?(g=this.vertices[q[0][l]].clone(),h=this.vertices[q[0][l+1]].clone()):(g=this.vertices[q[1][l]].clone(),h=this.vertices[q[1][l+1]].clone()),g.setY(Math.sqrt(g.x*g.x+g.z*g.z)*c).normalize(),h.setY(Math.sqrt(h.x*h.x+h.z*h.z)*c).normalize(),p=0;p<e;p++){var t=q[p][l],r=q[p+1][l],s=q[p+1][l+1],u=q[p][l+1],v=g.clone(),x=g.clone(), +D=h.clone(),w=h.clone(),y=n[p][l].clone(),A=n[p+1][l].clone(),E=n[p+1][l+1].clone(),G=n[p][l+1].clone();this.faces.push(new THREE.Face3(t,r,u,[v,x,w]));this.faceVertexUvs[0].push([y,A,G]);this.faces.push(new THREE.Face3(r,s,u,[x.clone(),D,w.clone()]));this.faceVertexUvs[0].push([A.clone(),E,G.clone()])}if(!1===f&&0<a)for(this.vertices.push(new THREE.Vector3(0,k,0)),l=0;l<d;l++)t=q[0][l],r=q[0][l+1],s=this.vertices.length-1,v=new THREE.Vector3(0,1,0),x=new THREE.Vector3(0,1,0),D=new THREE.Vector3(0, +1,0),y=n[0][l].clone(),A=n[0][l+1].clone(),E=new THREE.Vector2(A.x,0),this.faces.push(new THREE.Face3(t,r,s,[v,x,D])),this.faceVertexUvs[0].push([y,A,E]);if(!1===f&&0<b)for(this.vertices.push(new THREE.Vector3(0,-k,0)),l=0;l<d;l++)t=q[e][l+1],r=q[e][l],s=this.vertices.length-1,v=new THREE.Vector3(0,-1,0),x=new THREE.Vector3(0,-1,0),D=new THREE.Vector3(0,-1,0),y=n[e][l+1].clone(),A=n[e][l].clone(),E=new THREE.Vector2(A.x,1),this.faces.push(new THREE.Face3(t,r,s,[v,x,D])),this.faceVertexUvs[0].push([y, +A,E]);this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),this.type="ExtrudeGeometry",a=a instanceof Array?a:[a],this.addShapeList(a,b),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry; +THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)}; +THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||THREE.error("THREE.ExtrudeGeometry: vec does not exist");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=1,d=a.x-b.x,e=a.y-b.y,f=c.x-a.x,g=c.y-a.y,h=d*d+e*e;if(1E-10<Math.abs(d*g-e*f)){var k=Math.sqrt(h),l=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;f=((c.x-g/l-h)*g-(c.y+f/l-b)*f)/(d*g-e*f);c=h+d*f-a.x;a=b+e*f-a.y;d=c*c+a*a;if(2>=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10<d?1E-10<f&&(a=!0): +-1E-10>d?-1E-10>f&&(a=!0):Math.sign(e)==Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(O=a.length;0<=--O;){c=O;d=O-1;0>d&&(d=a.length-1);for(var e=0,f=t+2*p,e=0;e<f;e++){var g=oa*e,h=oa*(e+1),k=b+c+g,g=b+d+g,l=b+d+h,h=b+c+h,k=k+U,g=g+U,l=l+U,h=h+U;I.faces.push(new THREE.Face3(k,g,h,null,null,x));I.faces.push(new THREE.Face3(g,l,h,null,null,x));k=D.generateSideWallUV(I,k,g,l,h);I.faceVertexUvs[0].push([k[0], +k[1],k[3]]);I.faceVertexUvs[0].push([k[1],k[2],k[3]])}}}function f(a,b,c){I.vertices.push(new THREE.Vector3(a,b,c))}function g(a,b,c){a+=U;b+=U;c+=U;I.faces.push(new THREE.Face3(a,b,c,null,null,v));a=D.generateTopUV(I,a,b,c);I.faceVertexUvs[0].push(a)}var h=void 0!==b.amount?b.amount:100,k=void 0!==b.bevelThickness?b.bevelThickness:6,l=void 0!==b.bevelSize?b.bevelSize:k-2,p=void 0!==b.bevelSegments?b.bevelSegments:3,q=void 0!==b.bevelEnabled?b.bevelEnabled:!0,n=void 0!==b.curveSegments?b.curveSegments: +12,t=void 0!==b.steps?b.steps:1,r=b.extrudePath,s,u=!1,v=b.material,x=b.extrudeMaterial,D=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,w,y,A,E;r&&(s=r.getSpacedPoints(t),u=!0,q=!1,w=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(r,t,!1),y=new THREE.Vector3,A=new THREE.Vector3,E=new THREE.Vector3);q||(l=k=p=0);var G,F,z,I=this,U=this.vertices.length,r=a.extractPoints(n),n=r.shape,M=r.holes;if(r=!THREE.Shape.Utils.isClockWise(n)){n=n.reverse();F=0;for(z= +M.length;F<z;F++)G=M[F],THREE.Shape.Utils.isClockWise(G)&&(M[F]=G.reverse());r=!1}var H=THREE.Shape.Utils.triangulateShape(n,M),L=n;F=0;for(z=M.length;F<z;F++)G=M[F],n=n.concat(G);var P,N,R,V,J,oa=n.length,ja,ha=H.length,r=[],O=0;R=L.length;P=R-1;for(N=O+1;O<R;O++,P++,N++)P===R&&(P=0),N===R&&(N=0),r[O]=d(L[O],L[P],L[N]);var ca=[],ba,qa=r.concat();F=0;for(z=M.length;F<z;F++){G=M[F];ba=[];O=0;R=G.length;P=R-1;for(N=O+1;O<R;O++,P++,N++)P===R&&(P=0),N===R&&(N=0),ba[O]=d(G[O],G[P],G[N]);ca.push(ba);qa= +qa.concat(ba)}for(P=0;P<p;P++){R=P/p;V=k*(1-R);N=l*Math.sin(R*Math.PI/2);O=0;for(R=L.length;O<R;O++)J=c(L[O],r[O],N),f(J.x,J.y,-V);F=0;for(z=M.length;F<z;F++)for(G=M[F],ba=ca[F],O=0,R=G.length;O<R;O++)J=c(G[O],ba[O],N),f(J.x,J.y,-V)}N=l;for(O=0;O<oa;O++)J=q?c(n[O],qa[O],N):n[O],u?(A.copy(w.normals[0]).multiplyScalar(J.x),y.copy(w.binormals[0]).multiplyScalar(J.y),E.copy(s[0]).add(A).add(y),f(E.x,E.y,E.z)):f(J.x,J.y,0);for(R=1;R<=t;R++)for(O=0;O<oa;O++)J=q?c(n[O],qa[O],N):n[O],u?(A.copy(w.normals[R]).multiplyScalar(J.x), +y.copy(w.binormals[R]).multiplyScalar(J.y),E.copy(s[R]).add(A).add(y),f(E.x,E.y,E.z)):f(J.x,J.y,h/t*R);for(P=p-1;0<=P;P--){R=P/p;V=k*(1-R);N=l*Math.sin(R*Math.PI/2);O=0;for(R=L.length;O<R;O++)J=c(L[O],r[O],N),f(J.x,J.y,h+V);F=0;for(z=M.length;F<z;F++)for(G=M[F],ba=ca[F],O=0,R=G.length;O<R;O++)J=c(G[O],ba[O],N),u?f(J.x,J.y+s[t-1].y,s[t-1].x+V):f(J.x,J.y,h+V)}(function(){if(q){var a;a=0*oa;for(O=0;O<ha;O++)ja=H[O],g(ja[2]+a,ja[1]+a,ja[0]+a);a=t+2*p;a*=oa;for(O=0;O<ha;O++)ja=H[O],g(ja[0]+a,ja[1]+a,ja[2]+ +a)}else{for(O=0;O<ha;O++)ja=H[O],g(ja[2],ja[1],ja[0]);for(O=0;O<ha;O++)ja=H[O],g(ja[0]+oa*t,ja[1]+oa*t,ja[2]+oa*t)}})();(function(){var a=0;e(L,a);a+=L.length;F=0;for(z=M.length;F<z;F++)G=M[F],e(G,a),a+=G.length})()}; +THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d){a=a.vertices;b=a[b];c=a[c];d=a[d];return[new THREE.Vector2(b.x,b.y),new THREE.Vector2(c.x,c.y),new THREE.Vector2(d.x,d.y)]},generateSideWallUV:function(a,b,c,d,e){a=a.vertices;b=a[b];c=a[c];d=a[d];e=a[e];return.01>Math.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y, +1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===a instanceof Array&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.constructor=THREE.ShapeGeometry;THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this}; +THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,f,g,h=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var k=e.shape,l=e.holes;if(!THREE.Shape.Utils.isClockWise(k))for(k=k.reverse(),e=0,f=l.length;e<f;e++)g=l[e],THREE.Shape.Utils.isClockWise(g)&&(l[e]=g.reverse());var p=THREE.Shape.Utils.triangulateShape(k,l);e=0;for(f=l.length;e<f;e++)g=l[e], +k=k.concat(g);l=k.length;f=p.length;for(e=0;e<l;e++)g=k[e],this.vertices.push(new THREE.Vector3(g.x,g.y,0));for(e=0;e<f;e++)l=p[e],k=l[0]+h,g=l[1]+h,l=l[2]+h,this.faces.push(new THREE.Face3(k,g,l,null,null,c)),this.faceVertexUvs[0].push(d.generateTopUV(this,k,g,l))}; +THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="LatheGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};b=b||12;c=c||0;d=d||2*Math.PI;for(var e=1/(a.length-1),f=1/b,g=0,h=b;g<=h;g++)for(var k=c+g*f*d,l=Math.cos(k),p=Math.sin(k),k=0,q=a.length;k<q;k++){var n=a[k],t=new THREE.Vector3;t.x=l*n.x-p*n.y;t.y=p*n.x+l*n.y;t.z=n.z;this.vertices.push(t)}c=a.length;g=0;for(h=b;g<h;g++)for(k=0,q=a.length-1;k<q;k++){b=p=k+c*g;d=p+c;var l=p+1+c,p=p+1,n=g*f,t=k*e,r= +n+f,s=t+e;this.faces.push(new THREE.Face3(b,d,p));this.faceVertexUvs[0].push([new THREE.Vector2(n,t),new THREE.Vector2(r,t),new THREE.Vector2(n,s)]);this.faces.push(new THREE.Face3(d,l,p));this.faceVertexUvs[0].push([new THREE.Vector2(r,t),new THREE.Vector2(r,s),new THREE.Vector2(n,s)])}this.mergeVertices();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.LatheGeometry.prototype.constructor=THREE.LatheGeometry; +THREE.PlaneGeometry=function(a,b,c,d){console.info("THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.");THREE.Geometry.call(this);this.type="PlaneGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};this.fromBufferGeometry(new THREE.PlaneBufferGeometry(a,b,c,d))};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry.prototype.constructor=THREE.PlaneGeometry; +THREE.PlaneBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="PlaneBufferGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};var e=a/2,f=b/2;c=c||1;d=d||1;var g=c+1,h=d+1,k=a/c,l=b/d;b=new Float32Array(g*h*3);a=new Float32Array(g*h*3);for(var p=new Float32Array(g*h*2),q=0,n=0,t=0;t<h;t++)for(var r=t*l-f,s=0;s<g;s++)b[q]=s*k-e,b[q+1]=-r,a[q+2]=1,p[n]=s/c,p[n+1]=1-t/d,q+=3,n+=2;q=0;e=new (65535<b.length/3?Uint32Array:Uint16Array)(c*d*6);for(t=0;t<d;t++)for(s= +0;s<c;s++)f=s+g*(t+1),h=s+1+g*(t+1),k=s+1+g*t,e[q]=s+g*t,e[q+1]=f,e[q+2]=k,e[q+3]=f,e[q+4]=h,e[q+5]=k,q+=6;this.addAttribute("index",new THREE.BufferAttribute(e,1));this.addAttribute("position",new THREE.BufferAttribute(b,3));this.addAttribute("normal",new THREE.BufferAttribute(a,3));this.addAttribute("uv",new THREE.BufferAttribute(p,2))};THREE.PlaneBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.PlaneBufferGeometry.prototype.constructor=THREE.PlaneBufferGeometry; +THREE.RingGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="RingGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:f};a=a||0;b=b||50;e=void 0!==e?e:0;f=void 0!==f?f:2*Math.PI;c=void 0!==c?Math.max(3,c):8;d=void 0!==d?Math.max(1,d):8;var g,h=[],k=a,l=(b-a)/d;for(a=0;a<d+1;a++){for(g=0;g<c+1;g++){var p=new THREE.Vector3,q=e+g/c*f;p.x=k*Math.cos(q);p.y=k*Math.sin(q);this.vertices.push(p);h.push(new THREE.Vector2((p.x/b+1)/2, +(p.y/b+1)/2))}k+=l}b=new THREE.Vector3(0,0,1);for(a=0;a<d;a++)for(e=a*(c+1),g=0;g<c;g++)f=q=g+e,l=q+c+1,p=q+c+2,this.faces.push(new THREE.Face3(f,l,p,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[p].clone()]),f=q,l=q+c+2,p=q+1,this.faces.push(new THREE.Face3(f,l,p,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[p].clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,k)}; +THREE.RingGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.RingGeometry.prototype.constructor=THREE.RingGeometry; +THREE.SphereGeometry=function(a,b,c,d,e,f,g){THREE.Geometry.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||50;b=Math.max(3,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h,k,l=[],p=[];for(k=0;k<=c;k++){var q=[],n=[];for(h=0;h<=b;h++){var t=h/b,r=k/c,s=new THREE.Vector3;s.x=-a*Math.cos(d+t*e)*Math.sin(f+r*g); +s.y=a*Math.cos(f+r*g);s.z=a*Math.sin(d+t*e)*Math.sin(f+r*g);this.vertices.push(s);q.push(this.vertices.length-1);n.push(new THREE.Vector2(t,1-r))}l.push(q);p.push(n)}for(k=0;k<c;k++)for(h=0;h<b;h++){d=l[k][h+1];e=l[k][h];f=l[k+1][h];g=l[k+1][h+1];var q=this.vertices[d].clone().normalize(),n=this.vertices[e].clone().normalize(),t=this.vertices[f].clone().normalize(),r=this.vertices[g].clone().normalize(),s=p[k][h+1].clone(),u=p[k][h].clone(),v=p[k+1][h].clone(),x=p[k+1][h+1].clone();Math.abs(this.vertices[d].y)=== +a?(s.x=(s.x+u.x)/2,this.faces.push(new THREE.Face3(d,f,g,[q,t,r])),this.faceVertexUvs[0].push([s,v,x])):Math.abs(this.vertices[f].y)===a?(v.x=(v.x+x.x)/2,this.faces.push(new THREE.Face3(d,e,f,[q,n,t])),this.faceVertexUvs[0].push([s,u,v])):(this.faces.push(new THREE.Face3(d,e,g,[q,n,r])),this.faceVertexUvs[0].push([s,u,x]),this.faces.push(new THREE.Face3(e,f,g,[n.clone(),t,r.clone()])),this.faceVertexUvs[0].push([u.clone(),v,x.clone()]))}this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3, +a)};THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;THREE.TextGeometry=function(a,b){b=b||{};var c=THREE.FontUtils.generateShapes(a,b);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);THREE.ExtrudeGeometry.call(this,c,b);this.type="TextGeometry"};THREE.TextGeometry.prototype=Object.create(THREE.ExtrudeGeometry.prototype); +THREE.TextGeometry.prototype.constructor=THREE.TextGeometry; +THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.type="TorusGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};a=a||100;b=b||40;c=c||8;d=d||6;e=e||2*Math.PI;for(var f=new THREE.Vector3,g=[],h=[],k=0;k<=c;k++)for(var l=0;l<=d;l++){var p=l/d*e,q=k/c*Math.PI*2;f.x=a*Math.cos(p);f.y=a*Math.sin(p);var n=new THREE.Vector3;n.x=(a+b*Math.cos(q))*Math.cos(p);n.y=(a+b*Math.cos(q))*Math.sin(p);n.z=b*Math.sin(q);this.vertices.push(n);g.push(new THREE.Vector2(l/ +d,k/c));h.push(n.clone().sub(f).normalize())}for(k=1;k<=c;k++)for(l=1;l<=d;l++)a=(d+1)*k+l-1,b=(d+1)*(k-1)+l-1,e=(d+1)*(k-1)+l,f=(d+1)*k+l,p=new THREE.Face3(a,b,f,[h[a].clone(),h[b].clone(),h[f].clone()]),this.faces.push(p),this.faceVertexUvs[0].push([g[a].clone(),g[b].clone(),g[f].clone()]),p=new THREE.Face3(b,e,f,[h[b].clone(),h[e].clone(),h[f].clone()]),this.faces.push(p),this.faceVertexUvs[0].push([g[b].clone(),g[e].clone(),g[f].clone()]);this.computeFaceNormals()}; +THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry; +THREE.TorusKnotGeometry=function(a,b,c,d,e,f,g){function h(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a);a*=b/c;b=Math.cos(a);f*=d*(2+b)*.5;g=d*(2+b)*g*.5;d=e*d*Math.sin(a)*.5;return new THREE.Vector3(f,g,d)}THREE.Geometry.call(this);this.type="TorusKnotGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,p:e,q:f,heightScale:g};a=a||100;b=b||40;c=c||64;d=d||8;e=e||2;f=f||3;g=g||1;for(var k=Array(c),l=new THREE.Vector3,p=new THREE.Vector3,q=new THREE.Vector3,n=0;n<c;++n){k[n]= +Array(d);var t=n/c*2*e*Math.PI,r=h(t,f,e,a,g),t=h(t+.01,f,e,a,g);l.subVectors(t,r);p.addVectors(t,r);q.crossVectors(l,p);p.crossVectors(q,l);q.normalize();p.normalize();for(t=0;t<d;++t){var s=t/d*2*Math.PI,u=-b*Math.cos(s),s=b*Math.sin(s),v=new THREE.Vector3;v.x=r.x+u*p.x+s*q.x;v.y=r.y+u*p.y+s*q.y;v.z=r.z+u*p.z+s*q.z;k[n][t]=this.vertices.push(v)-1}}for(n=0;n<c;++n)for(t=0;t<d;++t)e=(n+1)%c,f=(t+1)%d,a=k[n][t],b=k[e][t],e=k[e][f],f=k[n][f],g=new THREE.Vector2(n/c,t/d),l=new THREE.Vector2((n+1)/c, +t/d),p=new THREE.Vector2((n+1)/c,(t+1)/d),q=new THREE.Vector2(n/c,(t+1)/d),this.faces.push(new THREE.Face3(a,b,f)),this.faceVertexUvs[0].push([g,l,q]),this.faces.push(new THREE.Face3(b,e,f)),this.faceVertexUvs[0].push([l.clone(),p,q.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry.prototype.constructor=THREE.TorusKnotGeometry; +THREE.TubeGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="TubeGeometry";this.parameters={path:a,segments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;f=f||THREE.TubeGeometry.NoTaper;var g=[],h,k,l=b+1,p,q,n,t,r,s=new THREE.Vector3,u,v,x;u=new THREE.TubeGeometry.FrenetFrames(a,b,e);v=u.normals;x=u.binormals;this.tangents=u.tangents;this.normals=v;this.binormals=x;for(u=0;u<l;u++)for(g[u]=[],p=u/(l-1),r=a.getPointAt(p),h=v[u],k=x[u],n=c*f(p),p=0;p<d;p++)q= +p/d*2*Math.PI,t=-n*Math.cos(q),q=n*Math.sin(q),s.copy(r),s.x+=t*h.x+q*k.x,s.y+=t*h.y+q*k.y,s.z+=t*h.z+q*k.z,g[u][p]=this.vertices.push(new THREE.Vector3(s.x,s.y,s.z))-1;for(u=0;u<b;u++)for(p=0;p<d;p++)f=e?(u+1)%b:u+1,l=(p+1)%d,a=g[u][p],c=g[f][p],f=g[f][l],l=g[u][l],s=new THREE.Vector2(u/b,p/d),v=new THREE.Vector2((u+1)/b,p/d),x=new THREE.Vector2((u+1)/b,(p+1)/d),h=new THREE.Vector2(u/b,(p+1)/d),this.faces.push(new THREE.Face3(a,c,l)),this.faceVertexUvs[0].push([s,v,h]),this.faces.push(new THREE.Face3(c, +f,l)),this.faceVertexUvs[0].push([v.clone(),x,h.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry.prototype.constructor=THREE.TubeGeometry;THREE.TubeGeometry.NoTaper=function(a){return 1};THREE.TubeGeometry.SinusoidalTaper=function(a){return Math.sin(Math.PI*a)}; +THREE.TubeGeometry.FrenetFrames=function(a,b,c){var d=new THREE.Vector3,e=[],f=[],g=[],h=new THREE.Vector3,k=new THREE.Matrix4;b+=1;var l,p,q;this.tangents=e;this.normals=f;this.binormals=g;for(l=0;l<b;l++)p=l/(b-1),e[l]=a.getTangentAt(p),e[l].normalize();f[0]=new THREE.Vector3;g[0]=new THREE.Vector3;a=Number.MAX_VALUE;l=Math.abs(e[0].x);p=Math.abs(e[0].y);q=Math.abs(e[0].z);l<=a&&(a=l,d.set(1,0,0));p<=a&&(a=p,d.set(0,1,0));q<=a&&d.set(0,0,1);h.crossVectors(e[0],d).normalize();f[0].crossVectors(e[0], +h);g[0].crossVectors(e[0],f[0]);for(l=1;l<b;l++)f[l]=f[l-1].clone(),g[l]=g[l-1].clone(),h.crossVectors(e[l-1],e[l]),1E-4<h.length()&&(h.normalize(),d=Math.acos(THREE.Math.clamp(e[l-1].dot(e[l]),-1,1)),f[l].applyMatrix4(k.makeRotationAxis(h,d))),g[l].crossVectors(e[l],f[l]);if(c)for(d=Math.acos(THREE.Math.clamp(f[0].dot(f[b-1]),-1,1)),d/=b-1,0<e[0].dot(h.crossVectors(f[0],f[b-1]))&&(d=-d),l=1;l<b;l++)f[l].applyMatrix4(k.makeRotationAxis(e[l],d*l)),g[l].crossVectors(e[l],f[l])}; +THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=k.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+.5;a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+.5;b.uv=new THREE.Vector2(c,1-a);return b}function f(a,b,c){var d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);k.faces.push(d);u.copy(a).add(b).add(c).divideScalar(3);d=Math.atan2(u.z,-u.x);k.faceVertexUvs[0].push([h(a.uv,a,d),h(b.uv,b,d),h(c.uv,c,d)])}function g(a, +b){for(var c=Math.pow(2,b),d=e(k.vertices[a.a]),g=e(k.vertices[a.b]),h=e(k.vertices[a.c]),l=[],n=0;n<=c;n++){l[n]=[];for(var p=e(d.clone().lerp(h,n/c)),q=e(g.clone().lerp(h,n/c)),s=c-n,r=0;r<=s;r++)l[n][r]=0==r&&n==c?p:e(p.clone().lerp(q,r/s))}for(n=0;n<c;n++)for(r=0;r<2*(c-n)-1;r++)d=Math.floor(r/2),0==r%2?f(l[n][d+1],l[n+1][d],l[n][d]):f(l[n][d+1],l[n+1][d+1],l[n+1][d])}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5,a.y));return a.clone()} +THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,l=0,p=a.length;l<p;l+=3)e(new THREE.Vector3(a[l],a[l+1],a[l+2]));a=this.vertices;for(var q=[],n=l=0,p=b.length;l<p;l+=3,n++){var t=a[b[l]],r=a[b[l+1]],s=a[b[l+2]];q[n]=new THREE.Face3(t.index,r.index,s.index,[t.clone(),r.clone(),s.clone()])}for(var u=new THREE.Vector3,l=0,p=q.length;l<p;l++)g(q[l],d);l=0;for(p=this.faceVertexUvs[0].length;l<p;l++)b=this.faceVertexUvs[0][l], +d=b[0].x,a=b[1].x,q=b[2].x,n=Math.max(d,Math.max(a,q)),t=Math.min(d,Math.min(a,q)),.9<n&&.1>t&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));l=0;for(p=this.vertices.length;l<p;l++)this.vertices[l].multiplyScalar(c);this.mergeVertices();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PolyhedronGeometry.prototype.constructor=THREE.PolyhedronGeometry; +THREE.DodecahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};var c=(1+Math.sqrt(5))/2,d=1/c;THREE.PolyhedronGeometry.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19, +11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b)};THREE.DodecahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.DodecahedronGeometry.prototype.constructor=THREE.DodecahedronGeometry; +THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b}};THREE.IcosahedronGeometry.prototype=Object.create(THREE.Geometry.prototype); +THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;THREE.OctahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};THREE.PolyhedronGeometry.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b}};THREE.OctahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry; +THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b}};THREE.TetrahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry; +THREE.ParametricGeometry=function(a,b,c){THREE.Geometry.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};var d=this.vertices,e=this.faces,f=this.faceVertexUvs[0],g,h,k,l,p=b+1;for(g=0;g<=c;g++)for(l=g/c,h=0;h<=b;h++)k=h/b,k=a(k,l),d.push(k);var q,n,t,r;for(g=0;g<c;g++)for(h=0;h<b;h++)a=g*p+h,d=g*p+h+1,l=(g+1)*p+h+1,k=(g+1)*p+h,q=new THREE.Vector2(h/b,g/c),n=new THREE.Vector2((h+1)/b,g/c),t=new THREE.Vector2((h+1)/b,(g+1)/c),r=new THREE.Vector2(h/b,(g+1)/c),e.push(new THREE.Face3(a, +d,k)),f.push([q,n,r]),e.push(new THREE.Face3(d,l,k)),f.push([n.clone(),t,r.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry; +THREE.AxisHelper=function(a){a=a||1;var b=new Float32Array([0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a]),c=new Float32Array([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1]);a=new THREE.BufferGeometry;a.addAttribute("position",new THREE.BufferAttribute(b,3));a.addAttribute("color",new THREE.BufferAttribute(c,3));b=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.Line.call(this,a,b,THREE.LinePieces)};THREE.AxisHelper.prototype=Object.create(THREE.Line.prototype); +THREE.AxisHelper.prototype.constructor=THREE.AxisHelper; +THREE.ArrowHelper=function(){var a=new THREE.Geometry;a.vertices.push(new THREE.Vector3(0,0,0),new THREE.Vector3(0,1,0));var b=new THREE.CylinderGeometry(0,.5,1,5,1);b.applyMatrix((new THREE.Matrix4).makeTranslation(0,-.5,0));return function(c,d,e,f,g,h){THREE.Object3D.call(this);void 0===f&&(f=16776960);void 0===e&&(e=1);void 0===g&&(g=.2*e);void 0===h&&(h=.2*g);this.position.copy(d);this.line=new THREE.Line(a,new THREE.LineBasicMaterial({color:f}));this.line.matrixAutoUpdate=!1;this.add(this.line); +this.cone=new THREE.Mesh(b,new THREE.MeshBasicMaterial({color:f}));this.cone.matrixAutoUpdate=!1;this.add(this.cone);this.setDirection(c);this.setLength(e,g,h)}}();THREE.ArrowHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.ArrowHelper.prototype.constructor=THREE.ArrowHelper; +THREE.ArrowHelper.prototype.setDirection=function(){var a=new THREE.Vector3,b;return function(c){.99999<c.y?this.quaternion.set(0,0,0,1):-.99999>c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();THREE.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,a-b,1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()}; +THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)};THREE.BoxHelper=function(a){var b=new THREE.BufferGeometry;b.addAttribute("position",new THREE.BufferAttribute(new Float32Array(72),3));THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces);void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype);THREE.BoxHelper.prototype.constructor=THREE.BoxHelper; +THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.geometry.attributes.position.array;d[0]=b.x;d[1]=b.y;d[2]=b.z;d[3]=c.x;d[4]=b.y;d[5]=b.z;d[6]=c.x;d[7]=b.y;d[8]=b.z;d[9]=c.x;d[10]=c.y;d[11]=b.z;d[12]=c.x;d[13]=c.y;d[14]=b.z;d[15]=b.x;d[16]=c.y;d[17]=b.z;d[18]=b.x;d[19]=c.y;d[20]=b.z;d[21]=b.x;d[22]=b.y;d[23]=b.z;d[24]=b.x;d[25]=b.y;d[26]=c.z;d[27]=c.x;d[28]=b.y;d[29]=c.z;d[30]=c.x;d[31]=b.y; +d[32]=c.z;d[33]=c.x;d[34]=c.y;d[35]=c.z;d[36]=c.x;d[37]=c.y;d[38]=c.z;d[39]=b.x;d[40]=c.y;d[41]=c.z;d[42]=b.x;d[43]=c.y;d[44]=c.z;d[45]=b.x;d[46]=b.y;d[47]=c.z;d[48]=b.x;d[49]=b.y;d[50]=b.z;d[51]=b.x;d[52]=b.y;d[53]=c.z;d[54]=c.x;d[55]=b.y;d[56]=b.z;d[57]=c.x;d[58]=b.y;d[59]=c.z;d[60]=c.x;d[61]=c.y;d[62]=b.z;d[63]=c.x;d[64]=c.y;d[65]=c.z;d[66]=b.x;d[67]=c.y;d[68]=b.z;d[69]=b.x;d[70]=c.y;d[71]=c.z;this.geometry.attributes.position.needsUpdate=!0;this.geometry.computeBoundingSphere();this.matrix=a.matrixWorld; +this.matrixAutoUpdate=!1};THREE.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.constructor=THREE.BoundingBoxHelper;THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)}; +THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200); +b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}; +THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype);THREE.CameraHelper.prototype.constructor=THREE.CameraHelper; +THREE.CameraHelper.prototype.update=function(){var a,b,c=new THREE.Vector3,d=new THREE.Camera,e=function(e,g,h,k){c.set(g,h,k).unproject(d);e=b[e];if(void 0!==e)for(g=0,h=e.length;g<h;g++)a.vertices[e[g]].copy(c)};return function(){a=this.geometry;b=this.pointMap;d.projectionMatrix.copy(this.camera.projectionMatrix);e("c",0,0,-1);e("t",0,0,1);e("n1",-1,-1,-1);e("n2",1,-1,-1);e("n3",-1,1,-1);e("n4",1,1,-1);e("f1",-1,-1,1);e("f2",1,-1,1);e("f3",-1,1,1);e("f4",1,1,1);e("u1",.7,1.1,-1);e("u2",-.7,1.1, +-1);e("u3",0,2,-1);e("cf1",-1,0,1);e("cf2",1,0,1);e("cf3",0,-1,1);e("cf4",0,1,1);e("cn1",-1,0,-1);e("cn2",1,0,-1);e("cn3",0,-1,-1);e("cn4",0,1,-1);a.verticesNeedUpdate=!0}}(); +THREE.DirectionalLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;b=b||1;var c=new THREE.Geometry;c.vertices.push(new THREE.Vector3(-b,b,0),new THREE.Vector3(b,b,0),new THREE.Vector3(b,-b,0),new THREE.Vector3(-b,-b,0),new THREE.Vector3(-b,b,0));var d=new THREE.LineBasicMaterial({fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.lightPlane=new THREE.Line(c,d);this.add(this.lightPlane); +c=new THREE.Geometry;c.vertices.push(new THREE.Vector3,new THREE.Vector3);d=new THREE.LineBasicMaterial({fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine=new THREE.Line(c,d);this.add(this.targetLine);this.update()};THREE.DirectionalLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.DirectionalLightHelper.prototype.constructor=THREE.DirectionalLightHelper; +THREE.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose();this.lightPlane.material.dispose();this.targetLine.geometry.dispose();this.targetLine.material.dispose()}; +THREE.DirectionalLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);c.subVectors(b,a);this.lightPlane.lookAt(c);this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity);this.targetLine.geometry.vertices[1].copy(c);this.targetLine.geometry.verticesNeedUpdate=!0;this.targetLine.material.color.copy(this.lightPlane.material.color)}}(); +THREE.EdgesHelper=function(a,b,c){b=void 0!==b?b:16777215;c=Math.cos(THREE.Math.degToRad(void 0!==c?c:1));var d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h=new THREE.BufferGeometry,k;a.geometry instanceof THREE.BufferGeometry?(k=new THREE.Geometry,k.fromBufferGeometry(a.geometry)):k=a.geometry.clone();k.mergeVertices();k.computeFaceNormals();var l=k.vertices;k=k.faces;for(var p=0,q=0,n=k.length;q<n;q++)for(var t=k[q],r=0;3>r;r++){d[0]=t[g[r]];d[1]=t[g[(r+1)%3]];d.sort(f);var s=d.toString(); +void 0===e[s]?(e[s]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[s].face2=q}d=new Float32Array(6*p);f=0;for(s in e)if(g=e[s],void 0===g.face2||k[g.face1].normal.dot(k[g.face2].normal)<=c)p=l[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=l[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:b}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1}; +THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype);THREE.EdgesHelper.prototype.constructor=THREE.EdgesHelper; +THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=new THREE.Geometry;c=0;for(var e=this.object.geometry.faces.length;c<e;c++)b.vertices.push(new THREE.Vector3,new THREE.Vector3);THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:a,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.normalMatrix=new THREE.Matrix3;this.update()};THREE.FaceNormalsHelper.prototype=Object.create(THREE.Line.prototype); +THREE.FaceNormalsHelper.prototype.constructor=THREE.FaceNormalsHelper; +THREE.FaceNormalsHelper.prototype.update=function(){var a=this.geometry.vertices,b=this.object,c=b.geometry.vertices,d=b.geometry.faces,e=b.matrixWorld;b.updateMatrixWorld(!0);this.normalMatrix.getNormalMatrix(e);for(var f=b=0,g=d.length;b<g;b++,f+=2){var h=d[b];a[f].copy(c[h.a]).add(c[h.b]).add(c[h.c]).divideScalar(3).applyMatrix4(e);a[f+1].copy(h.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size).add(a[f])}this.geometry.verticesNeedUpdate=!0;return this}; +THREE.GridHelper=function(a,b){var c=new THREE.Geometry,d=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});this.color1=new THREE.Color(4473924);this.color2=new THREE.Color(8947848);for(var e=-a;e<=a;e+=b){c.vertices.push(new THREE.Vector3(-a,0,e),new THREE.Vector3(a,0,e),new THREE.Vector3(e,0,-a),new THREE.Vector3(e,0,a));var f=0===e?this.color1:this.color2;c.colors.push(f,f,f,f)}THREE.Line.call(this,c,d,THREE.LinePieces)};THREE.GridHelper.prototype=Object.create(THREE.Line.prototype); +THREE.GridHelper.prototype.constructor=THREE.GridHelper;THREE.GridHelper.prototype.setColors=function(a,b){this.color1.set(a);this.color2.set(b);this.geometry.colorsNeedUpdate=!0}; +THREE.HemisphereLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.colors=[new THREE.Color,new THREE.Color];var c=new THREE.SphereGeometry(b,4,2);c.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));for(var d=0;8>d;d++)c.faces[d].color=this.colors[4>d?0:1];d=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(c,d);this.add(this.lightSphere); +this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.constructor=THREE.HemisphereLightHelper;THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; +THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}(); +THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.constructor=THREE.PointLightHelper; +THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()};THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}; +THREE.SkeletonHelper=function(a){this.bones=this.getBoneList(a);for(var b=new THREE.Geometry,c=0;c<this.bones.length;c++)this.bones[c].parent instanceof THREE.Bone&&(b.vertices.push(new THREE.Vector3),b.vertices.push(new THREE.Vector3),b.colors.push(new THREE.Color(0,0,1)),b.colors.push(new THREE.Color(0,1,0)));c=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors,depthTest:!1,depthWrite:!1,transparent:!0});THREE.Line.call(this,b,c,THREE.LinePieces);this.root=a;this.matrix=a.matrixWorld; +this.matrixAutoUpdate=!1;this.update()};THREE.SkeletonHelper.prototype=Object.create(THREE.Line.prototype);THREE.SkeletonHelper.prototype.constructor=THREE.SkeletonHelper;THREE.SkeletonHelper.prototype.getBoneList=function(a){var b=[];a instanceof THREE.Bone&&b.push(a);for(var c=0;c<a.children.length;c++)b.push.apply(b,this.getBoneList(a.children[c]));return b}; +THREE.SkeletonHelper.prototype.update=function(){for(var a=this.geometry,b=(new THREE.Matrix4).getInverse(this.root.matrixWorld),c=new THREE.Matrix4,d=0,e=0;e<this.bones.length;e++){var f=this.bones[e];f.parent instanceof THREE.Bone&&(c.multiplyMatrices(b,f.matrixWorld),a.vertices[d].setFromMatrixPosition(c),c.multiplyMatrices(b,f.parent.matrixWorld),a.vertices[d+1].setFromMatrixPosition(c),d+=2)}a.verticesNeedUpdate=!0;a.computeBoundingSphere()}; +THREE.SpotLightHelper=function(a){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;a=new THREE.CylinderGeometry(0,1,1,8,1,!0);a.applyMatrix((new THREE.Matrix4).makeTranslation(0,-.5,0));a.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));var b=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new THREE.Mesh(a,b);this.add(this.cone);this.update()};THREE.SpotLightHelper.prototype=Object.create(THREE.Object3D.prototype); +THREE.SpotLightHelper.prototype.constructor=THREE.SpotLightHelper;THREE.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()}; +THREE.SpotLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){var c=this.light.distance?this.light.distance:1E4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c);a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);this.cone.lookAt(b.sub(a));this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}(); +THREE.VertexNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;b=void 0!==c?c:16711680;d=void 0!==d?d:1;c=new THREE.Geometry;a=a.geometry.faces;for(var e=0,f=a.length;e<f;e++)for(var g=0,h=a[e].vertexNormals.length;g<h;g++)c.vertices.push(new THREE.Vector3,new THREE.Vector3);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:b,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.normalMatrix=new THREE.Matrix3;this.update()};THREE.VertexNormalsHelper.prototype=Object.create(THREE.Line.prototype); +THREE.VertexNormalsHelper.prototype.constructor=THREE.VertexNormalsHelper; +THREE.VertexNormalsHelper.prototype.update=function(a){var b=new THREE.Vector3;return function(a){a=["a","b","c","d"];this.object.updateMatrixWorld(!0);this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,k=0,l=f.length;k<l;k++)for(var p=f[k],q=0,n=p.vertexNormals.length;q<n;q++){var t=p.vertexNormals[q];d[h].copy(e[p[a[q]]]).applyMatrix4(g);b.copy(t).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size); +b.add(d[h]);h+=1;d[h].copy(b);h+=1}this.geometry.verticesNeedUpdate=!0;return this}}(); +THREE.VertexTangentsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;b=void 0!==c?c:255;d=void 0!==d?d:1;c=new THREE.Geometry;a=a.geometry.faces;for(var e=0,f=a.length;e<f;e++)for(var g=0,h=a[e].vertexTangents.length;g<h;g++)c.vertices.push(new THREE.Vector3),c.vertices.push(new THREE.Vector3);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:b,linewidth:d}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.update()};THREE.VertexTangentsHelper.prototype=Object.create(THREE.Line.prototype); +THREE.VertexTangentsHelper.prototype.constructor=THREE.VertexTangentsHelper; +THREE.VertexTangentsHelper.prototype.update=function(a){var b=new THREE.Vector3;return function(a){a=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,k=0,l=f.length;k<l;k++)for(var p=f[k],q=0,n=p.vertexTangents.length;q<n;q++){var t=p.vertexTangents[q];d[h].copy(e[p[a[q]]]).applyMatrix4(g);b.copy(t).transformDirection(g).multiplyScalar(this.size);b.add(d[h]);h+=1;d[h].copy(b); +h+=1}this.geometry.verticesNeedUpdate=!0;return this}}(); +THREE.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h=new THREE.BufferGeometry;if(a.geometry instanceof THREE.Geometry){for(var k=a.geometry.vertices,l=a.geometry.faces,p=0,q=new Uint32Array(6*l.length),n=0,t=l.length;n<t;n++)for(var r=l[n],s=0;3>s;s++){d[0]=r[g[s]];d[1]=r[g[(s+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);n=0;for(t=p;n<t;n++)for(s=0;2>s;s++)p= +k[q[2*n+s]],g=6*n+3*s,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;t=a.geometry.attributes.index.array;l=a.geometry.drawcalls;p=0;0===l.length&&(l=[{count:t.length,index:0,start:0}]);for(var q=new Uint32Array(2*t.length),r=0,v=l.length;r<v;++r)for(var s=l[r].start,u=l[r].count,g=l[r].index,n=s,x=s+u;n<x;n+=3)for(s=0;3>s;s++)d[0]= +g+t[n+s],d[1]=g+t[n+(s+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);n=0;for(t=p;n<t;n++)for(s=0;2>s;s++)g=6*n+3*s,p=3*q[2*n+s],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),n=0,t=q;n<t;n++)for(s=0;3>s;s++)g=18*n+6*s,q=9*n+3*s,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*n+(s+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d, +3))}THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.WireframeHelper.prototype.constructor=THREE.WireframeHelper;THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(a){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.ImmediateRenderObject.prototype.constructor=THREE.ImmediateRenderObject; +THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.MorphBlendMesh.prototype.constructor=THREE.MorphBlendMesh; THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)}; -THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)(\d+)/,c,d={},e=this.geometry,f=0,h=e.morphTargets.length;f<h;f++){var g=e.morphTargets[f].name.match(b);if(g&&1<g.length){var i=g[1];d[i]||(d[i]={start:Infinity,end:-Infinity});g=d[i];f<g.start&&(g.start=f);f>g.end&&(g.end=f);c||(c=i)}}for(i in d)g=d[i],this.createAnimation(i,g.start,g.end,a);this.firstAnimation=c}; +THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;f<g;f++){var h=e.morphTargets[f].name.match(b);if(h&&1<h.length){var k=h[1];d[k]||(d[k]={start:Infinity,end:-Infinity});h=d[k];f<h.start&&(h.start=f);f>h.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c}; THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; -THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; -THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;b<c;b++){var d=this.animationsList[b];if(d.active){var e=d.duration/d.length;d.time+=d.direction*a;if(d.mirroredLoop){if(d.time>d.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),h=d.weight; -f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*h;this.morphTargetInfluences[d.lastFrame]=(1-e)*h}}};THREE.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";b.shaderSource(e,g+a.fragmentShader);b.shaderSource(f,g+a.vertexShader);b.compileShader(e);b.compileShader(f);b.attachShader(d,e);b.attachShader(d,f);b.linkProgram(d);return d}var b,c,d,e,f,h,g,i,k,m,l,p,s;this.init=function(t){b=t.context;c=t;d=t.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);t=0;e[t++]=-1;e[t++]=-1; -e[t++]=0;e[t++]=0;e[t++]=1;e[t++]=-1;e[t++]=1;e[t++]=0;e[t++]=1;e[t++]=1;e[t++]=1;e[t++]=1;e[t++]=-1;e[t++]=1;e[t++]=0;e[t++]=1;t=0;f[t++]=0;f[t++]=1;f[t++]=2;f[t++]=0;f[t++]=2;f[t++]=3;h=b.createBuffer();g=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,h);b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);i=b.createTexture();k=b.createTexture();b.bindTexture(b.TEXTURE_2D,i);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16, -0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,k);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE); -b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(m=!1,l=a(THREE.ShaderFlares.lensFlare,d)):(m=!0,l=a(THREE.ShaderFlares.lensFlareVertexTexture,d));p={};s={};p.vertex=b.getAttribLocation(l,"position");p.uv=b.getAttribLocation(l,"uv");s.renderType=b.getUniformLocation(l,"renderType");s.map=b.getUniformLocation(l,"map");s.occlusionMap=b.getUniformLocation(l,"occlusionMap");s.opacity= -b.getUniformLocation(l,"opacity");s.color=b.getUniformLocation(l,"color");s.scale=b.getUniformLocation(l,"scale");s.rotation=b.getUniformLocation(l,"rotation");s.screenPosition=b.getUniformLocation(l,"screenPosition")};this.render=function(a,d,e,f){var a=a.__webglFlares,u=a.length;if(u){var w=new THREE.Vector3,z=f/e,B=0.5*e,D=0.5*f,x=16/f,F=new THREE.Vector2(x*z,x),A=new THREE.Vector3(1,1,0),O=new THREE.Vector2(1,1),C=s,x=p;b.useProgram(l);b.enableVertexAttribArray(p.vertex);b.enableVertexAttribArray(p.uv); -b.uniform1i(C.occlusionMap,0);b.uniform1i(C.map,1);b.bindBuffer(b.ARRAY_BUFFER,h);b.vertexAttribPointer(x.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(x.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.disable(b.CULL_FACE);b.depthMask(!1);var E,I,y,v,G;for(E=0;E<u;E++)if(x=16/f,F.set(x*z,x),v=a[E],w.set(v.matrixWorld.elements[12],v.matrixWorld.elements[13],v.matrixWorld.elements[14]),w.applyMatrix4(d.matrixWorldInverse),w.applyProjection(d.projectionMatrix),A.copy(w),O.x=A.x*B+B, -O.y=A.y*D+D,m||0<O.x&&O.x<e&&0<O.y&&O.y<f){b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,i);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGB,O.x-8,O.y-8,16,16,0);b.uniform1i(C.renderType,0);b.uniform2f(C.scale,F.x,F.y);b.uniform3f(C.screenPosition,A.x,A.y,A.z);b.disable(b.BLEND);b.enable(b.DEPTH_TEST);b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0);b.activeTexture(b.TEXTURE0);b.bindTexture(b.TEXTURE_2D,k);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGBA,O.x-8,O.y-8,16,16,0);b.uniform1i(C.renderType,1);b.disable(b.DEPTH_TEST); -b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,i);b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0);v.positionScreen.copy(A);v.customUpdateCallback?v.customUpdateCallback(v):v.updateLensFlares();b.uniform1i(C.renderType,2);b.enable(b.BLEND);I=0;for(y=v.lensFlares.length;I<y;I++)G=v.lensFlares[I],0.001<G.opacity&&0.001<G.scale&&(A.x=G.x,A.y=G.y,A.z=G.z,x=G.size*G.scale/f,F.x=x*z,F.y=x,b.uniform3f(C.screenPosition,A.x,A.y,A.z),b.uniform2f(C.scale,F.x,F.y),b.uniform1f(C.rotation,G.rotation),b.uniform1f(C.opacity, -G.opacity),b.uniform3f(C.color,G.color.r,G.color.g,G.color.b),c.setBlending(G.blending,G.blendEquation,G.blendSrc,G.blendDst),c.setTexture(G.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0))}b.enable(b.CULL_FACE);b.enable(b.DEPTH_TEST);b.depthMask(!0)}}};THREE.ShadowMapPlugin=function(){var a,b,c,d,e,f,h=new THREE.Frustum,g=new THREE.Matrix4,i=new THREE.Vector3,k=new THREE.Vector3,m=new THREE.Vector3;this.init=function(g){a=g.context;b=g;var g=THREE.ShaderLib.depthRGBA,h=THREE.UniformsUtils.clone(g.uniforms);c=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h});d=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0});e=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader, -vertexShader:g.vertexShader,uniforms:h,skinning:!0});f=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0,skinning:!0});c._shadowPass=!0;d._shadowPass=!0;e._shadowPass=!0;f._shadowPass=!0};this.render=function(a,c){b.shadowMapEnabled&&b.shadowMapAutoUpdate&&this.update(a,c)};this.update=function(l,p){var s,t,n,r,q,u,w,z,B,D=[];r=0;a.clearColor(1,1,1,1);a.disable(a.BLEND);a.enable(a.CULL_FACE);a.frontFace(a.CCW);b.shadowMapCullFace===THREE.CullFaceFront? -a.cullFace(a.FRONT):a.cullFace(a.BACK);b.setDepthTest(!0);s=0;for(t=l.__lights.length;s<t;s++)if(n=l.__lights[s],n.castShadow)if(n instanceof THREE.DirectionalLight&&n.shadowCascade)for(q=0;q<n.shadowCascadeCount;q++){var x;if(n.shadowCascadeArray[q])x=n.shadowCascadeArray[q];else{B=n;w=q;x=new THREE.DirectionalLight;x.isVirtual=!0;x.onlyShadow=!0;x.castShadow=!0;x.shadowCameraNear=B.shadowCameraNear;x.shadowCameraFar=B.shadowCameraFar;x.shadowCameraLeft=B.shadowCameraLeft;x.shadowCameraRight=B.shadowCameraRight; -x.shadowCameraBottom=B.shadowCameraBottom;x.shadowCameraTop=B.shadowCameraTop;x.shadowCameraVisible=B.shadowCameraVisible;x.shadowDarkness=B.shadowDarkness;x.shadowBias=B.shadowCascadeBias[w];x.shadowMapWidth=B.shadowCascadeWidth[w];x.shadowMapHeight=B.shadowCascadeHeight[w];x.pointsWorld=[];x.pointsFrustum=[];z=x.pointsWorld;u=x.pointsFrustum;for(var F=0;8>F;F++)z[F]=new THREE.Vector3,u[F]=new THREE.Vector3;z=B.shadowCascadeNearZ[w];B=B.shadowCascadeFarZ[w];u[0].set(-1,-1,z);u[1].set(1,-1,z);u[2].set(-1, -1,z);u[3].set(1,1,z);u[4].set(-1,-1,B);u[5].set(1,-1,B);u[6].set(-1,1,B);u[7].set(1,1,B);x.originalCamera=p;u=new THREE.Gyroscope;u.position=n.shadowCascadeOffset;u.add(x);u.add(x.target);p.add(u);n.shadowCascadeArray[q]=x;console.log("Created virtualLight",x)}w=n;z=q;B=w.shadowCascadeArray[z];B.position.copy(w.position);B.target.position.copy(w.target.position);B.lookAt(B.target);B.shadowCameraVisible=w.shadowCameraVisible;B.shadowDarkness=w.shadowDarkness;B.shadowBias=w.shadowCascadeBias[z];u=w.shadowCascadeNearZ[z]; -w=w.shadowCascadeFarZ[z];B=B.pointsFrustum;B[0].z=u;B[1].z=u;B[2].z=u;B[3].z=u;B[4].z=w;B[5].z=w;B[6].z=w;B[7].z=w;D[r]=x;r++}else D[r]=n,r++;s=0;for(t=D.length;s<t;s++){n=D[s];n.shadowMap||(q=THREE.LinearFilter,b.shadowMapType===THREE.PCFSoftShadowMap&&(q=THREE.NearestFilter),n.shadowMap=new THREE.WebGLRenderTarget(n.shadowMapWidth,n.shadowMapHeight,{minFilter:q,magFilter:q,format:THREE.RGBAFormat}),n.shadowMapSize=new THREE.Vector2(n.shadowMapWidth,n.shadowMapHeight),n.shadowMatrix=new THREE.Matrix4); -if(!n.shadowCamera){if(n instanceof THREE.SpotLight)n.shadowCamera=new THREE.PerspectiveCamera(n.shadowCameraFov,n.shadowMapWidth/n.shadowMapHeight,n.shadowCameraNear,n.shadowCameraFar);else if(n instanceof THREE.DirectionalLight)n.shadowCamera=new THREE.OrthographicCamera(n.shadowCameraLeft,n.shadowCameraRight,n.shadowCameraTop,n.shadowCameraBottom,n.shadowCameraNear,n.shadowCameraFar);else{console.error("Unsupported light type for shadow");continue}l.add(n.shadowCamera);!0===l.autoUpdate&&l.updateMatrixWorld()}n.shadowCameraVisible&& -!n.cameraHelper&&(n.cameraHelper=new THREE.CameraHelper(n.shadowCamera),n.shadowCamera.add(n.cameraHelper));if(n.isVirtual&&x.originalCamera==p){q=p;r=n.shadowCamera;u=n.pointsFrustum;B=n.pointsWorld;i.set(Infinity,Infinity,Infinity);k.set(-Infinity,-Infinity,-Infinity);for(w=0;8>w;w++)z=B[w],z.copy(u[w]),THREE.ShadowMapPlugin.__projector.unprojectVector(z,q),z.applyMatrix4(r.matrixWorldInverse),z.x<i.x&&(i.x=z.x),z.x>k.x&&(k.x=z.x),z.y<i.y&&(i.y=z.y),z.y>k.y&&(k.y=z.y),z.z<i.z&&(i.z=z.z),z.z>k.z&& -(k.z=z.z);r.left=i.x;r.right=k.x;r.top=k.y;r.bottom=i.y;r.updateProjectionMatrix()}r=n.shadowMap;u=n.shadowMatrix;q=n.shadowCamera;q.position.getPositionFromMatrix(n.matrixWorld);m.getPositionFromMatrix(n.target.matrixWorld);q.lookAt(m);q.updateMatrixWorld();q.matrixWorldInverse.getInverse(q.matrixWorld);n.cameraHelper&&(n.cameraHelper.visible=n.shadowCameraVisible);n.shadowCameraVisible&&n.cameraHelper.update();u.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);u.multiply(q.projectionMatrix);u.multiply(q.matrixWorldInverse); -g.multiplyMatrices(q.projectionMatrix,q.matrixWorldInverse);h.setFromMatrix(g);b.setRenderTarget(r);b.clear();B=l.__webglObjects;n=0;for(r=B.length;n<r;n++)if(w=B[n],u=w.object,w.render=!1,u.visible&&u.castShadow&&(!(u instanceof THREE.Mesh||u instanceof THREE.ParticleSystem)||!u.frustumCulled||h.intersectsObject(u)))u._modelViewMatrix.multiplyMatrices(q.matrixWorldInverse,u.matrixWorld),w.render=!0;n=0;for(r=B.length;n<r;n++)w=B[n],w.render&&(u=w.object,w=w.buffer,F=u.material instanceof THREE.MeshFaceMaterial? -u.material.materials[0]:u.material,z=0<u.geometry.morphTargets.length&&F.morphTargets,F=u instanceof THREE.SkinnedMesh&&F.skinning,z=u.customDepthMaterial?u.customDepthMaterial:F?z?f:e:z?d:c,w instanceof THREE.BufferGeometry?b.renderBufferDirect(q,l.__lights,null,z,w,u):b.renderBuffer(q,l.__lights,null,z,w,u));B=l.__webglObjectsImmediate;n=0;for(r=B.length;n<r;n++)w=B[n],u=w.object,u.visible&&u.castShadow&&(u._modelViewMatrix.multiplyMatrices(q.matrixWorldInverse,u.matrixWorld),b.renderImmediateObject(q, -l.__lights,null,c,u))}s=b.getClearColor();t=b.getClearAlpha();a.clearColor(s.r,s.g,s.b,t);a.enable(a.BLEND);b.shadowMapCullFace===THREE.CullFaceFront&&a.cullFace(a.BACK)}};THREE.ShadowMapPlugin.__projector=new THREE.Projector;THREE.SpritePlugin=function(){function a(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var b,c,d,e,f,h,g,i,k,m;this.init=function(a){b=a.context;c=a;d=a.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);a=0;e[a++]=-0.5;e[a++]=-0.5;e[a++]=0;e[a++]=0;e[a++]=0.5;e[a++]=-0.5;e[a++]=1;e[a++]=0;e[a++]=0.5;e[a++]=0.5;e[a++]=1;e[a++]=1;e[a++]=-0.5;e[a++]=0.5;e[a++]=0;e[a++]=1;a=0;f[a++]=0;f[a++]=1;f[a++]=2;f[a++]=0;f[a++]=2;f[a++]=3;h=b.createBuffer();g=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,h); -b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);var a=THREE.ShaderSprite.sprite,p=b.createProgram(),s=b.createShader(b.FRAGMENT_SHADER),t=b.createShader(b.VERTEX_SHADER),n="precision "+d+" float;\n";b.shaderSource(s,n+a.fragmentShader);b.shaderSource(t,n+a.vertexShader);b.compileShader(s);b.compileShader(t);b.attachShader(p,s);b.attachShader(p,t);b.linkProgram(p);i=p;k={};m={};k.position=b.getAttribLocation(i, -"position");k.uv=b.getAttribLocation(i,"uv");m.uvOffset=b.getUniformLocation(i,"uvOffset");m.uvScale=b.getUniformLocation(i,"uvScale");m.rotation=b.getUniformLocation(i,"rotation");m.scale=b.getUniformLocation(i,"scale");m.alignment=b.getUniformLocation(i,"alignment");m.halfViewport=b.getUniformLocation(i,"halfViewport");m.color=b.getUniformLocation(i,"color");m.map=b.getUniformLocation(i,"map");m.opacity=b.getUniformLocation(i,"opacity");m.useScreenCoordinates=b.getUniformLocation(i,"useScreenCoordinates"); -m.sizeAttenuation=b.getUniformLocation(i,"sizeAttenuation");m.screenPosition=b.getUniformLocation(i,"screenPosition");m.modelViewMatrix=b.getUniformLocation(i,"modelViewMatrix");m.projectionMatrix=b.getUniformLocation(i,"projectionMatrix");m.fogType=b.getUniformLocation(i,"fogType");m.fogDensity=b.getUniformLocation(i,"fogDensity");m.fogNear=b.getUniformLocation(i,"fogNear");m.fogFar=b.getUniformLocation(i,"fogFar");m.fogColor=b.getUniformLocation(i,"fogColor");m.alphaTest=b.getUniformLocation(i, -"alphaTest")};this.render=function(d,e,f,t){var n=d.__webglSprites,r=n.length;if(r){var q=k,u=m,f=0.5*f,t=0.5*t;b.useProgram(i);b.enableVertexAttribArray(q.position);b.enableVertexAttribArray(q.uv);b.disable(b.CULL_FACE);b.enable(b.BLEND);b.bindBuffer(b.ARRAY_BUFFER,h);b.vertexAttribPointer(q.position,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(q.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.uniformMatrix4fv(u.projectionMatrix,!1,e.projectionMatrix.elements);b.activeTexture(b.TEXTURE0); -b.uniform1i(u.map,0);var w=q=0,z=d.fog;z?(b.uniform3f(u.fogColor,z.color.r,z.color.g,z.color.b),z instanceof THREE.Fog?(b.uniform1f(u.fogNear,z.near),b.uniform1f(u.fogFar,z.far),b.uniform1i(u.fogType,1),w=q=1):z instanceof THREE.FogExp2&&(b.uniform1f(u.fogDensity,z.density),b.uniform1i(u.fogType,2),w=q=2)):(b.uniform1i(u.fogType,0),w=q=0);for(var B,D,x=[],z=0;z<r;z++)B=n[z],D=B.material,B.visible&&0!==D.opacity&&(D.useScreenCoordinates?B.z=-B.position.z:(B._modelViewMatrix.multiplyMatrices(e.matrixWorldInverse, -B.matrixWorld),B.z=-B._modelViewMatrix.elements[14]));n.sort(a);for(z=0;z<r;z++)B=n[z],D=B.material,B.visible&&0!==D.opacity&&(D.map&&D.map.image&&D.map.image.width)&&(b.uniform1f(u.alphaTest,D.alphaTest),!0===D.useScreenCoordinates?(b.uniform1i(u.useScreenCoordinates,1),b.uniform3f(u.screenPosition,(B.position.x*c.devicePixelRatio-f)/f,(t-B.position.y*c.devicePixelRatio)/t,Math.max(0,Math.min(1,B.position.z))),x[0]=c.devicePixelRatio*B.scale.x,x[1]=c.devicePixelRatio*B.scale.y):(b.uniform1i(u.useScreenCoordinates, -0),b.uniform1i(u.sizeAttenuation,D.sizeAttenuation?1:0),b.uniformMatrix4fv(u.modelViewMatrix,!1,B._modelViewMatrix.elements),x[0]=B.scale.x,x[1]=B.scale.y),e=d.fog&&D.fog?w:0,q!==e&&(b.uniform1i(u.fogType,e),q=e),b.uniform2f(u.uvScale,D.uvScale.x,D.uvScale.y),b.uniform2f(u.uvOffset,D.uvOffset.x,D.uvOffset.y),b.uniform2f(u.alignment,D.alignment.x,D.alignment.y),b.uniform1f(u.opacity,D.opacity),b.uniform3f(u.color,D.color.r,D.color.g,D.color.b),b.uniform1f(u.rotation,B.rotation),b.uniform2fv(u.scale, -x),b.uniform2f(u.halfViewport,f,t),c.setBlending(D.blending,D.blendEquation,D.blendSrc,D.blendDst),c.setDepthTest(D.depthTest),c.setDepthWrite(D.depthWrite),c.setTexture(D.map,0),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE)}}};THREE.DepthPassPlugin=function(){this.enabled=!1;this.renderTarget=null;var a,b,c,d,e,f,h=new THREE.Frustum,g=new THREE.Matrix4;this.init=function(g){a=g.context;b=g;var g=THREE.ShaderLib.depthRGBA,h=THREE.UniformsUtils.clone(g.uniforms);c=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h});d=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0});e=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader, -vertexShader:g.vertexShader,uniforms:h,skinning:!0});f=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:h,morphTargets:!0,skinning:!0});c._shadowPass=!0;d._shadowPass=!0;e._shadowPass=!0;f._shadowPass=!0};this.render=function(a,b){this.enabled&&this.update(a,b)};this.update=function(i,k){var m,l,p,s,t,n;a.clearColor(1,1,1,1);a.disable(a.BLEND);b.setDepthTest(!0);!0===i.autoUpdate&&i.updateMatrixWorld();k.matrixWorldInverse.getInverse(k.matrixWorld);g.multiplyMatrices(k.projectionMatrix, -k.matrixWorldInverse);h.setFromMatrix(g);b.setRenderTarget(this.renderTarget);b.clear();n=i.__webglObjects;m=0;for(l=n.length;m<l;m++)if(p=n[m],t=p.object,p.render=!1,t.visible&&(!(t instanceof THREE.Mesh||t instanceof THREE.ParticleSystem)||!t.frustumCulled||h.intersectsObject(t)))t._modelViewMatrix.multiplyMatrices(k.matrixWorldInverse,t.matrixWorld),p.render=!0;var r;m=0;for(l=n.length;m<l;m++)if(p=n[m],p.render&&(t=p.object,p=p.buffer,!(t instanceof THREE.ParticleSystem)||t.customDepthMaterial))(r= -t.material instanceof THREE.MeshFaceMaterial?t.material.materials[0]:t.material)&&b.setMaterialFaces(t.material),s=0<t.geometry.morphTargets.length&&r.morphTargets,r=t instanceof THREE.SkinnedMesh&&r.skinning,s=t.customDepthMaterial?t.customDepthMaterial:r?s?f:e:s?d:c,p instanceof THREE.BufferGeometry?b.renderBufferDirect(k,i.__lights,null,s,p,t):b.renderBuffer(k,i.__lights,null,s,p,t);n=i.__webglObjectsImmediate;m=0;for(l=n.length;m<l;m++)p=n[m],t=p.object,t.visible&&(t._modelViewMatrix.multiplyMatrices(k.matrixWorldInverse, -t.matrixWorld),b.renderImmediateObject(k,i.__lights,null,c,t));m=b.getClearColor();l=b.getClearAlpha();a.clearColor(m.r,m.g,m.b,l);a.enable(a.BLEND)}};THREE.ShaderFlares={lensFlareVertexTexture:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility = visibility.r / 9.0;\nvVisibility *= 1.0 - visibility.g / 9.0;\nvVisibility *= visibility.b / 9.0;\nvVisibility *= 1.0 - visibility.a / 9.0;\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", -fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"},lensFlare:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}", -fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}};THREE.ShaderSprite={sprite:{vertexShader:"uniform int useScreenCoordinates;\nuniform int sizeAttenuation;\nuniform vec3 screenPosition;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 alignment;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nuniform vec2 halfViewport;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = ( position + alignment ) * scale;\nvec2 rotatedPosition;\nrotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\nrotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\nvec4 finalPosition;\nif( useScreenCoordinates != 0 ) {\nfinalPosition = vec4( screenPosition.xy + ( rotatedPosition / halfViewport ), screenPosition.z, 1.0 );\n} else {\nfinalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition * ( sizeAttenuation == 1 ? 1.0 : finalPosition.z );\nfinalPosition = projectionMatrix * finalPosition;\n}\ngl_Position = finalPosition;\n}", -fragmentShader:"uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"}}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):THREE.warn("THREE.MorphBlendMesh: animation["+a+"] undefined in .playAnimation()")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;b<c;b++){var d=this.animationsList[b];if(d.active){var e=d.duration/d.length;d.time+=d.direction*a;if(d.mirroredLoop){if(d.time>d.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; +f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}}; diff --git a/gz3d/src/gz.js b/gz3d/src/gz.js index 9aa8ac896ce571b86924cd492f9eb2944238b85d..e8dd0aec0149d76faae58cb7cb9805f32b730069 100644 --- a/gz3d/src/gz.js +++ b/gz3d/src/gz.js @@ -1,3 +1,3 @@ var GZ3D = GZ3D || { REVISION : '1' -}; +}; \ No newline at end of file diff --git a/gz3d/src/gziface.js b/gz3d/src/gziface.js index ccb90e0561140127b7d3dbcc2bca326fe5e52b32..3186fbba847a4646867188834540f933a99d18b9 100644 --- a/gz3d/src/gziface.js +++ b/gz3d/src/gziface.js @@ -1037,7 +1037,7 @@ GZ3D.GZIface.prototype.applyMaterial = function(obj, mat) var ambient = mat.ambient; if (ambient) { - obj.material.ambient.setRGB(ambient[0], ambient[1], ambient[2]); + obj.material.emissive.setRGB(ambient[0], ambient[1], ambient[2]); } var diffuse = mat.diffuse; if (diffuse) @@ -1372,7 +1372,7 @@ GZ3D.GZIface.prototype.parseMaterial = function(material) var ambient = mat['ambient']; if (ambient) { - obj.material.ambient.setRGB(ambient[0], ambient[1], ambient[2]); + obj.material.emissive.setRGB(ambient[0], ambient[1], ambient[2]); } var diffuse = mat['diffuse']; if (diffuse) diff --git a/gz3d/src/gzmanipulator.js b/gz3d/src/gzmanipulator.js index e347212ed3d31031763e55a6ab00aef78ffe51e8..84e9cadfbd303cdb19667bda4075bdf3d3c0542d 100644 --- a/gz3d/src/gzmanipulator.js +++ b/gz3d/src/gzmanipulator.js @@ -46,7 +46,6 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc) var changeEvent = {type: 'change'}; var ray = new THREE.Raycaster(); - var projector = new THREE.Projector(); var pointerVector = new THREE.Vector3(); var point = new THREE.Vector3(); @@ -1142,7 +1141,7 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc) var y = (pointer.clientY - rect.top) / rect.height; pointerVector.set((x) * 2 - 1, - (y) * 2 + 1, 0.5); - projector.unprojectVector(pointerVector, scope.camera); + pointerVector.unproject(scope.camera); ray.set(camPosition, pointerVector.sub(camPosition).normalize()); // checks all intersections between the ray and the objects, @@ -1175,7 +1174,8 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc) function bakeTransformations(object) { var tempGeometry = new THREE.Geometry(); - THREE.GeometryUtils.merge(tempGeometry, object); + object.updateMatrix(); + tempGeometry.merge(object.geometry, object.matrix); object.geometry = tempGeometry; object.position.set(0, 0, 0); object.rotation.set(0, 0, 0); diff --git a/gz3d/src/gzradialmenu.js b/gz3d/src/gzradialmenu.js index 0fca39b3e418114a9be2950ae8cdd69d9e1713e7..16c1cc5bb4aeb57299c508bf287ed26ca85e30a8 100644 --- a/gz3d/src/gzradialmenu.js +++ b/gz3d/src/gzradialmenu.js @@ -353,9 +353,9 @@ GZ3D.RadialMenu.prototype.addItem = function(type, iconTexture) // Icon iconTexture = THREE.ImageUtils.loadTexture( iconTexture ); - var iconMaterial = new THREE.SpriteMaterial( { useScreenCoordinates: true, - alignment: THREE.SpriteAlignment.center } ); - iconMaterial.map = iconTexture; + var iconMaterial = new THREE.SpriteMaterial( { + map: iconTexture + } ); var icon = new THREE.Sprite( iconMaterial ); icon.scale.set( this.bgSize*this.iconProportion, @@ -365,8 +365,6 @@ GZ3D.RadialMenu.prototype.addItem = function(type, iconTexture) // Background var bgMaterial = new THREE.SpriteMaterial( { map: this.bgShape, - useScreenCoordinates: true, - alignment: THREE.SpriteAlignment.center, color: this.plainColor } ); var bg = new THREE.Sprite( bgMaterial ); @@ -375,8 +373,6 @@ GZ3D.RadialMenu.prototype.addItem = function(type, iconTexture) // Highlight var highlightMaterial = new THREE.SpriteMaterial({ map: this.bgShape, - useScreenCoordinates: true, - alignment: THREE.SpriteAlignment.center, color: this.highlightColor}); var highlight = new THREE.Sprite(highlightMaterial); diff --git a/gz3d/src/gzscene.js b/gz3d/src/gzscene.js index d69c9d100a1bac5570a3a8d84318a08a7e202650..8e39fb46d5d3d7563c06d2a029141939b4b83e02 100644 --- a/gz3d/src/gzscene.js +++ b/gz3d/src/gzscene.js @@ -1,3 +1,5 @@ + + /** * The scene is where everything is placed, from objects, to lights and cameras. * @constructor @@ -97,7 +99,9 @@ GZ3D.Scene.prototype.init = function() this.timeDown = null; this.controls = new THREE.OrbitControls(this.camera); - this.scene.add(this.controls.targetIndicator); + if (this.controls.targetIndicator !== undefined) { + this.scene.add(this.controls.targetIndicator); + } this.emitter = new EventEmitter2({ verbose: true }); @@ -235,7 +239,7 @@ GZ3D.Scene.prototype.init = function() material = new THREE.MeshLambertMaterial(); material.color = new THREE.Color(0xffff00); - material.ambient = material.color; + material.emissive = material.color; geometry = new THREE.CylinderGeometry(0.02, 0.02, 0.25, 36, 1, false); @@ -570,13 +574,12 @@ GZ3D.Scene.prototype.onKeyDown = function(event) */ GZ3D.Scene.prototype.getRayCastModel = function(pos, intersect) { - var projector = new THREE.Projector(); var vector = new THREE.Vector3( ((pos.x - this.renderer.domElement.offsetLeft) / window.innerWidth) * 2 - 1, -((pos.y - this.renderer.domElement.offsetTop) / window.innerHeight) * 2 + 1, 1); - projector.unprojectVector(vector, this.camera); + vector.unproject(this.camera); var ray = new THREE.Raycaster( this.camera.position, vector.sub(this.camera.position).normalize() ); @@ -856,7 +859,7 @@ GZ3D.Scene.prototype.createCylinder = function(radius, length) */ GZ3D.Scene.prototype.createBox = function(width, height, depth) { - var geometry = new THREE.CubeGeometry(width, height, depth, 1, 1, 1); + var geometry = new THREE.BoxGeometry(width, height, depth, 1, 1, 1); // Fix UVs so textures are mapped in a way that is consistent to gazebo // Some face uvs need to be rotated clockwise, while others anticlockwise @@ -1282,7 +1285,7 @@ GZ3D.Scene.prototype.createRoads = function(points, width, texture) /* var ambient = mat['ambient']; if (ambient) { - material.ambient.setRGB(ambient[0], ambient[1], ambient[2]); + material.emissive.setRGB(ambient[0], ambient[1], ambient[2]); } var diffuse = mat['diffuse']; if (diffuse) @@ -1706,7 +1709,7 @@ GZ3D.Scene.prototype.setMaterial = function(obj, material) var ambient = material.ambient; if (ambient) { - obj.material.ambient.setRGB(ambient[0], ambient[1], ambient[2]); + obj.material.emissive.setRGB(ambient[0], ambient[1], ambient[2]); } var diffuse = material.diffuse; if (diffuse) diff --git a/gz3d/src/gzspawnmodel.js b/gz3d/src/gzspawnmodel.js index 9675c2257996987a4ef67640486cd5cb8b29a1f1..75df2c6db151e0467c5a5599f0aef0a1fc27cfad 100644 --- a/gz3d/src/gzspawnmodel.js +++ b/gz3d/src/gzspawnmodel.js @@ -18,7 +18,6 @@ GZ3D.SpawnModel = function(scene, domElement) GZ3D.SpawnModel.prototype.init = function() { this.plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); - this.projector = new THREE.Projector(); this.ray = new THREE.Ray(); this.obj = null; this.active = false; @@ -243,7 +242,7 @@ GZ3D.SpawnModel.prototype.moveSpawnedModel = function(positionX, positionY) { var vector = new THREE.Vector3( (positionX / window.innerWidth) * 2 - 1, -(positionY / window.innerHeight) * 2 + 1, 0.5); - this.projector.unprojectVector(vector, this.scene.camera); + vector.unproject(this.scene.camera); this.ray.set(this.scene.camera.position, vector.sub(this.scene.camera.position).normalize()); var point = this.ray.intersectPlane(this.plane);