diff --git a/images/IO_interface_schem.jpg b/images/IO_interface_schem.jpg new file mode 100644 index 00000000..2dcbf99d Binary files /dev/null and b/images/IO_interface_schem.jpg differ diff --git a/images/IO_interface_schem_thumb.jpeg b/images/IO_interface_schem_thumb.jpeg new file mode 100644 index 00000000..025d0e85 Binary files /dev/null and b/images/IO_interface_schem_thumb.jpeg differ diff --git a/various_tests/test_3D.html b/various_tests/test_3D.html index 426e8901..b68a1cfa 100644 --- a/various_tests/test_3D.html +++ b/various_tests/test_3D.html @@ -256,15 +256,14 @@ if (points) return new THREE.PointCloud(geometry, terrainMaterial); else - return new THREE.Line(geometry, terrainMaterial, THREE.LinePieces); + return new THREE.LineSegments(geometry, terrainMaterial); } var grid = createGrid(pipeline.toolPosBuffer.width, pipeline.toolPosBuffer.height, false, false, true); grid.frustumCulled = false; scene2.add(grid); scene2.add(new THREE.Mesh(clonedGeometry, new THREE.MeshLambertMaterial({ - color: 0xFEEFFE, - shading: THREE.SmoothShading + color: 0xFEEFFE }))); document.documentElement.addEventListener('keydown', function (event) { diff --git a/various_tests/test_3D_conservative_rendering.html b/various_tests/test_3D_conservative_rendering.html index 83286c5c..d0e57f8f 100644 --- a/various_tests/test_3D_conservative_rendering.html +++ b/various_tests/test_3D_conservative_rendering.html @@ -235,13 +235,11 @@ scene2.add(grid); scene2.add(new THREE.Mesh(clonedGeometry, new THREE.MeshLambertMaterial({ color: 0xFEEFFE, - shading: THREE.SmoothShading, side: THREE.DoubleSide }))); scene2.add(new THREE.PointCloud(pipeline.modelStage.inputGeometry.clone(), new THREE.ShaderMaterial({ depthTest: true, - sizeAttenuation: false, uniforms: pipeline.modelStage.shaderUniforms, attributes: pipeline.modelStage.shaderAttributes, vertexShader: pipeline.modelStage.vertexShader, @@ -253,7 +251,6 @@ scene2.add(new THREE.Line(pipeline.modelStage.inputGeometry.clone(), new THREE.ShaderMaterial({ depthTest: true, - sizeAttenuation: false, uniforms: pipeline.modelStage.shaderUniforms, attributes: pipeline.modelStage.shaderAttributes, vertexShader: pipeline.modelStage.vertexShader, diff --git a/webapp/cnc/app/view.js b/webapp/cnc/app/view.js index 8ed16323..0e729daf 100644 --- a/webapp/cnc/app/view.js +++ b/webapp/cnc/app/view.js @@ -221,16 +221,13 @@ define(['Ember', 'cnc/svgImporter', 'cnc/gerberImporter', 'cnc/excellonImporter' }); this.set('nativeComponent', threeDView); this.set('travelDisplay', threeDView.createDrawingNode(threeDView.rapidMaterial, new THREE.MeshLambertMaterial({ - color: 0xFEEFFE, - shading: THREE.SmoothShading + color: 0xFEEFFE }))); this.set('outlinesDisplay', threeDView.createDrawingNode(threeDView.outlineMaterial, new THREE.MeshLambertMaterial({ - color: 0xFEEFFE, - shading: THREE.SmoothShading + color: 0xFEEFFE }))); this.set('highlightDisplay', threeDView.createOverlayNode(threeDView.highlightMaterial, new THREE.MeshLambertMaterial({ - color: 0xdd4c2f, opacity: 0.5, - shading: THREE.SmoothShading + color: 0xdd4c2f, opacity: 0.5 }))); this.synchronizeCurrentOperation(); @@ -241,8 +238,7 @@ define(['Ember', 'cnc/svgImporter', 'cnc/gerberImporter', 'cnc/excellonImporter' return ShapeWrapper.create({ shape: shape, outlineDisplay: threeDView.createDrawingNode(threeDView.outlineMaterial, new THREE.MeshLambertMaterial({ - color: 0xFEEFFE, - shading: THREE.SmoothShading + color: 0xFEEFFE })) }); } diff --git a/webapp/cnc/cam/3D/modelProjector.js b/webapp/cnc/cam/3D/modelProjector.js index e1e7883f..8e08bba3 100644 --- a/webapp/cnc/cam/3D/modelProjector.js +++ b/webapp/cnc/cam/3D/modelProjector.js @@ -1,234 +1,138 @@ "use strict"; -define([], function () { - - function Projector() { - var scene = new THREE.Scene(); - this.scene = scene; - this.angle = 0; - this.normalVertexShader = [ - 'attribute vec3 prevPoint;', - 'attribute vec3 nextPoint;', - 'void main() {', - ' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);', - '}'].join('\n'); - - this.normalFragmentShader = [ - 'void main() {', - ' gl_FragData[0] = vec4(1.0 - gl_FragCoord.z, 0.0, 0.0, 1.0);', - '}'].join('\n'); - this.vertexShader = [ - 'attribute vec3 prevPoint;', - 'attribute vec3 nextPoint;', - 'uniform vec2 hPixel;', - 'uniform vec2 hPixelWorld;', - 'varying vec3 AABB_min;', - 'varying vec3 AABB_max;', - 'varying vec3 positionK;', - - 'float cross2d(vec2 v1, vec2 v2) {', - ' return v1.x * v2.y - v1.y * v2.x; ', - '}', - - // http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter42.html - 'void main() {', - ' vec3 eyeDirection = vec3(0.0, 0.0, -1.0);', - ' vec3 p1 = prevPoint, p2 = position, p3 = nextPoint;', - ' vec2 e1 = normalize(p2.xy - p1.xy);', - ' vec2 e2 = normalize(p2.xy - p3.xy);', - // project the side on the bisector - // http://stackoverflow.com/a/32515402/72637 - ' float halfsine = sqrt((1.0 - dot(e1, e2)) / 2.0);', - ' vec2 resultPoint2D = p2.xy + length(hPixelWorld) / halfsine * normalize(e1 + e2);', - - // project the 2D point to the triangle plane in 3D - // grab the triangle normal - ' vec3 normal = normalize(cross(p2.xyz - p1.xyz, p3.xyz - p2.xyz));', - // grab the Z for (x=0, y=0) - ' float d = dot(normal, p2.xyz);', - // the new Z is the distance from the 2D projected point to its projection on the triangle plane - ' float t = (dot(normal, vec3(resultPoint2D, 0.0)) - d) / (dot(normal, eyeDirection));', - - //shift the whole triangle up because Z is sampled at pixel center, but the maximum Z is at a corner. - //A mostly vertical triangle might send the Z very high or very low, we'll clamp that in the fragment shader - ' float cornerPessimization = sqrt(1.0 - normal.z * normal.z) * length(hPixelWorld);', - ' vec4 shiftedPosition = vec4(resultPoint2D, t + cornerPessimization, 1.0);', - ' vec4 projectedShiftedPosition = projectionMatrix * modelViewMatrix * shiftedPosition;', - - //compute the Axis Aligned bounding box - ' vec4 prevPos = projectionMatrix * modelViewMatrix * vec4(p1, 1.0);', - ' vec4 currPos = projectionMatrix * modelViewMatrix * vec4(p2, 1.0);', - ' vec4 nextPos = projectionMatrix * modelViewMatrix * vec4(p3, 1.0);', - ' vec3 minBounds = prevPos.xyz;', - ' minBounds = min(currPos.xyz, minBounds);', - ' minBounds = min(nextPos.xyz, minBounds);', - ' vec3 maxBounds = prevPos.xyz;', - ' maxBounds = max(currPos.xyz, maxBounds);', - ' maxBounds = max(nextPos.xyz, maxBounds);', - // extend the box by one pixel - ' minBounds = minBounds - vec3(hPixel, 0.0);', - ' maxBounds = maxBounds + vec3(hPixel, 0.0);', - - ' AABB_min = minBounds;', - ' AABB_max = maxBounds;', - ' gl_PointSize = 10.0;', - ' positionK = projectedShiftedPosition.xyz;', - ' gl_Position = projectedShiftedPosition;', - '}'].join('\n'); - - this.fragmentShader = [ - '#extension GL_EXT_frag_depth : require', - 'varying vec3 AABB_min;', - 'varying vec3 AABB_max;', - 'varying vec3 positionK;', - // depth encoding : http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ - 'highp float factor = (exp2(24.0) - 1.0) / exp2(24.0);', - 'vec3 EncodeFloatRGB(highp float v) {', - ' vec3 enc = fract(vec3(1.0, 255.0, 255.0 * 255.0) * factor * v);', - ' enc -= enc.yzz * vec3(1.0 / 255.0, 1.0 / 255.0, 0.0);', - ' return enc;', - '}', - 'highp float DecodeFloatRGB(vec3 rgb) {', - ' return dot(rgb, vec3(1.0, 1.0 / 255.0, 1.0 / 255.0 / 255.0)) / factor;', - '}', - 'void main() {', - ' vec2 pos = positionK.xy;', - //let's destroy the fragments that are really out there between the input corner and the dilated corner - ' if(any(bvec4(lessThan(pos, AABB_min.xy), greaterThan(pos, AABB_max.xy))))', - ' discard;', - // ok, we were pessimistic, but one thing still holds: - // the true Z value can never ever be higher or lower than any Z value of the input vertices, - // so we clip to get back to some reality - ' float z = clamp(positionK.z, AABB_min.z, AABB_max.z);', - // go back to fragment world - ' z = (0.5 * z + 0.5);', - // update the depth buffer, since what was a nice triangle is now a triangle with 2 bent corners (flattened by the Z clamp). - ' gl_FragDepthEXT = z;', - ' gl_FragData[0] = vec4(1.0 - z, 0.0, 0.0, 1.0);', - '}'].join('\n'); - this.shaderAttributes = {prevPoint: {type: 'v3', value: []}, nextPoint: {type: 'v3', value: []}}; - this.shaderUniforms = {hPixel: {type: 'v2'}, hPixelWorld: {type: 'v2'}}; - this.meshMaterial = new THREE.ShaderMaterial({ - doublesided: true, - depthTest: true, - sizeAttenuation: false, - linewidth: 1, - uniforms: this.shaderUniforms, - attributes: this.shaderAttributes, - vertexShader: this.vertexShader, - fragmentShader: this.fragmentShader - }); - this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1); - scene.add(this.camera); - } - - Projector.prototype = { - render: function (renderer, buffer) { - var extension = renderer.getContext().getExtension('EXT_frag_depth'); - if (!extension && this.meshMaterial.vertexShader != this.normalVertexShader) { - console.log('EXT_frag_depth webgl extension is not supported, the projection won\'t be conservative'); - this.meshMaterial.vertexShader = this.normalVertexShader; - this.meshMaterial.fragmentShader = this.normalFragmentShader; - } - this.meshMaterial.uniforms.hPixel.value = new THREE.Vector2(1 / buffer.width, 1 / buffer.height); - var w = (this.camera.right - this.camera.left) / buffer.width; - var h = (this.camera.top - this.camera.bottom) / buffer.height; - this.meshMaterial.uniforms.hPixelWorld.value = new THREE.Vector2(w / 2, h / 2); - renderer.render(this.scene, this.camera, buffer, true); - }, - setGeometry: function (meshGeometry) { - this.inputGeometry = meshGeometry; - if (this.model) { - this.scene.remove(this.model); - this.model = null; - } - this.model = new THREE.Object3D(); +define(['THREE', 'text!shaders/model_proj.vert', 'text!shaders/model_proj.frag', 'text!shaders/conservative_model_proj.vert', + 'text!shaders/conservative_model_proj.frag'], + function (THREE, normalVertexShader, normalFragmentShader, vertexShader, fragmentShader) { + + function Projector() { + var scene = new THREE.Scene(); + this.scene = scene; + this.angle = 0; + this.normalVertexShader = normalVertexShader; + this.normalFragmentShader = normalFragmentShader; + this.vertexShader = vertexShader; + this.fragmentShader = fragmentShader; + this.shaderAttributes = {prevPoint: {type: 'v3', value: []}, nextPoint: {type: 'v3', value: []}}; + this.shaderUniforms = {hPixel: {type: 'v2'}, hPixelWorld: {type: 'v2'}}; + this.meshMaterial = new THREE.ShaderMaterial({ + side: THREE.DoubleSide, + depthTest: true, + linewidth: 1, + uniforms: this.shaderUniforms, + vertexShader: this.vertexShader, + fragmentShader: this.fragmentShader + }); + this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1); + scene.add(this.camera); + } - var originalPosition = meshGeometry.attributes.position; - var attribute = originalPosition.clone(); - var triangleCount = attribute.length / attribute.itemSize / 3; + Projector.prototype = { + render: function (renderer, buffer) { + var extension = renderer.getContext().getExtension('EXT_frag_depth'); + if (!extension && this.meshMaterial.vertexShader != this.normalVertexShader) { + console.log('EXT_frag_depth webgl extension is not supported, the projection won\'t be conservative'); + this.meshMaterial.vertexShader = this.normalVertexShader; + this.meshMaterial.fragmentShader = this.normalFragmentShader; + } + this.meshMaterial.uniforms.hPixel.value = new THREE.Vector2(1 / buffer.width, 1 / buffer.height); + var w = (this.camera.right - this.camera.left) / buffer.width; + var h = (this.camera.top - this.camera.bottom) / buffer.height; + this.meshMaterial.uniforms.hPixelWorld.value = new THREE.Vector2(w / 2, h / 2); + renderer.render(this.scene, this.camera, buffer, true); + }, + setGeometry: function (meshGeometry) { + this.inputGeometry = meshGeometry; + if (this.model) { + this.scene.remove(this.model); + this.model = null; + } + this.model = new THREE.Object3D(); - for (var triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) { - attribute.copyAt(triangleIndex * 3 + 0, originalPosition, triangleIndex * 3 + 2); - attribute.copyAt(triangleIndex * 3 + 1, originalPosition, triangleIndex * 3 + 0); - attribute.copyAt(triangleIndex * 3 + 2, originalPosition, triangleIndex * 3 + 1); - } - meshGeometry.addAttribute('prevPoint', attribute); - attribute = originalPosition.clone(); - for (triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) { - attribute.copyAt(triangleIndex * 3 + 0, originalPosition, triangleIndex * 3 + 1); - attribute.copyAt(triangleIndex * 3 + 1, originalPosition, triangleIndex * 3 + 2); - attribute.copyAt(triangleIndex * 3 + 2, originalPosition, triangleIndex * 3 + 0); - } - meshGeometry.addAttribute('nextPoint', attribute); - meshGeometry.needsUpdate = true; + var originalPosition = meshGeometry.attributes.position; + var attribute = originalPosition.clone(); + var triangleCount = attribute.count / 3; - var mesh = new THREE.Mesh(meshGeometry, this.meshMaterial); - this.model.add(mesh); - this.modelBbox = this.computeCameraBoundingBox(); - this.scene.add(this.model); - this.model.updateMatrixWorld(); - this.resetCamera(); - }, - resetCamera: function () { - var bbox = this.modelBbox; - var bboxSize = bbox.size(); - this.aspectRatio = bboxSize.x / bboxSize.y; - this.camera.lookAt(new THREE.Vector3(0, 0, bbox.min.z)); - this.camera.near = 1; - this.camera.position.set(0, 0, bbox.max.z + 10 + this.camera.near); - this.camera.far = this.camera.position.z - bbox.min.z; - this.zRatio = 1 / (this.camera.far - this.camera.near); - this.setCamera(bbox.min.x, bbox.max.x, bbox.min.y, bbox.max.y); - }, - setCamera: function (left, right, bottom, top) { - this.camera.bottom = bottom; - this.camera.top = top; - this.camera.left = left; - this.camera.right = right; - this.camera.updateProjectionMatrix(); - this.camera.updateMatrixWorld(); - }, - pushZInverseProjOn: function (matrix) { - var pos = new THREE.Vector3().setFromMatrixPosition(matrix); - pos.z = this.camera.position.z - this.camera.far; - matrix.scale(new THREE.Vector3(1, 1, this.camera.far - this.camera.near)); - matrix.setPosition(pos); - }, - setAngle: function (angleDeg) { - this.angle = angleDeg; - this.camera.up.set(0, 1, 0).applyAxisAngle(new THREE.Vector3(0, 0, 1), angleDeg * Math.PI / 180); - this.camera.lookAt(this.camera.position.clone().sub(new THREE.Vector3(0, 0, 1))); - this.camera.updateProjectionMatrix(); - this.camera.updateMatrixWorld(); - this.modelBbox = this.computeCameraBoundingBox(); - }, - computeCameraBoundingBox: function () { - var vector = new THREE.Vector3(); - var m = new THREE.Matrix4(); - m.lookAt(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0).applyAxisAngle(new THREE.Vector3(0, 0, 1), -this.angle * Math.PI / 180)); - var boundingBox = new THREE.Box3(); - var positions = this.inputGeometry.attributes.position.array; - if (positions) { - var bb = boundingBox; - bb.makeEmpty(); - for (var i = 0, il = positions.length; i < il; i += 3) { - vector.set(positions[i], positions[i + 1], positions[i + 2]); - vector.applyMatrix4(m); - bb.expandByPoint(vector); + for (var triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) { + attribute.copyAt(triangleIndex * 3 + 0, originalPosition, triangleIndex * 3 + 2); + attribute.copyAt(triangleIndex * 3 + 1, originalPosition, triangleIndex * 3 + 0); + attribute.copyAt(triangleIndex * 3 + 2, originalPosition, triangleIndex * 3 + 1); + } + meshGeometry.addAttribute('prevPoint', attribute); + attribute = originalPosition.clone(); + for (triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) { + attribute.copyAt(triangleIndex * 3 + 0, originalPosition, triangleIndex * 3 + 1); + attribute.copyAt(triangleIndex * 3 + 1, originalPosition, triangleIndex * 3 + 2); + attribute.copyAt(triangleIndex * 3 + 2, originalPosition, triangleIndex * 3 + 0); + } + meshGeometry.addAttribute('nextPoint', attribute); + meshGeometry.needsUpdate = true; + + var mesh = new THREE.Mesh(meshGeometry, this.meshMaterial); + this.model.add(mesh); + this.modelBbox = this.computeCameraBoundingBox(); + this.scene.add(this.model); + this.model.updateMatrixWorld(); + this.resetCamera(); + }, + resetCamera: function () { + var bbox = this.modelBbox; + var bboxSize = bbox.size(); + this.aspectRatio = bboxSize.x / bboxSize.y; + this.camera.lookAt(new THREE.Vector3(0, 0, bbox.min.z)); + this.camera.near = 1; + this.camera.position.set(0, 0, bbox.max.z + 10 + this.camera.near); + this.camera.far = this.camera.position.z - bbox.min.z; + this.zRatio = 1 / (this.camera.far - this.camera.near); + this.setCamera(bbox.min.x, bbox.max.x, bbox.min.y, bbox.max.y); + }, + setCamera: function (left, right, bottom, top) { + this.camera.bottom = bottom; + this.camera.top = top; + this.camera.left = left; + this.camera.right = right; + this.camera.updateProjectionMatrix(); + this.camera.updateMatrixWorld(); + }, + pushZInverseProjOn: function (matrix) { + var pos = new THREE.Vector3().setFromMatrixPosition(matrix); + pos.z = this.camera.position.z - this.camera.far; + matrix.scale(new THREE.Vector3(1, 1, this.camera.far - this.camera.near)); + matrix.setPosition(pos); + }, + setAngle: function (angleDeg) { + this.angle = angleDeg; + this.camera.up.set(0, 1, 0).applyAxisAngle(new THREE.Vector3(0, 0, 1), angleDeg * Math.PI / 180); + this.camera.lookAt(this.camera.position.clone().sub(new THREE.Vector3(0, 0, 1))); + this.camera.updateProjectionMatrix(); + this.camera.updateMatrixWorld(); + this.modelBbox = this.computeCameraBoundingBox(); + }, + computeCameraBoundingBox: function () { + var vector = new THREE.Vector3(); + var m = new THREE.Matrix4(); + m.lookAt(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0).applyAxisAngle(new THREE.Vector3(0, 0, 1), -this.angle * Math.PI / 180)); + var boundingBox = new THREE.Box3(); + var positions = this.inputGeometry.attributes.position.array; + if (positions) { + var bb = boundingBox; + bb.makeEmpty(); + for (var i = 0, il = positions.length; i < il; i += 3) { + vector.set(positions[i], positions[i + 1], positions[i + 2]); + vector.applyMatrix4(m); + bb.expandByPoint(vector); + } } - } - if (positions === undefined || positions.length === 0) { - boundingBox.min.set(0, 0, 0); - boundingBox.max.set(0, 0, 0); - } + if (positions === undefined || positions.length === 0) { + boundingBox.min.set(0, 0, 0); + boundingBox.max.set(0, 0, 0); + } - if (isNaN(boundingBox.min.x) || isNaN(boundingBox.min.y) || isNaN(boundingBox.min.z)) { - console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.'); + if (isNaN(boundingBox.min.x) || isNaN(boundingBox.min.y) || isNaN(boundingBox.min.z)) { + console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.'); + } + return boundingBox; } - return boundingBox; - } - }; + }; - return Projector; -}); \ No newline at end of file + return Projector; + }); \ No newline at end of file diff --git a/webapp/cnc/gcode/simulation.js b/webapp/cnc/gcode/simulation.js index 598dafeb..470c831f 100644 --- a/webapp/cnc/gcode/simulation.js +++ b/webapp/cnc/gcode/simulation.js @@ -241,8 +241,6 @@ define(['cnc/util', 'cnc/gcode/geometry'], function (util, geometry) { function discretize(segment) { var type = COMPONENT_TYPES[segment.type]; - - console.log(segment.type, type); var steps = type.simulationSteps(segment); var startTime = currentTime; for (var j = 1; j <= steps; j++) { diff --git a/webapp/cnc/ui/threeDView.js b/webapp/cnc/ui/threeDView.js index 9acc9545..5c26c2f3 100644 --- a/webapp/cnc/ui/threeDView.js +++ b/webapp/cnc/ui/threeDView.js @@ -74,7 +74,7 @@ define(['THREE', 'TWEEN', 'cnc/util', 'libs/threejs/OrbitControls', 'cnc/ui/cube var res = earcut(rawVertices, [], 3); var bufferedGeometry = new THREE.BufferGeometry(); bufferedGeometry.addAttribute('position', new THREE.BufferAttribute(rawVertices, 3)); - bufferedGeometry.addAttribute('index', new THREE.BufferAttribute(new Uint16Array(res), 1)); + bufferedGeometry.setIndex(new THREE.BufferAttribute(new Uint16Array(res), 1)); this.node.add(new THREE.Mesh(bufferedGeometry, this.meshMaterial)); } }, @@ -113,14 +113,14 @@ define(['THREE', 'TWEEN', 'cnc/util', 'libs/threejs/OrbitControls', 'cnc/ui/cube if (this.bufferedGeometry == null) { this.bufferedGeometry = new THREE.BufferGeometry(); this.bufferedGeometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); - this.bufferedGeometry.addAttribute('index', new THREE.BufferAttribute(newIndices, 1)); - this.node.add(new THREE.Line(this.bufferedGeometry, this.lineMaterial, THREE.LinePieces)); + this.bufferedGeometry.setIndex(new THREE.BufferAttribute(newIndices, 1)); + this.node.add(new THREE.LineSegments(this.bufferedGeometry, this.lineMaterial)); } else { var attributes = this.bufferedGeometry.attributes; attributes.position.array = typedArrayConcat(attributes.position.array, vertices, Float32Array); - attributes.index.array = typedArrayConcat(attributes.index.array, newIndices, Uint16Array); + this.bufferedGeometry.index.array = typedArrayConcat(this.bufferedGeometry.index.array, newIndices, Uint16Array); attributes.position.needsUpdate = true; - attributes.index.needsUpdate = true; + this.bufferedGeometry.index.needsUpdate = true; } } }; @@ -247,7 +247,7 @@ define(['THREE', 'TWEEN', 'cnc/util', 'libs/threejs/OrbitControls', 'cnc/ui/cube this.requestAnimationFrameCallback = this.actuallyRender.bind(this); $container.prepend(cubeManipulator(this)); $container.prepend($('
Sorry, there is no mouse selection in this view.
')); - this.rapidToolpathNode = this.createDrawingNode(this.rapidMaterial); + this.rapidToolpathNode = this.createOverlayNode(this.rapidMaterial); this.normalToolpathNode = this.createDrawingNode(this.normalMaterial, new THREE.MeshBasicMaterial({ color: 0x6622BB, opacity: 0.5, diff --git a/webapp/libs/threejs/postprocessing/ShaderPass.js b/webapp/libs/threejs/postprocessing/ShaderPass.js index fdd7fb68..d85b1324 100644 --- a/webapp/libs/threejs/postprocessing/ShaderPass.js +++ b/webapp/libs/threejs/postprocessing/ShaderPass.js @@ -2,57 +2,57 @@ * @author alteredq / http://alteredqualia.com/ */ -THREE.ShaderPass = function (shader, textureID) { +THREE.ShaderPass = function ( shader, textureID ) { - this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; + this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; - this.uniforms = THREE.UniformsUtils.clone(shader.uniforms); - this.material = new THREE.ShaderMaterial({ + this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - defines: shader.defines || {}, - uniforms: this.uniforms, - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader + this.material = new THREE.ShaderMaterial( { - }); + uniforms: this.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader - this.renderToScreen = false; + } ); - this.enabled = true; - this.needsSwap = true; - this.clear = false; + this.renderToScreen = false; + this.enabled = true; + 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); + this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); + this.scene = new THREE.Scene(); + + this.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null ); + this.scene.add( this.quad ); }; THREE.ShaderPass.prototype = { - render: function (renderer, writeBuffer, readBuffer, delta) { + render: function ( renderer, writeBuffer, readBuffer, delta ) { - if (this.uniforms[ this.textureID ]) { + if ( this.uniforms[ this.textureID ] ) { - this.uniforms[ this.textureID ].value = readBuffer; + this.uniforms[ this.textureID ].value = readBuffer; - } + } - this.quad.material = this.material; + this.quad.material = this.material; - if (this.renderToScreen) { + if ( this.renderToScreen ) { - renderer.render(this.scene, this.camera); + renderer.render( this.scene, this.camera ); - } else { + } else { - renderer.render(this.scene, this.camera, writeBuffer, this.clear); + renderer.render( this.scene, this.camera, writeBuffer, this.clear ); - } + } - } + } }; diff --git a/webapp/libs/threejs/three-depthtextures.js b/webapp/libs/threejs/three-depthtextures.js index a526a607..bfb411d3 100644 --- a/webapp/libs/threejs/three-depthtextures.js +++ b/webapp/libs/threejs/three-depthtextures.js @@ -4,46 +4,102 @@ * @author mrdoob / http://mrdoob.com/ */ -var THREE = {REVISION: '72dev'}; +var THREE = { REVISION: '73dev' }; -// browserify support +// + +if ( typeof define === 'function' && define.amd ) { -if (typeof module === 'object') { + define( 'three', THREE ); - module.exports = THREE; +} else if ( 'undefined' !== typeof exports && 'undefined' !== typeof module ) { + + module.exports = THREE; } + // polyfills -if (Math.sign === undefined) { +if ( self.requestAnimationFrame === undefined || self.cancelAnimationFrame === undefined ) { + + // Missing in Android stock browser. + + ( function () { + + var lastTime = 0; + var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; + + for ( var x = 0; x < vendors.length && ! self.requestAnimationFrame; ++ x ) { + + self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; + self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; + + } + + if ( self.requestAnimationFrame === undefined && self.setTimeout !== undefined ) { + + self.requestAnimationFrame = function ( callback ) { + + 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; + + }; - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + } - Math.sign = function (x) { + if ( self.cancelAnimationFrame === undefined && self.clearTimeout !== undefined ) { - return ( x < 0 ) ? -1 : ( x > 0 ) ? 1 : +x; + self.cancelAnimationFrame = function ( id ) { - }; + self.clearTimeout( id ); + + }; + + } + + }() ); } +if ( Math.sign === 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); -}; + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + + Math.sign = function ( x ) { + + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; + + }; + +} + +if ( Function.prototype.name === undefined && Object.defineProperty !== undefined ) { + + // Missing in IE9-11. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name + + Object.defineProperty( Function.prototype, 'name', { + + get: function () { + + return this.toString().match( /^\s*function\s*(\S*)\s*\(/ )[ 1 ]; + } + + } ); + +} // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button -THREE.MOUSE = {LEFT: 0, MIDDLE: 1, RIGHT: 2}; +THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; // GL STATE CONSTANTS @@ -71,7 +127,6 @@ THREE.DoubleSide = 2; // shading -THREE.NoShading = 0; THREE.FlatShading = 1; THREE.SmoothShading = 2; @@ -92,7 +147,7 @@ THREE.CustomBlending = 5; // custom blending equations // (numbers start from 100 not to clash with other -// mappings to OpenGL constants defined in Texture.js) +// mappings to OpenGL constants defined in Texture.js) THREE.AddEquation = 100; THREE.SubtractEquation = 101; @@ -211,48 +266,49 @@ THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; +// Loop styles for AnimationAction + +THREE.LoopOnce = 2200; +THREE.LoopRepeat = 2201; +THREE.LoopPingPong = 2202; // DEPRECATED THREE.Projector = function () { - THREE.error('THREE.Projector has been moved to /examples/js/renderers/Projector.js.'); + console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); - this.projectVector = function (vector, camera) { + this.projectVector = function ( vector, camera ) { - THREE.warn('THREE.Projector: .projectVector() is now vector.project().'); - vector.project(camera); + console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + vector.project( camera ); - }; + }; - this.unprojectVector = function (vector, camera) { + this.unprojectVector = function ( vector, camera ) { - THREE.warn('THREE.Projector: .unprojectVector() is now vector.unproject().'); - vector.unproject(camera); + console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + vector.unproject( camera ); - }; + }; - this.pickingRay = function (vector, camera) { + this.pickingRay = function ( vector, camera ) { - THREE.error('THREE.Projector: .pickingRay() is now raycaster.setFromCamera().'); + console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); - }; + }; }; THREE.CanvasRenderer = function () { - THREE.error('THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js'); + console.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 () { - }; + this.domElement = document.createElement( 'canvas' ); + this.clear = function () {}; + this.render = function () {}; + this.setClearColor = function () {}; + this.setSize = function () {}; }; @@ -262,1077 +318,1053 @@ THREE.CanvasRenderer = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.Color = function (color) { +THREE.Color = function ( color ) { - if (arguments.length === 3) { + if ( arguments.length === 3 ) { - return this.setRGB(arguments[0], arguments[1], arguments[2]); + return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); - } + } - return this.set(color) + return this.set( color ); }; THREE.Color.prototype = { - constructor: THREE.Color, + constructor: THREE.Color, - r: 1, g: 1, b: 1, + r: 1, g: 1, b: 1, - set: function (value) { + set: function ( value ) { - if (value instanceof THREE.Color) { + if ( value instanceof THREE.Color ) { - this.copy(value); + this.copy( value ); - } else if (typeof value === 'number') { + } else if ( typeof value === 'number' ) { - this.setHex(value); + this.setHex( value ); - } else if (typeof value === 'string') { + } else if ( typeof value === 'string' ) { - this.setStyle(value); + this.setStyle( value ); - } + } - return this; + return this; - }, + }, - setHex: function (hex) { + setHex: function ( hex ) { - hex = Math.floor(hex); + hex = Math.floor( hex ); - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - return this; + return this; - }, + }, - setRGB: function (r, g, b) { + setRGB: function ( r, g, b ) { - this.r = r; - this.g = g; - this.b = b; + this.r = r; + this.g = g; + this.b = b; - return this; + return this; - }, + }, - setHSL: function (h, s, l) { + setHSL: function () { - // h,s,l ranges are in 0.0 - 1.0 + function hue2rgb ( p, q, t ) { - if (s === 0) { + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; - this.r = this.g = this.b = l; + } - } else { + return function ( h, s, l ) { - var hue2rgb = function (p, q, t) { + // h,s,l ranges are in 0.0 - 1.0 + h = THREE.Math.euclideanModulo( h, 1 ); + s = THREE.Math.clamp( s, 0, 1 ); + l = THREE.Math.clamp( l, 0, 1 ); - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + ( q - p ) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; + if ( s === 0 ) { - }; + this.r = this.g = this.b = l; - var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - var q = ( 2 * l ) - p; + } else { - this.r = hue2rgb(q, p, h + 1 / 3); - this.g = hue2rgb(q, p, h); - this.b = hue2rgb(q, p, h - 1 / 3); + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; - } + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - return this; + } - }, + return this; - setStyle: function (style) { + }; - // rgb(255,0,0) + }(), - if (/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(style)) { + setStyle: function ( style ) { - var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(style); + var parseAlpha = function ( strAlpha ) { - this.r = Math.min(255, parseInt(color[1], 10)) / 255; - this.g = Math.min(255, parseInt(color[2], 10)) / 255; - this.b = Math.min(255, parseInt(color[3], 10)) / 255; + var alpha = parseFloat( strAlpha ); - return this; + if ( alpha < 1 ) { - } + console.warn( 'THREE.Color: Alpha component of color ' + style + ' will be ignored.' ); - // rgb(100%,0%,0%) + } - if (/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(style)) { + return alpha; - var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(style); + } - this.r = Math.min(100, parseInt(color[1], 10)) / 100; - this.g = Math.min(100, parseInt(color[2], 10)) / 100; - this.b = Math.min(100, parseInt(color[3], 10)) / 100; - return this; + var m; - } + if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { - // #ff0000 + // rgb / hsl - if (/^\#([0-9a-f]{6})$/i.test(style)) { + var color; + var name = m[ 1 ]; + var components = m[ 2 ]; - var color = /^\#([0-9a-f]{6})$/i.exec(style); + switch ( name ) { - this.setHex(parseInt(color[1], 16)); + case 'rgb': - return this; + if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/.exec( components ) ) { - } + // rgb(255,0,0) + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; - // #f00 + return this; - if (/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(style)) { + } - var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(style); + if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*$/.exec( components ) ) { - this.setHex(parseInt(color[1] + color[1] + color[2] + color[2] + color[3] + color[3], 16)); + // rgb(100%,0%,0%) + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - return this; + return this; - } + } - // red + break; - if (/^(\w+)$/i.test(style)) { + case 'rgba': - this.setHex(THREE.ColorKeywords[style]); + if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([0-9]*\.?[0-9]+)\s*$/.exec( components ) ) { - return this; + // rgba(255,0,0,0.5) + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + parseAlpha( color[ 4 ] ); - } + return this; + } - }, + if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*([0-9]*\.?[0-9]+)\s*$/.exec( components ) ) { - copy: function (color) { + // rgba(100%,0%,0%,0.5) + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + parseAlpha( color[ 4 ] ); - this.r = color.r; - this.g = color.g; - this.b = color.b; + return this; - return this; + } - }, + break; - copyGammaToLinear: function (color, gammaFactor) { + case 'hsl': - if (gammaFactor === undefined) gammaFactor = 2.0; + if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*$/.exec( components ) ) { - this.r = Math.pow(color.r, gammaFactor); - this.g = Math.pow(color.g, gammaFactor); - this.b = Math.pow(color.b, gammaFactor); + // hsl(120,50%,50%) + var h = parseFloat( color[ 1 ] ); + var s = parseInt( color[ 2 ], 10 ) / 100; + var l = parseInt( color[ 3 ], 10 ) / 100; - return this; + return this.setHSL( h, s, l ); - }, + } - copyLinearToGamma: function (color, gammaFactor) { + break; - if (gammaFactor === undefined) gammaFactor = 2.0; + case 'hsla': - var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*([0-9]*\.?[0-9]+)\s*$/.exec( components ) ) { - this.r = Math.pow(color.r, safeInverse); - this.g = Math.pow(color.g, safeInverse); - this.b = Math.pow(color.b, safeInverse); + // hsla(120,50%,50%,0.5) + var h = parseFloat( color[ 1 ] ); + var s = parseInt( color[ 2 ], 10 ) / 100; + var l = parseInt( color[ 3 ], 10 ) / 100; + parseAlpha( color[ 4 ] ); - return this; + return this.setHSL( h, s, l ); - }, + } - convertGammaToLinear: function () { + break; - var r = this.r, g = this.g, b = this.b; + } - this.r = r * r; - this.g = g * g; - this.b = b * b; + } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { - return this; + // hex color - }, + var hex = m[ 1 ]; + var size = hex.length; - convertLinearToGamma: function () { + if ( size === 3 ) { - this.r = Math.sqrt(this.r); - this.g = Math.sqrt(this.g); - this.b = Math.sqrt(this.b); + // #ff0 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; - return this; + return this; - }, + } else if ( size === 6 ) { - getHex: function () { + // #ff0000 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + return this; - }, + } - getHexString: function () { + } - return ( '000000' + this.getHex().toString(16) ).slice(-6); + if ( style && style.length > 0 ) { - }, + // color keywords + var hex = THREE.ColorKeywords[ style ]; - getHSL: function (optionalTarget) { + if ( hex !== undefined ) { - // h,s,l ranges are in 0.0 - 1.0 + // red + this.setHex( hex ); - var hsl = optionalTarget || {h: 0, s: 0, l: 0}; + } else { - var r = this.r, g = this.g, b = this.b; + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); - var max = Math.max(r, g, b); - var min = Math.min(r, g, b); + } - var hue, saturation; - var lightness = ( min + max ) / 2.0; + } - if (min === max) { + return this; - hue = 0; - saturation = 0; + }, - } else { + clone: function () { - var delta = max - min; + return new this.constructor( this.r, this.g, this.b ); - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + }, - switch (max) { + copy: function ( color ) { - 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; + this.r = color.r; + this.g = color.g; + this.b = color.b; - } + return this; - hue /= 6; + }, - } + copyGammaToLinear: function ( color, gammaFactor ) { - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; + if ( gammaFactor === undefined ) gammaFactor = 2.0; - return hsl; + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); - }, + return this; - getStyle: function () { + }, - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + copyLinearToGamma: function ( color, gammaFactor ) { - }, + if ( gammaFactor === undefined ) gammaFactor = 2.0; - offsetHSL: function (h, s, l) { + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - var hsl = this.getHSL(); + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); - hsl.h += h; - hsl.s += s; - hsl.l += l; + return this; - this.setHSL(hsl.h, hsl.s, hsl.l); + }, - return this; + convertGammaToLinear: function () { - }, + var r = this.r, g = this.g, b = this.b; - add: function (color) { + this.r = r * r; + this.g = g * g; + this.b = b * b; - this.r += color.r; - this.g += color.g; - this.b += color.b; + return this; - return this; + }, - }, + convertLinearToGamma: function () { - addColors: function (color1, color2) { + this.r = Math.sqrt( this.r ); + this.g = Math.sqrt( this.g ); + this.b = Math.sqrt( this.b ); - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + return this; - return this; + }, - }, + getHex: function () { - addScalar: function (s) { + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - this.r += s; - this.g += s; - this.b += s; + }, - return this; + getHexString: function () { - }, + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - multiply: function (color) { + }, - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + getHSL: function ( optionalTarget ) { - return this; + // h,s,l ranges are in 0.0 - 1.0 - }, + var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; - multiplyScalar: function (s) { + var r = this.r, g = this.g, b = this.b; - this.r *= s; - this.g *= s; - this.b *= s; + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); - return this; + var hue, saturation; + var lightness = ( min + max ) / 2.0; - }, + if ( min === max ) { - lerp: function (color, alpha) { + hue = 0; + saturation = 0; - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + } else { - return this; + var delta = max - min; - }, + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - equals: function (c) { + switch ( max ) { - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + 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; - }, + } - fromArray: function (array) { + hue /= 6; - this.r = array[0]; - this.g = array[1]; - this.b = array[2]; + } - return this; + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; - }, + return hsl; - toArray: function (array, offset) { + }, - if (array === undefined) array = []; - if (offset === undefined) offset = 0; + getStyle: function () { - array[offset] = this.r; - array[offset + 1] = this.g; - array[offset + 2] = this.b; + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - return array; - }, + }, - clone: function () { + offsetHSL: function ( h, s, l ) { - return new THREE.Color().setRGB(this.r, this.g, this.b); + var hsl = this.getHSL(); - } + hsl.h += h; hsl.s += s; hsl.l += l; -}; + this.setHSL( hsl.h, hsl.s, hsl.l ); + + return this; + + }, + + add: function ( color ) { + + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; + + }, + + addColors: function ( color1, color2 ) { + + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; + + }, + + addScalar: function ( s ) { + + this.r += s; + this.g += s; + this.b += s; + + return this; + + }, + + multiply: function ( color ) { + + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.r *= s; + this.g *= s; + this.b *= s; + + return this; + + }, + + lerp: function ( color, alpha ) { + + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; + + }, + + equals: function ( c ) { + + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + + }, + + fromArray: function ( array ) { + + this.r = array[ 0 ]; + this.g = array[ 1 ]; + this.b = array[ 2 ]; + + return this; + + }, + + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + + return array; + + } -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/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Quaternion = function (x, y, z, w) { +THREE.Quaternion = function ( x, y, z, w ) { - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; }; THREE.Quaternion.prototype = { - constructor: THREE.Quaternion, + constructor: THREE.Quaternion, - _x: 0, _y: 0, _z: 0, _w: 0, + get x () { - get x() { + return this._x; - return this._x; + }, - }, + set x ( value ) { - set x(value) { + this._x = value; + this.onChangeCallback(); - this._x = value; - this.onChangeCallback(); + }, - }, + get y () { - get y() { + return this._y; - return this._y; + }, - }, + set y ( value ) { - set y(value) { + this._y = value; + this.onChangeCallback(); - this._y = value; - this.onChangeCallback(); + }, - }, + get z () { - get z() { + return this._z; - return this._z; + }, - }, + set z ( value ) { - set z(value) { + this._z = value; + this.onChangeCallback(); - this._z = value; - this.onChangeCallback(); + }, - }, + get w () { - get w() { + return this._w; - return this._w; + }, - }, + set w ( value ) { - set w(value) { + this._w = value; + this.onChangeCallback(); - this._w = value; - this.onChangeCallback(); + }, - }, + set: function ( x, y, z, w ) { - set: function (x, y, z, w) { + this._x = x; + this._y = y; + this._z = z; + this._w = w; - this._x = x; - this._y = y; - this._z = z; - this._w = w; + this.onChangeCallback(); - this.onChangeCallback(); + return this; - return this; + }, - }, + clone: function () { - copy: function (quaternion) { + return new this.constructor( this._x, this._y, this._z, this._w ); - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + }, - this.onChangeCallback(); + copy: function ( quaternion ) { - return this; + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - }, + this.onChangeCallback(); - setFromEuler: function (euler, update) { + return this; - if (euler instanceof THREE.Euler === false) { + }, - throw new Error('THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.'); - } + setFromEuler: function ( euler, update ) { - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m + if ( euler instanceof THREE.Euler === false ) { - var c1 = Math.cos(euler._x / 2); - var c2 = Math.cos(euler._y / 2); - var c3 = Math.cos(euler._z / 2); - var s1 = Math.sin(euler._x / 2); - var s2 = Math.sin(euler._y / 2); - var s3 = Math.sin(euler._z / 2); + throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - if (euler.order === 'XYZ') { + } - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - } else if (euler.order === 'YXZ') { + var c1 = Math.cos( euler._x / 2 ); + var c2 = Math.cos( euler._y / 2 ); + var c3 = Math.cos( euler._z / 2 ); + var s1 = Math.sin( euler._x / 2 ); + var s2 = Math.sin( euler._y / 2 ); + var s3 = Math.sin( euler._z / 2 ); - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; + var order = euler.order; - } else if (euler.order === 'ZXY') { + if ( order === 'XYZ' ) { - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; - } else if (euler.order === 'ZYX') { + } else if ( order === 'YXZ' ) { - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; - } else if (euler.order === 'YZX') { + } else if ( order === 'ZXY' ) { - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; - } else if (euler.order === 'XZY') { + } else if ( order === 'ZYX' ) { - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; - } + } else if ( order === 'YZX' ) { - if (update !== false) this.onChangeCallback(); + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; - return this; + } else if ( order === 'XZY' ) { - }, + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; - setFromAxisAngle: function (axis, angle) { + } - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + if ( update !== false ) this.onChangeCallback(); - // assumes axis is normalized + return this; - var halfAngle = angle / 2, s = Math.sin(halfAngle); + }, - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos(halfAngle); + setFromAxisAngle: function ( axis, angle ) { - this.onChangeCallback(); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - return this; + // assumes axis is normalized - }, + var halfAngle = angle / 2, s = Math.sin( halfAngle ); - setFromRotationMatrix: function (m) { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + this.onChangeCallback(); - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + return this; - 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], + setFromRotationMatrix: function ( m ) { - trace = m11 + m22 + m33, - s; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - if (trace > 0) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - s = 0.5 / Math.sqrt(trace + 1.0); + var te = m.elements, - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + 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 ], - } else if (m11 > m22 && m11 > m33) { + trace = m11 + m22 + m33, + s; - s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33); + if ( trace > 0 ) { - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + s = 0.5 / Math.sqrt( trace + 1.0 ); - } else if (m22 > m33) { + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33); + } else if ( m11 > m22 && m11 > m33 ) { - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - } else { + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22); + } else if ( m22 > m33 ) { - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - } + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - this.onChangeCallback(); + } else { - return this; + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - }, + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - setFromUnitVectors: function () { + } - // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final + this.onChangeCallback(); - // assumes direction vectors vFrom and vTo are normalized + return this; - var v1, r; + }, - var EPS = 0.000001; + setFromUnitVectors: function () { - return function (vFrom, vTo) { + // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final - if (v1 === undefined) v1 = new THREE.Vector3(); + // assumes direction vectors vFrom and vTo are normalized - r = vFrom.dot(vTo) + 1; + var v1, r; - if (r < EPS) { + var EPS = 0.000001; - r = 0; + return function ( vFrom, vTo ) { - if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { + if ( v1 === undefined ) v1 = new THREE.Vector3(); - v1.set(-vFrom.y, vFrom.x, 0); + r = vFrom.dot( vTo ) + 1; - } else { + if ( r < EPS ) { - v1.set(0, -vFrom.z, vFrom.y); + r = 0; - } + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - } else { + v1.set( - vFrom.y, vFrom.x, 0 ); - v1.crossVectors(vFrom, vTo); + } else { - } + v1.set( 0, - vFrom.z, vFrom.y ); - this._x = v1.x; - this._y = v1.y; - this._z = v1.z; - this._w = r; + } - this.normalize(); + } else { - return this; + v1.crossVectors( vFrom, vTo ); - } + } - }(), + this._x = v1.x; + this._y = v1.y; + this._z = v1.z; + this._w = r; - inverse: function () { + this.normalize(); - this.conjugate().normalize(); + return this; - return this; + } - }, + }(), - conjugate: function () { + inverse: function () { - this._x *= -1; - this._y *= -1; - this._z *= -1; + this.conjugate().normalize(); - this.onChangeCallback(); + return this; - return this; + }, - }, + conjugate: function () { - dot: function (v) { + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + this.onChangeCallback(); - }, + return this; - lengthSq: function () { + }, - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + dot: function ( v ) { - }, + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - length: function () { + }, - return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w); + lengthSq: function () { - }, + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - normalize: function () { + }, - var l = this.length(); + length: function () { - if (l === 0) { + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + }, - } else { + normalize: function () { - l = 1 / l; + var l = this.length(); - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + if ( l === 0 ) { - } + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - this.onChangeCallback(); + } else { - return this; + l = 1 / l; - }, + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - multiply: function (q, p) { + } - if (p !== undefined) { + this.onChangeCallback(); - THREE.warn('THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.'); - return this.multiplyQuaternions(q, p); + return this; - } + }, - return this.multiplyQuaternions(this, q); + multiply: function ( q, p ) { - }, + if ( p !== undefined ) { - multiplyQuaternions: function (a, b) { + console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + } - var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + return this.multiplyQuaternions( this, q ); - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + }, - this.onChangeCallback(); + multiplyQuaternions: function ( a, b ) { - return this; + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - }, + var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - multiplyVector3: function (vector) { + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - THREE.warn('THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.'); - return vector.applyQuaternion(this); + this.onChangeCallback(); - }, + return this; - slerp: function (qb, t) { + }, - if (t === 0) return this; - if (t === 1) return this.copy(qb); + multiplyVector3: function ( vector ) { - var x = this._x, y = this._y, z = this._z, w = this._w; + console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + }, - var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + slerp: function ( qb, t ) { - if (cosHalfTheta < 0) { + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - this._w = -qb._w; - this._x = -qb._x; - this._y = -qb._y; - this._z = -qb._z; + var x = this._x, y = this._y, z = this._z, w = this._w; - cosHalfTheta = -cosHalfTheta; + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - } else { + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - this.copy(qb); + if ( cosHalfTheta < 0 ) { - } + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - if (cosHalfTheta >= 1.0) { + cosHalfTheta = - cosHalfTheta; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + } else { - return this; + this.copy( qb ); - } + } - var halfTheta = Math.acos(cosHalfTheta); - var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if ( cosHalfTheta >= 1.0 ) { - if (Math.abs(sinHalfTheta) < 0.001) { + this._w = w; + this._x = x; + this._y = y; + this._z = z; - this._w = 0.5 * ( w + this._w ); - this._x = 0.5 * ( x + this._x ); - this._y = 0.5 * ( y + this._y ); - this._z = 0.5 * ( z + this._z ); + return this; - return this; + } - } + var halfTheta = Math.acos( cosHalfTheta ); + var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); - var ratioA = Math.sin(( 1 - t ) * halfTheta) / sinHalfTheta, - ratioB = Math.sin(t * halfTheta) / sinHalfTheta; + if ( Math.abs( sinHalfTheta ) < 0.001 ) { - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); + this._w = 0.5 * ( w + this._w ); + this._x = 0.5 * ( x + this._x ); + this._y = 0.5 * ( y + this._y ); + this._z = 0.5 * ( z + this._z ); - this.onChangeCallback(); + return this; - return this; + } - }, + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - equals: function (quaternion) { + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + this.onChangeCallback(); - }, + return this; - fromArray: function (array, offset) { + }, - if (offset === undefined) offset = 0; + equals: function ( quaternion ) { - this._x = array[offset]; - this._y = array[offset + 1]; - this._z = array[offset + 2]; - this._w = array[offset + 3]; + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - this.onChangeCallback(); + }, - return this; + fromArray: function ( array, offset ) { - }, + if ( offset === undefined ) offset = 0; - toArray: function (array, offset) { + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - if (array === undefined) array = []; - if (offset === undefined) offset = 0; + this.onChangeCallback(); - array[offset] = this._x; - array[offset + 1] = this._y; - array[offset + 2] = this._z; - array[offset + 3] = this._w; + return this; - return array; + }, - }, + toArray: function ( array, offset ) { - onChange: function (callback) { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - this.onChangeCallback = callback; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - return this; + return array; - }, + }, - onChangeCallback: function () { - }, + onChange: function ( callback ) { - clone: function () { + this.onChangeCallback = callback; - return new THREE.Quaternion(this._x, this._y, this._z, this._w); + return this; - } + }, + + onChangeCallback: function () {} }; -THREE.Quaternion.slerp = function (qa, qb, qm, t) { +THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { - return qm.copy(qa).slerp(qb, t); + return qm.copy( qa ).slerp( qb, t ); }; @@ -1345,442 +1377,451 @@ THREE.Quaternion.slerp = function (qa, qb, qm, t) { * @author zz85 / http://www.lab4games.net/zz85/blog */ -THREE.Vector2 = function (x, y) { +THREE.Vector2 = function ( x, y ) { - this.x = x || 0; - this.y = y || 0; + this.x = x || 0; + this.y = y || 0; }; THREE.Vector2.prototype = { - constructor: THREE.Vector2, + constructor: THREE.Vector2, - set: function (x, y) { + set: function ( x, y ) { - this.x = x; - this.y = y; + this.x = x; + this.y = y; - return this; + return this; - }, + }, - setX: function (x) { + setX: function ( x ) { - this.x = x; + this.x = x; - return this; + return this; - }, + }, - setY: function (y) { + setY: function ( y ) { - this.y = y; + this.y = y; - return this; + return this; - }, + }, - setComponent: function (index, value) { + setComponent: function ( index, value ) { - switch (index) { + switch ( index ) { - case 0: - this.x = value; - break; - case 1: - this.y = value; - break; - default: - throw new Error('index is out of range: ' + index); + case 0: this.x = value; break; + case 1: this.y = value; break; + default: throw new Error( 'index is out of range: ' + index ); - } + } - }, + }, - getComponent: function (index) { + getComponent: function ( index ) { - switch (index) { + switch ( index ) { - case 0: - return this.x; - case 1: - return this.y; - default: - throw new Error('index is out of range: ' + index); + case 0: return this.x; + case 1: return this.y; + default: throw new Error( 'index is out of range: ' + index ); - } + } - }, + }, - copy: function (v) { + clone: function () { - this.x = v.x; - this.y = v.y; + return new this.constructor( this.x, this.y ); - return this; + }, - }, + copy: function ( v ) { - add: function (v, w) { + this.x = v.x; + this.y = v.y; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.'); - return this.addVectors(v, w); + }, - } + add: function ( v, w ) { - this.x += v.x; - this.y += v.y; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - }, + } - addScalar: function (s) { + this.x += v.x; + this.y += v.y; - this.x += s; - this.y += s; + return this; - 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; - return this; + }, - }, + addVectors: function ( a, b ) { - sub: function (v, w) { + this.x = a.x + b.x; + this.y = a.y + b.y; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.'); - return this.subVectors(v, w); + }, - } + addScaledVector: function ( v, s ) { - this.x -= v.x; - this.y -= v.y; + this.x += v.x * s; + this.y += v.y * s; - return this; + return this; - }, + }, - subScalar: function (s) { + sub: function ( v, w ) { - this.x -= s; - this.y -= s; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); - }, + } - subVectors: function (a, b) { + this.x -= v.x; + this.y -= v.y; - this.x = a.x - b.x; - this.y = a.y - b.y; + return this; - return this; + }, - }, + subScalar: function ( s ) { - multiply: function (v) { + this.x -= s; + this.y -= s; - this.x *= v.x; - this.y *= v.y; + return this; - return this; + }, - }, + subVectors: function ( a, b ) { - multiplyScalar: function (s) { + this.x = a.x - b.x; + this.y = a.y - b.y; - this.x *= s; - this.y *= s; + return this; - return this; + }, - }, + multiply: function ( v ) { - divide: function (v) { + this.x *= v.x; + this.y *= v.y; - this.x /= v.x; - this.y /= v.y; + return this; - return this; + }, - }, + multiplyScalar: function ( s ) { - divideScalar: function (scalar) { + this.x *= s; + this.y *= s; - if (scalar !== 0) { + return this; - var invScalar = 1 / scalar; + }, - this.x *= invScalar; - this.y *= invScalar; + divide: function ( v ) { - } else { + this.x /= v.x; + this.y /= v.y; - this.x = 0; - this.y = 0; + return this; - } + }, - return this; + divideScalar: function ( scalar ) { - }, + if ( scalar !== 0 ) { - min: function (v) { + var invScalar = 1 / scalar; - if (this.x > v.x) { + this.x *= invScalar; + this.y *= invScalar; - this.x = v.x; + } else { - } + this.x = 0; + this.y = 0; - if (this.y > v.y) { + } - this.y = v.y; + return this; - } + }, - return this; + min: function ( v ) { - }, + if ( this.x > v.x ) { - max: function (v) { + this.x = v.x; - if (this.x < v.x) { + } - this.x = v.x; + if ( this.y > v.y ) { - } + this.y = v.y; - if (this.y < v.y) { + } - this.y = v.y; + return this; - } + }, - return this; + max: function ( v ) { - }, + if ( this.x < v.x ) { - clamp: function (min, max) { + this.x = v.x; - // This function assumes min < max, if this assumption isn't true it will not operate correctly + } - if (this.x < min.x) { + if ( this.y < v.y ) { - this.x = min.x; + this.y = v.y; - } else if (this.x > max.x) { + } - this.x = max.x; + return this; - } + }, - if (this.y < min.y) { + clamp: function ( min, max ) { - this.y = min.y; + // This function assumes min < max, if this assumption isn't true it will not operate correctly - } else if (this.y > max.y) { + if ( this.x < min.x ) { - this.y = max.y; + this.x = min.x; - } + } else if ( this.x > max.x ) { - return this; - }, + this.x = max.x; - clampScalar: (function () { + } - var min, max; + if ( this.y < min.y ) { - return function (minVal, maxVal) { + this.y = min.y; - if (min === undefined) { + } else if ( this.y > max.y ) { - min = new THREE.Vector2(); - max = new THREE.Vector2(); + this.y = max.y; - } + } - min.set(minVal, minVal); - max.set(maxVal, maxVal); + return this; - return this.clamp(min, max); + }, - }; + clampScalar: function () { - })(), + var min, max; - floor: function () { + return function clampScalar( minVal, maxVal ) { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); + if ( min === undefined ) { - return this; + min = new THREE.Vector2(); + max = new THREE.Vector2(); - }, + } - ceil: function () { + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); - this.x = Math.ceil(this.x); - this.y = Math.ceil(this.y); + return this.clamp( min, max ); - return this; + }; - }, + }(), - round: function () { + floor: function () { - this.x = Math.round(this.x); - this.y = Math.round(this.y); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); - return this; + return this; - }, + }, - roundToZero: function () { + ceil: 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.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); - return this; + return this; - }, + }, - negate: function () { + round: function () { - this.x = -this.x; - this.y = -this.y; + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); - return this; + return this; - }, + }, - dot: function (v) { + roundToZero: function () { - return this.x * v.x + this.y * v.y; + 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; - lengthSq: function () { + }, - return this.x * this.x + this.y * this.y; + negate: function () { - }, + this.x = - this.x; + this.y = - this.y; - length: function () { + return this; - return Math.sqrt(this.x * this.x + this.y * this.y); + }, - }, + dot: function ( v ) { - normalize: function () { + return this.x * v.x + this.y * v.y; - return this.divideScalar(this.length()); + }, - }, + lengthSq: function () { - distanceTo: function (v) { + return this.x * this.x + this.y * this.y; - return Math.sqrt(this.distanceToSquared(v)); + }, - }, + length: function () { - distanceToSquared: function (v) { + return Math.sqrt( this.x * this.x + this.y * this.y ); - var dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; + }, - }, + lengthManhattan: function() { - setLength: function (l) { + return Math.abs( this.x ) + Math.abs( this.y ); - var oldLength = this.length(); + }, - if (oldLength !== 0 && l !== oldLength) { + normalize: function () { - this.multiplyScalar(l / oldLength); - } + return this.divideScalar( this.length() ); - return this; + }, - }, + distanceTo: function ( v ) { - lerp: function (v, alpha) { + return Math.sqrt( this.distanceToSquared( v ) ); - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; + }, - return this; + distanceToSquared: function ( v ) { - }, + var dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; - lerpVectors: function (v1, v2, alpha) { + }, - this.subVectors(v2, v1).multiplyScalar(alpha).add(v1); + setLength: function ( l ) { - return this; + var oldLength = this.length(); - }, + if ( oldLength !== 0 && l !== oldLength ) { - equals: function (v) { + this.multiplyScalar( l / oldLength ); - return ( ( v.x === this.x ) && ( v.y === this.y ) ); + } - }, + return this; - fromArray: function (array, offset) { + }, - if (offset === undefined) offset = 0; + lerp: function ( v, alpha ) { - this.x = array[offset]; - this.y = array[offset + 1]; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; - return this; + return this; - }, + }, - toArray: function (array, offset) { + lerpVectors: function ( v1, v2, alpha ) { - if (array === undefined) array = []; - if (offset === undefined) offset = 0; + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - array[offset] = this.x; - array[offset + 1] = this.y; + return this; - return array; + }, - }, + equals: function ( v ) { - fromAttribute: function (attribute, index, offset) { + return ( ( v.x === this.x ) && ( v.y === this.y ) ); - if (offset === undefined) offset = 0; + }, - index = index * attribute.itemSize + offset; + fromArray: function ( array, offset ) { - this.x = attribute.array[index]; - this.y = attribute.array[index + 1]; + if ( offset === undefined ) offset = 0; - return this; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; - }, + return this; - clone: function () { + }, - return new THREE.Vector2(this.x, this.y); + toArray: function ( array, offset ) { - } + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + + return array; + + }, + + fromAttribute: function ( attribute, index, offset ) { + + if ( offset === undefined ) offset = 0; + + index = index * attribute.itemSize + offset; + + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + + return this; + + } }; @@ -1795,856 +1836,858 @@ THREE.Vector2.prototype = { * @author WestLangley / http://github.com/WestLangley */ -THREE.Vector3 = function (x, y, z) { +THREE.Vector3 = function ( x, y, z ) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; }; THREE.Vector3.prototype = { - constructor: THREE.Vector3, + constructor: THREE.Vector3, - set: function (x, y, z) { + set: function ( x, y, z ) { - this.x = x; - this.y = y; - this.z = z; + this.x = x; + this.y = y; + this.z = z; - return this; + return this; - }, + }, - setX: function (x) { + setX: function ( x ) { - this.x = x; + this.x = x; - return this; + return this; - }, + }, - setY: function (y) { + setY: function ( y ) { - this.y = y; + this.y = y; - return this; + return this; - }, + }, - setZ: function (z) { + setZ: function ( z ) { - this.z = z; + this.z = z; - return this; + return this; - }, + }, - setComponent: function (index, value) { + setComponent: function ( index, value ) { - switch (index) { + switch ( index ) { - 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); + 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 ); - } + } - }, + }, - getComponent: function (index) { + getComponent: function ( index ) { - switch (index) { + switch ( index ) { - 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); + 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 ); - } + } - }, + }, - copy: function (v) { + clone: function () { - this.x = v.x; - this.y = v.y; - this.z = v.z; + return new this.constructor( this.x, this.y, this.z ); - return this; + }, - }, + copy: function ( v ) { - add: function (v, w) { + this.x = v.x; + this.y = v.y; + this.z = v.z; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.'); - return this.addVectors(v, w); + }, - } + add: function ( v, w ) { - this.x += v.x; - this.y += v.y; - this.z += v.z; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - }, + } - addScalar: function (s) { + this.x += v.x; + this.y += v.y; + this.z += v.z; - this.x += s; - this.y += s; - this.z += s; + return this; - return this; + }, - }, + addScalar: function ( s ) { - addVectors: function (a, b) { + this.x += s; + this.y += s; + this.z += s; - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + return this; - return this; + }, - }, + addVectors: function ( a, b ) { - sub: function (v, w) { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.'); - return this.subVectors(v, w); + }, - } + addScaledVector: function ( v, s ) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; - return this; + return this; - }, + }, - subScalar: function (s) { + sub: function ( v, w ) { - this.x -= s; - this.y -= s; - this.z -= s; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); - }, + } - subVectors: function (a, b) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + return this; - return this; + }, - }, + subScalar: function ( s ) { - multiply: function (v, w) { + this.x -= s; + this.y -= s; + this.z -= s; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.'); - return this.multiplyVectors(v, w); + }, - } + subVectors: function ( a, b ) { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - return this; + return this; - }, + }, - multiplyScalar: function (scalar) { + multiply: function ( v, w ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); - }, + } - multiplyVectors: function (a, b) { + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + return this; - return this; + }, - }, + multiplyScalar: function ( scalar ) { - applyEuler: function () { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - var quaternion; + return this; - return function (euler) { + }, - if (euler instanceof THREE.Euler === false) { + multiplyVectors: function ( a, b ) { - THREE.error('THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.'); + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; - } + return this; - if (quaternion === undefined) quaternion = new THREE.Quaternion(); + }, - this.applyQuaternion(quaternion.setFromEuler(euler)); + applyEuler: function () { - return this; + var quaternion; - }; + return function applyEuler( euler ) { - }(), + if ( euler instanceof THREE.Euler === false ) { - applyAxisAngle: function () { + console.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - var quaternion; + } - return function (axis, angle) { + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - if (quaternion === undefined) quaternion = new THREE.Quaternion(); + this.applyQuaternion( quaternion.setFromEuler( euler ) ); - this.applyQuaternion(quaternion.setFromAxisAngle(axis, angle)); + return this; - return this; + }; - }; + }(), - }(), + applyAxisAngle: function () { - applyMatrix3: function (m) { + var quaternion; - var x = this.x; - var y = this.y; - var z = this.z; + return function applyAxisAngle( axis, angle ) { - var e = m.elements; + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - 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.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); - return this; + return this; - }, + }; - applyMatrix4: function (m) { + }(), - // input: THREE.Matrix4 affine matrix + applyMatrix3: function ( m ) { - var x = this.x, y = this.y, z = this.z; + var x = this.x; + var y = this.y; + var z = this.z; - var e = m.elements; + 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[ 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; + return this; - }, + }, - applyProjection: function (m) { + applyMatrix4: function ( m ) { - // input: THREE.Matrix4 projection matrix + // input: THREE.Matrix4 affine matrix - var x = this.x, y = this.y, z = this.z; + 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 e = m.elements; - 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 ]; + 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; + return this; - }, + }, - applyQuaternion: function (q) { + applyProjection: function ( m ) { - var x = this.x; - var y = this.y; - var z = this.z; + // input: THREE.Matrix4 projection matrix - var qx = q.x; - var qy = q.y; - var qz = q.z; - var qw = q.w; + var x = this.x, y = this.y, z = this.z; - // calculate quat * vector + var e = m.elements; + var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide - 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; + 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; - // calculate result * inverse quat + return this; - 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; + applyQuaternion: function ( q ) { - }, + var x = this.x; + var y = this.y; + var z = this.z; - project: function () { + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; - var matrix; + // calculate quat * vector - return function (camera) { + 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; - if (matrix === undefined) matrix = new THREE.Matrix4(); + // calculate result * inverse quat - matrix.multiplyMatrices(camera.projectionMatrix, matrix.getInverse(camera.matrixWorld)); - return this.applyProjection(matrix); + 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; - }(), + }, - unproject: function () { + project: function () { - var matrix; + var matrix; - return function (camera) { + return function project( camera ) { - if (matrix === undefined) matrix = new THREE.Matrix4(); + if ( matrix === undefined ) matrix = new THREE.Matrix4(); - matrix.multiplyMatrices(camera.matrixWorld, matrix.getInverse(camera.projectionMatrix)); - return this.applyProjection(matrix); + matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); + return this.applyProjection( matrix ); - }; + }; - }(), + }(), - transformDirection: function (m) { + unproject: function () { - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + var matrix; - var x = this.x, y = this.y, z = this.z; + return function unproject( camera ) { - var e = m.elements; + if ( matrix === undefined ) matrix = new THREE.Matrix4(); - 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; + matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); + return this.applyProjection( matrix ); - this.normalize(); + }; - return this; + }(), - }, + transformDirection: function ( m ) { - divide: function (v) { + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + var x = this.x, y = this.y, z = this.z; - return this; + 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; - divideScalar: function (scalar) { + this.normalize(); - if (scalar !== 0) { + return this; - var invScalar = 1 / scalar; + }, - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; + divide: function ( v ) { - } else { + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; - this.x = 0; - this.y = 0; - this.z = 0; + return this; - } + }, - return this; + divideScalar: function ( scalar ) { - }, + if ( scalar !== 0 ) { - min: function (v) { + var invScalar = 1 / scalar; - if (this.x > v.x) { + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; - this.x = v.x; + } else { - } + this.x = 0; + this.y = 0; + this.z = 0; - if (this.y > v.y) { + } - this.y = v.y; + return this; - } + }, - if (this.z > v.z) { + min: function ( v ) { - this.z = v.z; + if ( this.x > v.x ) { - } + this.x = v.x; - return this; + } - }, + if ( this.y > v.y ) { - max: function (v) { + this.y = v.y; - if (this.x < v.x) { + } - this.x = v.x; + if ( this.z > v.z ) { - } + this.z = v.z; - if (this.y < v.y) { + } - this.y = v.y; + return this; - } + }, - if (this.z < v.z) { + max: function ( v ) { - this.z = v.z; + if ( this.x < v.x ) { - } + this.x = v.x; - return this; + } - }, + if ( this.y < v.y ) { - clamp: function (min, max) { + this.y = v.y; - // This function assumes min < max, if this assumption isn't true it will not operate correctly + } - if (this.x < min.x) { + if ( this.z < v.z ) { - this.x = min.x; + this.z = v.z; - } else if (this.x > max.x) { + } - this.x = max.x; + return this; - } + }, - if (this.y < min.y) { + clamp: function ( min, max ) { - this.y = min.y; + // This function assumes min < max, if this assumption isn't true it will not operate correctly - } else if (this.y > max.y) { + if ( this.x < min.x ) { - this.y = max.y; + this.x = min.x; - } + } else if ( this.x > max.x ) { - if (this.z < min.z) { + this.x = max.x; - this.z = min.z; + } - } else if (this.z > max.z) { + if ( this.y < min.y ) { - this.z = max.z; + this.y = min.y; - } + } else if ( this.y > max.y ) { - return this; + this.y = max.y; - }, + } - clampScalar: (function () { + if ( this.z < min.z ) { - var min, max; + this.z = min.z; - return function (minVal, maxVal) { + } else if ( this.z > max.z ) { - if (min === undefined) { + this.z = max.z; - min = new THREE.Vector3(); - max = new THREE.Vector3(); + } - } + return this; - min.set(minVal, minVal, minVal); - max.set(maxVal, maxVal, maxVal); + }, - return this.clamp(min, max); + clampScalar: function () { - }; + var min, max; - })(), + return function clampScalar( minVal, maxVal ) { - floor: function () { + if ( min === undefined ) { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - this.z = Math.floor(this.z); + min = new THREE.Vector3(); + max = new THREE.Vector3(); - return this; + } - }, + min.set( minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal ); - ceil: function () { + return this.clamp( min, max ); - this.x = Math.ceil(this.x); - this.y = Math.ceil(this.y); - this.z = Math.ceil(this.z); + }; - return this; + }(), - }, + floor: function () { - round: function () { + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - this.x = Math.round(this.x); - this.y = Math.round(this.y); - this.z = Math.round(this.z); + return this; - return this; + }, - }, + ceil: function () { - roundToZero: function () { + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - 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; - return this; + }, - }, + round: function () { - negate: function () { + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); - this.x = -this.x; - this.y = -this.y; - this.z = -this.z; + return this; - return this; + }, - }, + roundToZero: function () { - dot: function (v) { + 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.x * v.x + this.y * v.y + this.z * v.z; + return this; - }, + }, - lengthSq: function () { + negate: function () { - return this.x * this.x + this.y * this.y + this.z * this.z; + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; - }, + return this; - length: function () { + }, - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + dot: function ( v ) { - }, + return this.x * v.x + this.y * v.y + this.z * v.z; - lengthManhattan: function () { + }, - return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z); + lengthSq: function () { - }, + return this.x * this.x + this.y * this.y + this.z * this.z; - normalize: function () { + }, - return this.divideScalar(this.length()); + length: function () { - }, + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - setLength: function (l) { + }, - var oldLength = this.length(); + lengthManhattan: function () { - if (oldLength !== 0 && l !== oldLength) { + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - this.multiplyScalar(l / oldLength); - } + }, - return this; + normalize: function () { - }, + return this.divideScalar( this.length() ); - lerp: function (v, alpha) { + }, - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + setLength: function ( l ) { - return this; + var oldLength = this.length(); - }, + if ( oldLength !== 0 && l !== oldLength ) { - lerpVectors: function (v1, v2, alpha) { + this.multiplyScalar( l / oldLength ); - this.subVectors(v2, v1).multiplyScalar(alpha).add(v1); + } - return this; + return this; - }, + }, - cross: function (v, w) { + lerp: function ( v, alpha ) { - if (w !== undefined) { + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; - THREE.warn('THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.'); - return this.crossVectors(v, w); + return this; - } + }, - var x = this.x, y = this.y, z = this.z; + lerpVectors: function ( v1, v2, alpha ) { - this.x = y * v.z - z * v.y; - this.y = z * v.x - x * v.z; - this.z = x * v.y - y * v.x; + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; - }, + }, - crossVectors: function (a, b) { + cross: function ( v, w ) { - var ax = a.x, ay = a.y, az = a.z; - var bx = b.x, by = b.y, bz = b.z; + if ( w !== undefined ) { - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); - return this; + } - }, + var x = this.x, y = this.y, z = this.z; - projectOnVector: function () { + this.x = y * v.z - z * v.y; + this.y = z * v.x - x * v.z; + this.z = x * v.y - y * v.x; - var v1, dot; + return this; - return function (vector) { + }, - if (v1 === undefined) v1 = new THREE.Vector3(); + crossVectors: function ( a, b ) { - v1.copy(vector).normalize(); + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; - dot = this.dot(v1); + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; - return this.copy(v1).multiplyScalar(dot); + return this; - }; + }, - }(), + projectOnVector: function () { - projectOnPlane: function () { + var v1, dot; - var v1; + return function projectOnVector( vector ) { - return function (planeNormal) { + if ( v1 === undefined ) v1 = new THREE.Vector3(); - if (v1 === undefined) v1 = new THREE.Vector3(); + v1.copy( vector ).normalize(); - v1.copy(this).projectOnVector(planeNormal); + dot = this.dot( v1 ); - return this.sub(v1); + return this.copy( v1 ).multiplyScalar( dot ); - } + }; - }(), + }(), - reflect: function () { + projectOnPlane: function () { - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length + var v1; - var v1; + return function projectOnPlane( planeNormal ) { - return function (normal) { + if ( v1 === undefined ) v1 = new THREE.Vector3(); - if (v1 === undefined) v1 = new THREE.Vector3(); + v1.copy( this ).projectOnVector( planeNormal ); - return this.sub(v1.copy(normal).multiplyScalar(2 * this.dot(normal))); + return this.sub( v1 ); - } + } - }(), + }(), - angleTo: function (v) { + reflect: function () { - var theta = this.dot(v) / ( this.length() * v.length() ); + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - // clamp, to handle numerical problems + var v1; - return Math.acos(THREE.Math.clamp(theta, -1, 1)); + return function reflect( normal ) { - }, + if ( v1 === undefined ) v1 = new THREE.Vector3(); - distanceTo: function (v) { + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - return Math.sqrt(this.distanceToSquared(v)); + } - }, + }(), - distanceToSquared: function (v) { + angleTo: function ( v ) { - var dx = this.x - v.x; - var dy = this.y - v.y; - var dz = this.z - v.z; + var theta = this.dot( v ) / ( this.length() * v.length() ); - return dx * dx + dy * dy + dz * dz; + // clamp, to handle numerical problems - }, + return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) ); - setEulerFromRotationMatrix: function (m, order) { + }, - THREE.error('THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.'); + distanceTo: function ( v ) { - }, + return Math.sqrt( this.distanceToSquared( v ) ); - setEulerFromQuaternion: function (q, order) { + }, - THREE.error('THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.'); + distanceToSquared: function ( v ) { - }, + var dx = this.x - v.x; + var dy = this.y - v.y; + var dz = this.z - v.z; - getPositionFromMatrix: function (m) { + return dx * dx + dy * dy + dz * dz; - THREE.warn('THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().'); + }, - return this.setFromMatrixPosition(m); + setEulerFromRotationMatrix: function ( m, order ) { - }, + console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - getScaleFromMatrix: function (m) { + }, - THREE.warn('THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().'); + setEulerFromQuaternion: function ( q, order ) { - return this.setFromMatrixScale(m); - }, + console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - getColumnFromMatrix: function (index, matrix) { + }, - THREE.warn('THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().'); + getPositionFromMatrix: function ( m ) { - return this.setFromMatrixColumn(index, matrix); + console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - }, + return this.setFromMatrixPosition( m ); - setFromMatrixPosition: function (m) { + }, - this.x = m.elements[12]; - this.y = m.elements[13]; - this.z = m.elements[14]; + getScaleFromMatrix: function ( m ) { - return this; + console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - }, + return this.setFromMatrixScale( m ); - setFromMatrixScale: 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(); + getColumnFromMatrix: function ( index, matrix ) { - this.x = sx; - this.y = sy; - this.z = sz; + console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return this; - }, + return this.setFromMatrixColumn( index, matrix ); - setFromMatrixColumn: function (index, matrix) { + }, - var offset = index * 4; + setFromMatrixPosition: function ( m ) { - var me = matrix.elements; + this.x = m.elements[ 12 ]; + this.y = m.elements[ 13 ]; + this.z = m.elements[ 14 ]; - this.x = me[offset]; - this.y = me[offset + 1]; - this.z = me[offset + 2]; + return this; - return this; + }, - }, + setFromMatrixScale: function ( m ) { - equals: function (v) { + 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 ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + this.x = sx; + this.y = sy; + this.z = sz; - }, + return this; - fromArray: function (array, offset) { + }, - if (offset === undefined) offset = 0; + setFromMatrixColumn: function ( index, matrix ) { - this.x = array[offset]; - this.y = array[offset + 1]; - this.z = array[offset + 2]; + var offset = index * 4; - return this; + var me = matrix.elements; - }, + this.x = me[ offset ]; + this.y = me[ offset + 1 ]; + this.z = me[ offset + 2 ]; - toArray: function (array, offset) { + return this; - if (array === undefined) array = []; - if (offset === undefined) offset = 0; + }, - array[offset] = this.x; - array[offset + 1] = this.y; - array[offset + 2] = this.z; + equals: function ( v ) { - return array; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - }, + }, - fromAttribute: function (attribute, index, offset) { + fromArray: function ( array, offset ) { - if (offset === undefined) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; - this.x = attribute.array[index]; - this.y = attribute.array[index + 1]; - this.z = attribute.array[index + 2]; + return this; - return this; + }, - }, + toArray: function ( array, offset ) { - clone: function () { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return new THREE.Vector3(this.x, this.y, this.z); + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - } + return array; + + }, + + fromAttribute: function ( attribute, index, offset ) { + + 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 ]; + + return this; + + } }; @@ -2658,701 +2701,704 @@ THREE.Vector3.prototype = { * @author WestLangley / http://github.com/WestLangley */ -THREE.Vector4 = function (x, y, z, w) { +THREE.Vector4 = function ( x, y, z, w ) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; }; THREE.Vector4.prototype = { - constructor: THREE.Vector4, + constructor: THREE.Vector4, - set: function (x, y, z, w) { + set: function ( x, y, z, w ) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - return this; + return this; - }, + }, - setX: function (x) { + setX: function ( x ) { - this.x = x; + this.x = x; - return this; + return this; - }, + }, - setY: function (y) { + setY: function ( y ) { - this.y = y; + this.y = y; - return this; + return this; - }, + }, - setZ: function (z) { + setZ: function ( z ) { - this.z = z; + this.z = z; - return this; + return this; - }, + }, - setW: function (w) { + setW: function ( w ) { - this.w = w; + this.w = w; - return this; + return this; - }, + }, - setComponent: function (index, value) { + setComponent: function ( index, value ) { - switch (index) { + switch ( index ) { - case 0: - this.x = value; - break; - 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); + case 0: this.x = value; break; + 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 ); - } + } - }, + }, - getComponent: function (index) { + getComponent: function ( index ) { - switch (index) { + switch ( index ) { - case 0: - return this.x; - 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); + case 0: return this.x; + 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 ); - } + } - }, + }, - copy: function (v) { + clone: function () { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + return new this.constructor( this.x, this.y, this.z, this.w ); - return this; + }, - }, + copy: function ( v ) { - add: function (v, w) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.'); - return this.addVectors(v, w); + }, - } + add: function ( v, w ) { - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - }, + } - addScalar: function (s) { + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - this.x += s; - this.y += s; - this.z += s; - this.w += s; + return this; - return this; + }, - }, + addScalar: function ( s ) { - addVectors: function (a, b) { + this.x += s; + this.y += s; + this.z += s; + this.w += s; - 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; - return this; + }, - }, + addVectors: function ( a, b ) { - sub: function (v, w) { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - if (w !== undefined) { + return this; - THREE.warn('THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.'); - return this.subVectors(v, w); + }, - } + addScaledVector: function ( v, s ) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; - return this; + return this; - }, + }, - subScalar: function (s) { + sub: function ( v, w ) { - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + if ( w !== undefined ) { - return this; + console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); - }, + } - subVectors: function (a, b) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; - 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; - return this; + }, - }, + subScalar: function ( s ) { - multiplyScalar: function (scalar) { + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + return this; - return this; + }, - }, + subVectors: function ( a, b ) { - applyMatrix4: function (m) { + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - var x = this.x; - var y = this.y; - var z = this.z; - var w = this.w; + return this; - 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; + multiplyScalar: function ( scalar ) { - return this; + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - }, + return this; - divideScalar: function (scalar) { + }, - if (scalar !== 0) { + applyMatrix4: function ( m ) { - var invScalar = 1 / scalar; + var x = this.x; + var y = this.y; + var z = this.z; + var w = this.w; - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - this.w *= invScalar; + var e = m.elements; - } else { + 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 = 0; - this.y = 0; - this.z = 0; - this.w = 1; + return this; - } + }, - return this; + divideScalar: function ( scalar ) { - }, + if ( scalar !== 0 ) { - setAxisAngleFromQuaternion: function (q) { + var invScalar = 1 / scalar; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + this.w *= invScalar; - // q is assumed to be normalized + } else { - this.w = 2 * Math.acos(q.w); + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; - var s = Math.sqrt(1 - q.w * q.w); + } - if (s < 0.0001) { + return this; - this.x = 1; - this.y = 0; - this.z = 0; + }, - } else { + setAxisAngleFromQuaternion: function ( q ) { - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - } + // q is assumed to be normalized - return this; + this.w = 2 * Math.acos( q.w ); - }, + var s = Math.sqrt( 1 - q.w * q.w ); - setAxisAngleFromRotationMatrix: function (m) { + if ( s < 0.0001 ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + this.x = 1; + this.y = 0; + this.z = 0; - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + } else { - var angle, x, y, z, // variables for result - epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - 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]; + return this; - if (( Math.abs(m12 - m21) < 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 + setAxisAngleFromRotationMatrix: function ( m ) { - if (( Math.abs(m12 + m21) < epsilon2 ) - && ( Math.abs(m13 + m31) < epsilon2 ) - && ( Math.abs(m23 + m32) < epsilon2 ) - && ( Math.abs(m11 + m22 + m33 - 3) < epsilon2 )) { + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - // this singularity is identity matrix so angle = 0 + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - this.set(1, 0, 0, 0); + var angle, x, y, z, // variables for result + epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - return this; // zero angle, arbitrary axis + 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 ]; - // otherwise this singularity is angle = 180 + if ( ( Math.abs( m12 - m21 ) < epsilon ) + && ( Math.abs( m13 - m31 ) < epsilon ) + && ( Math.abs( m23 - m32 ) < epsilon ) ) { - angle = Math.PI; + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - var xx = ( m11 + 1 ) / 2; - var yy = ( m22 + 1 ) / 2; - var zz = ( m33 + 1 ) / 2; - var xy = ( m12 + m21 ) / 4; - var xz = ( m13 + m31 ) / 4; - var yz = ( m23 + m32 ) / 4; + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) + && ( Math.abs( m13 + m31 ) < epsilon2 ) + && ( Math.abs( m23 + m32 ) < epsilon2 ) + && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - if (( xx > yy ) && ( xx > zz )) { // m11 is the largest diagonal term + // this singularity is identity matrix so angle = 0 - if (xx < epsilon) { + this.set( 1, 0, 0, 0 ); - x = 0; - y = 0.707106781; - z = 0.707106781; + return this; // zero angle, arbitrary axis - } else { + } - x = Math.sqrt(xx); - y = xy / x; - z = xz / x; + // otherwise this singularity is angle = 180 - } + angle = Math.PI; - } else if (yy > zz) { // m22 is the largest diagonal term + var xx = ( m11 + 1 ) / 2; + var yy = ( m22 + 1 ) / 2; + var zz = ( m33 + 1 ) / 2; + var xy = ( m12 + m21 ) / 4; + var xz = ( m13 + m31 ) / 4; + var yz = ( m23 + m32 ) / 4; - if (yy < epsilon) { + if ( ( xx > yy ) && ( xx > zz ) ) { - x = 0.707106781; - y = 0; - z = 0.707106781; + // m11 is the largest diagonal term - } else { + if ( xx < epsilon ) { - y = Math.sqrt(yy); - x = xy / y; - z = yz / y; + x = 0; + y = 0.707106781; + z = 0.707106781; - } + } else { - } else { // m33 is the largest diagonal term so base result on this + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - if (zz < epsilon) { + } - x = 0.707106781; - y = 0.707106781; - z = 0; + } else if ( yy > zz ) { - } else { + // m22 is the largest diagonal term - z = Math.sqrt(zz); - x = xz / z; - y = yz / z; + if ( yy < epsilon ) { - } + x = 0.707106781; + y = 0; + z = 0.707106781; - } + } else { - this.set(x, y, z, angle); + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - return this; // return 180 deg rotation + } - } + } else { - // as we have reached here there are no singularities so we can handle normally + // m33 is the largest diagonal term so base result on this - var s = Math.sqrt(( m32 - m23 ) * ( m32 - m23 ) - + ( m13 - m31 ) * ( m13 - m31 ) - + ( m21 - m12 ) * ( m21 - m12 )); // used to normalize + if ( zz < epsilon ) { - if (Math.abs(s) < 0.001) s = 1; + x = 0.707106781; + y = 0.707106781; + z = 0; - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case + } else { - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos(( m11 + m22 + m33 - 1 ) / 2); + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - return this; + } - }, + } - min: function (v) { + this.set( x, y, z, angle ); - if (this.x > v.x) { + return this; // return 180 deg rotation - this.x = v.x; + } - } + // as we have reached here there are no singularities so we can handle normally - if (this.y > v.y) { + var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - this.y = v.y; + if ( Math.abs( s ) < 0.001 ) s = 1; - } + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case - if (this.z > v.z) { + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - this.z = v.z; + return this; - } + }, - if (this.w > v.w) { + min: function ( v ) { - this.w = v.w; + if ( this.x > v.x ) { - } + this.x = v.x; - return this; + } - }, + if ( this.y > v.y ) { - max: function (v) { + this.y = v.y; - if (this.x < v.x) { + } - this.x = v.x; + if ( this.z > v.z ) { - } + this.z = v.z; - if (this.y < v.y) { + } - this.y = v.y; + if ( this.w > v.w ) { - } + this.w = v.w; - if (this.z < v.z) { + } - this.z = v.z; + return this; - } + }, - if (this.w < v.w) { + max: function ( v ) { - this.w = v.w; + if ( this.x < v.x ) { - } + this.x = v.x; - return this; + } - }, + if ( this.y < v.y ) { - clamp: function (min, max) { + this.y = v.y; - // This function assumes min < max, if this assumption isn't true it will not operate correctly + } - if (this.x < min.x) { + if ( this.z < v.z ) { - this.x = min.x; + this.z = v.z; - } else if (this.x > max.x) { + } - this.x = max.x; + if ( this.w < v.w ) { - } + this.w = v.w; - if (this.y < min.y) { + } - this.y = min.y; + return this; - } else if (this.y > max.y) { + }, - this.y = max.y; + clamp: function ( min, max ) { - } + // This function assumes min < max, if this assumption isn't true it will not operate correctly - if (this.z < min.z) { + if ( this.x < min.x ) { - this.z = min.z; + this.x = min.x; - } else if (this.z > max.z) { + } else if ( this.x > max.x ) { - this.z = max.z; + this.x = max.x; - } + } - if (this.w < min.w) { + if ( this.y < min.y ) { - this.w = min.w; + this.y = min.y; - } else if (this.w > max.w) { + } else if ( this.y > max.y ) { - this.w = max.w; + this.y = max.y; - } + } - return this; + if ( this.z < min.z ) { - }, + this.z = min.z; - clampScalar: (function () { + } else if ( this.z > max.z ) { - var min, max; + this.z = max.z; - return function (minVal, maxVal) { + } - if (min === undefined) { + if ( this.w < min.w ) { - min = new THREE.Vector4(); - max = new THREE.Vector4(); + this.w = min.w; - } + } else if ( this.w > max.w ) { - min.set(minVal, minVal, minVal, minVal); - max.set(maxVal, maxVal, maxVal, maxVal); + this.w = max.w; - return this.clamp(min, max); + } - }; + return this; - })(), + }, - floor: function () { + clampScalar: 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); + var min, max; - return this; + return function clampScalar( minVal, maxVal ) { - }, + if ( min === undefined ) { - ceil: function () { + min = new THREE.Vector4(); + max = new THREE.Vector4(); - 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; + min.set( minVal, minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal, maxVal ); - }, + return this.clamp( min, max ); - 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; + 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 ); - roundToZero: function () { + return this; - 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; + 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 ); - negate: function () { + return this; - this.x = -this.x; - this.y = -this.y; - this.z = -this.z; - this.w = -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 ); - dot: function (v) { + return this; - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + }, - }, + roundToZero: function () { - lengthSq: 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.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + return this; - }, + }, - length: function () { + negate: function () { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - }, + return this; - lengthManhattan: function () { + }, - return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w); + dot: function ( v ) { - }, + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - normalize: function () { + }, - return this.divideScalar(this.length()); + lengthSq: function () { - }, + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - setLength: function (l) { + }, - var oldLength = this.length(); + length: function () { - if (oldLength !== 0 && l !== oldLength) { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - this.multiplyScalar(l / oldLength); + }, - } + lengthManhattan: function () { - return this; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - }, + }, - lerp: function (v, alpha) { + normalize: function () { - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; + return this.divideScalar( this.length() ); - return this; + }, - }, + setLength: function ( l ) { - lerpVectors: function (v1, v2, alpha) { + var oldLength = this.length(); - this.subVectors(v2, v1).multiplyScalar(alpha).add(v1); + if ( oldLength !== 0 && l !== oldLength ) { - return this; + this.multiplyScalar( l / oldLength ); - }, + } - equals: function (v) { + return this; - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + }, - }, + lerp: function ( v, alpha ) { - fromArray: function (array, offset) { + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - if (offset === undefined) offset = 0; + return this; - this.x = array[offset]; - this.y = array[offset + 1]; - this.z = array[offset + 2]; - this.w = array[offset + 3]; + }, - return this; + lerpVectors: function ( v1, v2, alpha ) { - }, + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - toArray: function (array, offset) { + return this; - 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; + equals: function ( v ) { - return array; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - }, + }, - fromAttribute: function (attribute, index, offset) { + fromArray: function ( array, offset ) { - if (offset === undefined) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; - 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; - return this; + }, - }, + toArray: function ( array, offset ) { - clone: function () { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return new THREE.Vector4(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; + + }, + + fromAttribute: function ( attribute, index, offset ) { + + 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; + + } }; @@ -3361,1050 +3407,1051 @@ THREE.Vector4.prototype = { /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Euler = function (x, y, z, order) { +THREE.Euler = function ( x, y, z, order ) { - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || THREE.Euler.DefaultOrder; + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || THREE.Euler.DefaultOrder; }; -THREE.Euler.RotationOrders = ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX']; +THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; THREE.Euler.DefaultOrder = 'XYZ'; THREE.Euler.prototype = { - constructor: THREE.Euler, + constructor: THREE.Euler, - _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, + get x () { - get x() { + return this._x; - return this._x; + }, - }, + set x ( value ) { - set x(value) { + this._x = value; + this.onChangeCallback(); - this._x = value; - this.onChangeCallback(); + }, - }, + get y () { - get y() { + return this._y; - return this._y; + }, - }, + set y ( value ) { - set y(value) { + this._y = value; + this.onChangeCallback(); - this._y = value; - this.onChangeCallback(); + }, - }, + get z () { - get z() { + return this._z; - return this._z; + }, - }, + set z ( value ) { - set z(value) { + this._z = value; + this.onChangeCallback(); - this._z = value; - this.onChangeCallback(); + }, - }, + get order () { - get order() { + return this._order; - return this._order; + }, - }, + set order ( value ) { - set order(value) { + this._order = value; + this.onChangeCallback(); - this._order = value; - this.onChangeCallback(); + }, - }, + set: function ( x, y, z, order ) { - set: function (x, y, z, order) { + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; + this.onChangeCallback(); - this.onChangeCallback(); + return this; - return this; + }, - }, + clone: function () { - copy: function (euler) { + return new this.constructor( this._x, this._y, this._z, this._order); - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + }, - this.onChangeCallback(); + copy: function ( euler ) { - return this; + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; - }, + this.onChangeCallback(); - setFromRotationMatrix: function (m, order, update) { + return this; - var clamp = THREE.Math.clamp; + }, - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + setFromRotationMatrix: function ( m, order, update ) { - 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 clamp = THREE.Math.clamp; - order = order || this._order; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - if (order === 'XYZ') { + 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 ]; - this._y = Math.asin(clamp(m13, -1, 1)); + order = order || this._order; - if (Math.abs(m13) < 0.99999) { + if ( order === 'XYZ' ) { - this._x = Math.atan2(-m23, m33); - this._z = Math.atan2(-m12, m11); + this._y = Math.asin( clamp( m13, - 1, 1 ) ); - } else { + if ( Math.abs( m13 ) < 0.99999 ) { - this._x = Math.atan2(m32, m22); - this._z = 0; + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); - } + } else { - } else if (order === 'YXZ') { + this._x = Math.atan2( m32, m22 ); + this._z = 0; - this._x = Math.asin(-clamp(m23, -1, 1)); + } - if (Math.abs(m23) < 0.99999) { + } else if ( order === 'YXZ' ) { - this._y = Math.atan2(m13, m33); - this._z = Math.atan2(m21, m22); + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - } else { + if ( Math.abs( m23 ) < 0.99999 ) { - this._y = Math.atan2(-m31, m11); - this._z = 0; + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); - } + } else { - } else if (order === 'ZXY') { + this._y = Math.atan2( - m31, m11 ); + this._z = 0; - this._x = Math.asin(clamp(m32, -1, 1)); + } - if (Math.abs(m32) < 0.99999) { + } else if ( order === 'ZXY' ) { - this._y = Math.atan2(-m31, m33); - this._z = Math.atan2(-m12, m22); + this._x = Math.asin( clamp( m32, - 1, 1 ) ); - } else { + if ( Math.abs( m32 ) < 0.99999 ) { - this._y = 0; - this._z = Math.atan2(m21, m11); + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); - } + } else { - } else if (order === 'ZYX') { + this._y = 0; + this._z = Math.atan2( m21, m11 ); - this._y = Math.asin(-clamp(m31, -1, 1)); + } - if (Math.abs(m31) < 0.99999) { + } else if ( order === 'ZYX' ) { - this._x = Math.atan2(m32, m33); - this._z = Math.atan2(m21, m11); + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - } else { + if ( Math.abs( m31 ) < 0.99999 ) { - this._x = 0; - this._z = Math.atan2(-m12, m22); + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); - } + } else { - } else if (order === 'YZX') { + this._x = 0; + this._z = Math.atan2( - m12, m22 ); - this._z = Math.asin(clamp(m21, -1, 1)); + } - if (Math.abs(m21) < 0.99999) { + } else if ( order === 'YZX' ) { - this._x = Math.atan2(-m23, m22); - this._y = Math.atan2(-m31, m11); + this._z = Math.asin( clamp( m21, - 1, 1 ) ); - } else { + if ( Math.abs( m21 ) < 0.99999 ) { - this._x = 0; - this._y = Math.atan2(m13, m33); + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); - } + } else { - } else if (order === 'XZY') { + this._x = 0; + this._y = Math.atan2( m13, m33 ); - this._z = Math.asin(-clamp(m12, -1, 1)); + } - if (Math.abs(m12) < 0.99999) { + } else if ( order === 'XZY' ) { - this._x = Math.atan2(m32, m22); - this._y = Math.atan2(m13, m11); + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - } else { + if ( Math.abs( m12 ) < 0.99999 ) { - this._x = Math.atan2(-m23, m33); - this._y = 0; + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); - } + } else { - } else { + this._x = Math.atan2( - m23, m33 ); + this._y = 0; - THREE.warn('THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order) + } - } + } else { - this._order = order; + console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) - if (update !== false) this.onChangeCallback(); + } - return this; + this._order = order; - }, + if ( update !== false ) this.onChangeCallback(); - setFromQuaternion: function () { + return this; - var matrix; + }, - return function (q, order, update) { + setFromQuaternion: function () { - if (matrix === undefined) matrix = new THREE.Matrix4(); - matrix.makeRotationFromQuaternion(q); - this.setFromRotationMatrix(matrix, order, update); + var matrix; - return this; + return function ( q, order, update ) { - }; + if ( matrix === undefined ) matrix = new THREE.Matrix4(); + matrix.makeRotationFromQuaternion( q ); + this.setFromRotationMatrix( matrix, order, update ); - }(), + return this; - setFromVector3: function (v, order) { + }; - return this.set(v.x, v.y, v.z, order || this._order); + }(), - }, + setFromVector3: function ( v, order ) { - reorder: function () { + return this.set( v.x, v.y, v.z, order || this._order ); - // WARNING: this discards revolution information -bhouston + }, - var q = new THREE.Quaternion(); + reorder: function () { - return function (newOrder) { + // WARNING: this discards revolution information -bhouston - q.setFromEuler(this); - this.setFromQuaternion(q, newOrder); + var q = new THREE.Quaternion(); - }; + return function ( newOrder ) { - }(), + q.setFromEuler( this ); + this.setFromQuaternion( q, newOrder ); - equals: function (euler) { + }; - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + }(), - }, + equals: function ( euler ) { - fromArray: function (array) { + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - this._x = array[0]; - this._y = array[1]; - this._z = array[2]; - if (array[3] !== undefined) this._order = array[3]; + }, - this.onChangeCallback(); + fromArray: function ( array ) { - return this; + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - }, + this.onChangeCallback(); - toArray: function (array, offset) { + return this; - 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._order; + toArray: function ( array, offset ) { - return array; - }, + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - toVector3: function (optionalResult) { + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; - if (optionalResult) { + return array; - return optionalResult.set(this._x, this._y, this._z); + }, - } else { + toVector3: function ( optionalResult ) { - return new THREE.Vector3(this._x, this._y, this._z); + if ( optionalResult ) { - } + return optionalResult.set( this._x, this._y, this._z ); - }, + } else { - onChange: function (callback) { + return new THREE.Vector3( this._x, this._y, this._z ); - this.onChangeCallback = callback; + } - return this; + }, - }, + onChange: function ( callback ) { - onChangeCallback: function () { - }, + this.onChangeCallback = callback; - clone: function () { + return this; - return new THREE.Euler(this._x, this._y, this._z, this._order); + }, - } + onChangeCallback: function () {} }; // File:src/math/Line3.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Line3 = function (start, end) { +THREE.Line3 = function ( start, end ) { - this.start = ( start !== undefined ) ? start : new THREE.Vector3(); - this.end = ( end !== undefined ) ? end : new THREE.Vector3(); + this.start = ( start !== undefined ) ? start : new THREE.Vector3(); + this.end = ( end !== undefined ) ? end : new THREE.Vector3(); }; THREE.Line3.prototype = { - constructor: THREE.Line3, + constructor: THREE.Line3, - set: function (start, end) { + set: function ( start, end ) { - this.start.copy(start); - this.end.copy(end); + this.start.copy( start ); + this.end.copy( end ); - return this; + return this; - }, + }, - copy: function (line) { + clone: function () { - this.start.copy(line.start); - this.end.copy(line.end); + return new this.constructor().copy( this ); - return this; + }, - }, + copy: function ( line ) { - center: function (optionalTarget) { + this.start.copy( line.start ); + this.end.copy( line.end ); - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors(this.start, this.end).multiplyScalar(0.5); + return this; - }, + }, - delta: function (optionalTarget) { + center: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors(this.end, this.start); + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - }, + }, - distanceSq: function () { + delta: function ( optionalTarget ) { - return this.start.distanceToSquared(this.end); + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.end, this.start ); - }, + }, - distance: function () { + distanceSq: function () { - return this.start.distanceTo(this.end); + return this.start.distanceToSquared( this.end ); - }, + }, - at: function (t, optionalTarget) { + distance: function () { - var result = optionalTarget || new THREE.Vector3(); + return this.start.distanceTo( this.end ); - return this.delta(result).multiplyScalar(t).add(this.start); + }, - }, + at: function ( t, optionalTarget ) { - closestPointToPointParameter: function () { + var result = optionalTarget || new THREE.Vector3(); - var startP = new THREE.Vector3(); - var startEnd = new THREE.Vector3(); + return this.delta( result ).multiplyScalar( t ).add( this.start ); - return function (point, clampToLine) { + }, - startP.subVectors(point, this.start); - startEnd.subVectors(this.end, this.start); + closestPointToPointParameter: function () { - var startEnd2 = startEnd.dot(startEnd); - var startEnd_startP = startEnd.dot(startP); + var startP = new THREE.Vector3(); + var startEnd = new THREE.Vector3(); - var t = startEnd_startP / startEnd2; + return function ( point, clampToLine ) { - if (clampToLine) { + startP.subVectors( point, this.start ); + startEnd.subVectors( this.end, this.start ); - t = THREE.Math.clamp(t, 0, 1); + var startEnd2 = startEnd.dot( startEnd ); + var startEnd_startP = startEnd.dot( startP ); - } + var t = startEnd_startP / startEnd2; - return t; + if ( clampToLine ) { - }; + t = THREE.Math.clamp( t, 0, 1 ); - }(), + } - closestPointToPoint: function (point, clampToLine, optionalTarget) { + return t; - var t = this.closestPointToPointParameter(point, clampToLine); + }; - var result = optionalTarget || new THREE.Vector3(); + }(), - return this.delta(result).multiplyScalar(t).add(this.start); + closestPointToPoint: function ( point, clampToLine, optionalTarget ) { - }, + var t = this.closestPointToPointParameter( point, clampToLine ); - applyMatrix4: function (matrix) { + var result = optionalTarget || new THREE.Vector3(); - this.start.applyMatrix4(matrix); - this.end.applyMatrix4(matrix); + return this.delta( result ).multiplyScalar( t ).add( this.start ); - return this; + }, - }, + applyMatrix4: function ( matrix ) { - equals: function (line) { + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); - return line.start.equals(this.start) && line.end.equals(this.end); + return this; - }, + }, - clone: function () { + equals: function ( line ) { - return new THREE.Line3().copy(this); + return line.start.equals( this.start ) && line.end.equals( this.end ); - } + } }; // File:src/math/Box2.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Box2 = function (min, max) { +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.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity ); }; THREE.Box2.prototype = { - constructor: THREE.Box2, + constructor: THREE.Box2, - set: function (min, max) { + set: function ( min, max ) { - this.min.copy(min); - this.max.copy(max); + this.min.copy( min ); + this.max.copy( max ); - return this; + return this; - }, + }, - setFromPoints: function (points) { + setFromPoints: function ( points ) { - this.makeEmpty(); + this.makeEmpty(); - for (var i = 0, il = points.length; i < il; i++) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - this.expandByPoint(points[i]) + this.expandByPoint( points[ i ] ) - } + } - return this; + return this; - }, + }, - setFromCenterAndSize: function () { + setFromCenterAndSize: function () { - var v1 = new THREE.Vector2(); + var v1 = new THREE.Vector2(); - return function (center, size) { + return function ( center, size ) { - var halfSize = v1.copy(size).multiplyScalar(0.5); - this.min.copy(center).sub(halfSize); - this.max.copy(center).add(halfSize); + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - return this; + return this; - }; + }; - }(), + }(), + + clone: function () { - copy: function (box) { + return new this.constructor().copy( this ); - this.min.copy(box.min); - this.max.copy(box.max); + }, - return this; + copy: function ( box ) { - }, + this.min.copy( box.min ); + this.max.copy( box.max ); - makeEmpty: function () { + return this; - this.min.x = this.min.y = Infinity; - this.max.x = this.max.y = -Infinity; + }, - return this; + makeEmpty: function () { - }, + this.min.x = this.min.y = Infinity; + this.max.x = this.max.y = - Infinity; - empty: function () { + return this; - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + }, - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + empty: function () { - }, + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - center: function (optionalTarget) { + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - var result = optionalTarget || new THREE.Vector2(); - return result.addVectors(this.min, this.max).multiplyScalar(0.5); + }, - }, + center: function ( optionalTarget ) { - size: function (optionalTarget) { + var result = optionalTarget || new THREE.Vector2(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - var result = optionalTarget || new THREE.Vector2(); - return result.subVectors(this.max, this.min); + }, - }, + size: function ( optionalTarget ) { - expandByPoint: function (point) { + var result = optionalTarget || new THREE.Vector2(); + return result.subVectors( this.max, this.min ); - this.min.min(point); - this.max.max(point); + }, - return this; - }, + expandByPoint: function ( point ) { - expandByVector: function (vector) { + this.min.min( point ); + this.max.max( point ); - this.min.sub(vector); - this.max.add(vector); + return this; - return this; - }, + }, - expandByScalar: function (scalar) { + expandByVector: function ( vector ) { - this.min.addScalar(-scalar); - this.max.addScalar(scalar); + this.min.sub( vector ); + this.max.add( vector ); - return this; - }, + return this; - containsPoint: function (point) { + }, - if (point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y) { + expandByScalar: function ( scalar ) { - return false; + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - } + return this; - return true; + }, - }, + containsPoint: function ( point ) { - containsBox: function (box) { + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ) { - if (( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y )) { + return false; - return true; + } - } + return true; - return false; + }, - }, + containsBox: function ( box ) { - getParameter: function (point, optionalTarget) { + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + return true; - 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 ) - ); + return false; - }, + }, - isIntersectionBox: function (box) { + getParameter: function ( point, optionalTarget ) { - // using 6 splitting planes to rule out intersections. + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - if (box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y) { + var result = optionalTarget || new THREE.Vector2(); - return false; + 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 ) + ); - } + }, - return true; + isIntersectionBox: function ( box ) { - }, + // using 6 splitting planes to rule out intersections. - clampPoint: function (point, optionalTarget) { + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ) { - var result = optionalTarget || new THREE.Vector2(); - return result.copy(point).clamp(this.min, this.max); + return false; - }, + } - distanceToPoint: function () { + return true; - var v1 = new THREE.Vector2(); + }, - return function (point) { + clampPoint: function ( point, optionalTarget ) { - var clampedPoint = v1.copy(point).clamp(this.min, this.max); - return clampedPoint.sub(point).length(); + var result = optionalTarget || new THREE.Vector2(); + return result.copy( point ).clamp( this.min, this.max ); - }; + }, - }(), + distanceToPoint: function () { - intersect: function (box) { + var v1 = new THREE.Vector2(); - this.min.max(box.min); - this.max.min(box.max); + return function ( point ) { - return this; + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - }, + }; - union: function (box) { + }(), - this.min.min(box.min); - this.max.max(box.max); + intersect: function ( box ) { - return this; + this.min.max( box.min ); + this.max.min( box.max ); - }, + return this; - translate: function (offset) { + }, - this.min.add(offset); - this.max.add(offset); + union: function ( box ) { - return this; + this.min.min( box.min ); + this.max.max( box.max ); - }, + return this; - equals: function (box) { + }, - return box.min.equals(this.min) && box.max.equals(this.max); + translate: function ( offset ) { - }, + this.min.add( offset ); + this.max.add( offset ); - clone: function () { + return this; - return new THREE.Box2().copy(this); + }, - } + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } }; // File:src/math/Box3.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io * @author WestLangley / http://github.com/WestLangley */ -THREE.Box3 = function (min, max) { +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.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity ); }; THREE.Box3.prototype = { - constructor: THREE.Box3, + constructor: THREE.Box3, - set: function (min, max) { + set: function ( min, max ) { - this.min.copy(min); - this.max.copy(max); + this.min.copy( min ); + this.max.copy( max ); - return this; + return this; - }, + }, - setFromPoints: function (points) { + setFromPoints: function ( points ) { - this.makeEmpty(); + this.makeEmpty(); - for (var i = 0, il = points.length; i < il; i++) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - this.expandByPoint(points[i]) + this.expandByPoint( points[ i ] ); - } + } - return this; + return this; - }, + }, - setFromCenterAndSize: function () { + setFromCenterAndSize: function () { - var v1 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return function (center, size) { + return function ( center, size ) { - var halfSize = v1.copy(size).multiplyScalar(0.5); + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy(center).sub(halfSize); - this.max.copy(center).add(halfSize); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - return this; + return this; - }; + }; - }(), + }(), - 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 + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - var v1 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return function (object) { + return function ( object ) { - var scope = this; + var scope = this; - object.updateMatrixWorld(true); + object.updateMatrixWorld( true ); - this.makeEmpty(); + this.makeEmpty(); - object.traverse(function (node) { + object.traverse( function ( node ) { - var geometry = node.geometry; + var geometry = node.geometry; - if (geometry !== undefined) { + if ( geometry !== undefined ) { - if (geometry instanceof THREE.Geometry) { + if ( geometry instanceof THREE.Geometry ) { - var vertices = geometry.vertices; + var vertices = geometry.vertices; - for (var i = 0, il = vertices.length; i < il; i++) { + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - v1.copy(vertices[i]); + v1.copy( vertices[ i ] ); - v1.applyMatrix4(node.matrixWorld); + v1.applyMatrix4( node.matrixWorld ); - scope.expandByPoint(v1); + scope.expandByPoint( v1 ); - } + } - } else if (geometry instanceof THREE.BufferGeometry && geometry.attributes['position'] !== undefined) { + } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) { - var positions = geometry.attributes['position'].array; + var positions = geometry.attributes[ 'position' ].array; - for (var i = 0, il = positions.length; i < il; i += 3) { + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - v1.set(positions[i], positions[i + 1], positions[i + 2]); + v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - v1.applyMatrix4(node.matrixWorld); + v1.applyMatrix4( node.matrixWorld ); - scope.expandByPoint(v1); + scope.expandByPoint( v1 ); - } + } - } + } - } + } - }); + } ); - return this; + return this; - }; + }; - }(), + }(), - copy: function (box) { + clone: function () { - this.min.copy(box.min); - this.max.copy(box.max); + return new this.constructor().copy( this ); - return this; + }, - }, + copy: function ( box ) { - makeEmpty: function () { + this.min.copy( box.min ); + this.max.copy( box.max ); - this.min.x = this.min.y = this.min.z = Infinity; - this.max.x = this.max.y = this.max.z = -Infinity; + return this; - return this; + }, - }, + makeEmpty: function () { - empty: function () { + this.min.x = this.min.y = this.min.z = Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + return this; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + }, - }, + empty: function () { - center: function (optionalTarget) { + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors(this.min, this.max).multiplyScalar(0.5); + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - }, + }, - size: function (optionalTarget) { + center: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors(this.max, this.min); + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - }, + }, - expandByPoint: function (point) { + size: function ( optionalTarget ) { - this.min.min(point); - this.max.max(point); + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.max, this.min ); - return this; + }, - }, + expandByPoint: function ( point ) { - expandByVector: function (vector) { + this.min.min( point ); + this.max.max( point ); - this.min.sub(vector); - this.max.add(vector); + return this; - return this; + }, - }, + expandByVector: function ( vector ) { - expandByScalar: function (scalar) { + this.min.sub( vector ); + this.max.add( vector ); - this.min.addScalar(-scalar); - this.max.addScalar(scalar); + return this; - return this; + }, - }, + expandByScalar: function ( scalar ) { - containsPoint: function (point) { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - if (point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z) { + return this; - return false; + }, - } + containsPoint: function ( point ) { - return true; + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ) { - }, + return false; - containsBox: function (box) { + } - if (( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && - ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z )) { + return true; - return true; + }, - } + containsBox: function ( box ) { - return false; + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && + ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { - }, + return true; - getParameter: function (point, optionalTarget) { + } - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + return false; - 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 ) - ); + getParameter: function ( point, optionalTarget ) { - }, + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - isIntersectionBox: function (box) { + var result = optionalTarget || new THREE.Vector3(); - // using 6 splitting planes to rule out intersections. + 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 ) + ); - if (box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z) { + }, - return false; + isIntersectionBox: function ( box ) { - } + // using 6 splitting planes to rule out intersections. - return true; + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ) { - }, + return false; - clampPoint: function (point, optionalTarget) { + } - var result = optionalTarget || new THREE.Vector3(); - return result.copy(point).clamp(this.min, this.max); + return true; - }, + }, - distanceToPoint: function () { + clampPoint: function ( point, optionalTarget ) { - var v1 = new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); + return result.copy( point ).clamp( this.min, this.max ); - return function (point) { + }, - var clampedPoint = v1.copy(point).clamp(this.min, this.max); - return clampedPoint.sub(point).length(); + distanceToPoint: function () { - }; + var v1 = new THREE.Vector3(); - }(), + return function ( point ) { - getBoundingSphere: function () { + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - var v1 = new THREE.Vector3(); + }; - return function (optionalTarget) { + }(), - var result = optionalTarget || new THREE.Sphere(); + getBoundingSphere: function () { - result.center = this.center(); - result.radius = this.size(v1).length() * 0.5; + var v1 = new THREE.Vector3(); - return result; + return function ( optionalTarget ) { - }; + var result = optionalTarget || new THREE.Sphere(); - }(), + result.center = this.center(); + result.radius = this.size( v1 ).length() * 0.5; - intersect: function (box) { + return result; - this.min.max(box.min); - this.max.min(box.max); + }; - return this; + }(), - }, + intersect: function ( box ) { - union: function (box) { + this.min.max( box.min ); + this.max.min( box.max ); - this.min.min(box.min); - this.max.max(box.max); + return this; - return this; + }, - }, + union: function ( box ) { - applyMatrix4: function () { + this.min.min( box.min ); + this.max.max( box.max ); - var points = [ - 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 this; - 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 + applyMatrix4: function () { - this.makeEmpty(); - this.setFromPoints(points); + var points = [ + 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 this; + 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 - }(), + this.makeEmpty(); + this.setFromPoints( points ); - translate: function (offset) { + return this; - this.min.add(offset); - this.max.add(offset); + }; - return this; + }(), - }, + translate: function ( offset ) { - equals: function (box) { + this.min.add( offset ); + this.max.add( offset ); - return box.min.equals(this.min) && box.max.equals(this.max); + return this; - }, + }, - clone: function () { + equals: function ( box ) { - return new THREE.Box3().copy(this); + return box.min.equals( this.min ) && box.max.equals( this.max ); - } + } }; @@ -4413,316 +4460,296 @@ THREE.Box3.prototype = { /** * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ THREE.Matrix3 = function () { - this.elements = new Float32Array([ + this.elements = new Float32Array( [ - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - ]); + ] ); - if (arguments.length > 0) { + if ( arguments.length > 0 ) { - THREE.error('THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.'); + console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); - } + } }; THREE.Matrix3.prototype = { - constructor: THREE.Matrix3, + constructor: THREE.Matrix3, - set: function (n11, n12, n13, n21, n22, n23, n31, n32, n33) { + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - var te = this.elements; + 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; + return this; - }, + }, - identity: function () { + identity: function () { - this.set( - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - ); + this.set( - return this; + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - }, + ); - copy: function (m) { + return this; - var me = m.elements; + }, - this.set( - me[0], me[3], me[6], - me[1], me[4], me[7], - me[2], me[5], me[8] - ); + clone: function () { - return this; + return new this.constructor().fromArray( this.elements ); - }, + }, - multiplyVector3: function (vector) { + copy: function ( m ) { - THREE.warn('THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.'); - return vector.applyMatrix3(this); + var me = m.elements; - }, + this.set( - multiplyVector3Array: function (a) { + me[ 0 ], me[ 3 ], me[ 6 ], + me[ 1 ], me[ 4 ], me[ 7 ], + me[ 2 ], me[ 5 ], me[ 8 ] - THREE.warn('THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.'); - return this.applyToVector3Array(a); + ); - }, + return this; - applyToVector3Array: function () { + }, - var v1; + multiplyVector3: function ( vector ) { - return function applyToVector3Array(array, offset, length) { + console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); - if (v1 === undefined) v1 = new THREE.Vector3(); - if (offset === undefined) offset = 0; - if (length === undefined) length = array.length; + }, - for (var i = 0, j = offset; i < length; i += 3, j += 3) { + multiplyVector3Array: function ( a ) { - v1.x = array[j]; - v1.y = array[j + 1]; - v1.z = array[j + 2]; + console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); - v1.applyMatrix3(this); + }, - array[j] = v1.x; - array[j + 1] = v1.y; - array[j + 2] = v1.z; + applyToVector3Array: function () { - } + var v1; - return array; + return function ( array, offset, length ) { - }; + if ( v1 === undefined ) v1 = new THREE.Vector3(); + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - }(), + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - applyToBuffer: function () { + v1.fromArray( array, j ); + v1.applyMatrix3( this ); + v1.toArray( array, j ); - var v1; + } - return function applyToBuffer(buffer, offset, length) { + return array; - if (v1 === undefined) v1 = new THREE.Vector3(); - if (offset === undefined) offset = 0; - if (length === undefined) length = buffer.length / buffer.itemSize; + }; - for (var i = 0, j = offset; i < length; i++, j++) { + }(), - v1.x = buffer.getX(j); - v1.y = buffer.getY(j); - v1.z = buffer.getZ(j); + applyToBuffer: function () { - v1.applyMatrix3(this); + var v1; - buffer.setXYZ(v1.x, v1.y, v1.z); + return function applyToBuffer( buffer, offset, length ) { - } + if ( v1 === undefined ) v1 = new THREE.Vector3(); + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = buffer.length / buffer.itemSize; - return buffer; + for ( var i = 0, j = offset; i < length; i ++, j ++ ) { - }; + v1.x = buffer.getX( j ); + v1.y = buffer.getY( j ); + v1.z = buffer.getZ( j ); - }(), + v1.applyMatrix3( this ); - multiplyScalar: function (s) { + buffer.setXYZ( v1.x, v1.y, v1.z ); - 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; + return buffer; - return this; + }; - }, + }(), - determinant: function () { + multiplyScalar: function ( s ) { - var te = this.elements; + 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]; + 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 a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; + return this; - }, + }, - getInverse: function (matrix, throwOnInvertible) { + determinant: function () { - // input: THREE.Matrix4 - // ( based on http://code.google.com/p/webgl-mjs/ ) + var te = this.elements; - var me = matrix.elements; - 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 ]; - 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]; + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - var det = me[0] * te[0] + me[1] * te[3] + me[2] * te[6]; + }, - // no inverse + getInverse: function ( matrix, throwOnInvertible ) { - if (det === 0) { + // input: THREE.Matrix4 + // ( based on http://code.google.com/p/webgl-mjs/ ) - var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; + var me = matrix.elements; + var te = this.elements; - if (throwOnInvertible || false) { + 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 ]; - throw new Error(msg); + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; - } else { + // no inverse - THREE.warn(msg); + if ( det === 0 ) { - } + var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; - this.identity(); + if ( throwOnInvertible || false ) { - return this; + throw new Error( msg ); - } + } else { - this.multiplyScalar(1.0 / det); + console.warn( msg ); - return this; + } - }, + this.identity(); - transpose: function () { + return this; - 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; + this.multiplyScalar( 1.0 / det ); - return this; + return this; - }, + }, - flattenToArrayOffset: function (array, offset) { + transpose: function () { - var te = this.elements; + var tmp, m = this.elements; - array[offset] = te[0]; - array[offset + 1] = te[1]; - array[offset + 2] = te[2]; + 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; - array[offset + 3] = te[3]; - array[offset + 4] = te[4]; - array[offset + 5] = te[5]; + return this; - array[offset + 6] = te[6]; - array[offset + 7] = te[7]; - array[offset + 8] = te[8]; + }, - return array; + flattenToArrayOffset: function ( array, offset ) { - }, + var te = this.elements; - getNormalMatrix: function (m) { + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; - // input: THREE.Matrix4 + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; - this.getInverse(m).transpose(); + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; - return this; + return array; - }, + }, - transposeIntoArray: function (r) { + getNormalMatrix: function ( m ) { - var m = this.elements; + // input: THREE.Matrix4 - r[0] = m[0]; - r[1] = m[3]; - r[2] = m[6]; - r[3] = m[1]; - r[4] = m[4]; - r[5] = m[7]; - r[6] = m[2]; - r[7] = m[5]; - r[8] = m[8]; + this.getInverse( m ).transpose(); - return this; + return this; - }, + }, - fromArray: function (array) { + transposeIntoArray: function ( r ) { - this.elements.set(array); + var m = this.elements; - return this; + r[ 0 ] = m[ 0 ]; + r[ 1 ] = m[ 3 ]; + r[ 2 ] = m[ 6 ]; + r[ 3 ] = m[ 1 ]; + r[ 4 ] = m[ 4 ]; + r[ 5 ] = m[ 7 ]; + r[ 6 ] = m[ 2 ]; + r[ 7 ] = m[ 5 ]; + r[ 8 ] = m[ 8 ]; - }, + return this; - toArray: function () { + }, - var te = this.elements; + fromArray: function ( array ) { - return [ - te[0], te[1], te[2], - te[3], te[4], te[5], - te[6], te[7], te[8] - ]; + this.elements.set( array ); - }, + return this; - clone: function () { + }, - return new THREE.Matrix3().fromArray(this.elements); + toArray: function () { - } + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], + te[ 3 ], te[ 4 ], te[ 5 ], + te[ 6 ], te[ 7 ], te[ 8 ] + ]; + + } }; @@ -4737,1773 +4764,1722 @@ THREE.Matrix3.prototype = { * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author timknip / http://www.floorplanner.com/ - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io * @author WestLangley / http://github.com/WestLangley */ THREE.Matrix4 = function () { - this.elements = new Float32Array([ + this.elements = new Float32Array( [ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - ]); + ] ); - if (arguments.length > 0) { + if ( arguments.length > 0 ) { - THREE.error('THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.'); + console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - } + } }; THREE.Matrix4.prototype = { - constructor: THREE.Matrix4, + constructor: THREE.Matrix4, - set: function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) { + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - var te = this.elements; + 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; + return this; - }, + }, - identity: function () { + identity: function () { - this.set( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ); + this.set( - return this; + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - }, + ); - copy: function (m) { + return this; - this.elements.set(m.elements); + }, - return this; + clone: function () { - }, + return new THREE.Matrix4().fromArray( this.elements ); - extractPosition: function (m) { + }, - THREE.warn('THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().'); - return this.copyPosition(m); + copy: function ( m ) { - }, + this.elements.set( m.elements ); - copyPosition: function (m) { + return this; - var te = this.elements; - var me = m.elements; + }, - te[12] = me[12]; - te[13] = me[13]; - te[14] = me[14]; + extractPosition: function ( m ) { - return this; + console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); - }, + }, - extractBasis: function (xAxis, yAxis, zAxis) { + copyPosition: function ( m ) { - var te = this.elements; + var te = this.elements; + var me = m.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]); + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; - return this; + return this; - }, + }, - makeBasis: function (xAxis, yAxis, zAxis) { + extractBasis: function ( xAxis, yAxis, zAxis ) { - 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 - ); + var te = this.elements; - return this; + 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; - extractRotation: function () { + }, - var v1; + makeBasis: function ( xAxis, yAxis, zAxis ) { - return function (m) { + 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 + ); - if (v1 === undefined) v1 = new THREE.Vector3(); + return this; - 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(); + extractRotation: function () { - te[0] = me[0] * scaleX; - te[1] = me[1] * scaleX; - te[2] = me[2] * scaleX; + var v1; - te[4] = me[4] * scaleY; - te[5] = me[5] * scaleY; - te[6] = me[6] * scaleY; + return function ( m ) { - te[8] = me[8] * scaleZ; - te[9] = me[9] * scaleZ; - te[10] = me[10] * scaleZ; + if ( v1 === undefined ) v1 = new THREE.Vector3(); - return this; + 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(); - }(), + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; - makeRotationFromEuler: function (euler) { + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; - if (euler instanceof THREE.Euler === false) { + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; - THREE.error('THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.'); + return this; - } + }; - var te = this.elements; + }(), - var x = euler.x, y = euler.y, z = euler.z; - var a = Math.cos(x), b = Math.sin(x); - var c = Math.cos(y), d = Math.sin(y); - var e = Math.cos(z), f = Math.sin(z); + makeRotationFromEuler: function ( euler ) { - if (euler.order === 'XYZ') { + if ( euler instanceof THREE.Euler === false ) { - var ae = a * e, af = a * f, be = b * e, bf = b * f; + console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - 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; + var te = this.elements; - te[2] = bf - ae * d; - te[6] = be + af * d; - te[10] = a * c; + var x = euler.x, y = euler.y, z = euler.z; + var a = Math.cos( x ), b = Math.sin( x ); + var c = Math.cos( y ), d = Math.sin( y ); + var e = Math.cos( z ), f = Math.sin( z ); - } else if (euler.order === 'YXZ') { + if ( euler.order === 'XYZ' ) { - var ce = c * e, cf = c * f, de = d * e, df = d * f; + var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = ce + df * b; - te[4] = de * b - cf; - te[8] = a * d; + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - te[1] = a * f; - te[5] = a * e; - te[9] = -b; + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - te[2] = cf * b - de; - te[6] = df + ce * b; - te[10] = a * c; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - } else if (euler.order === 'ZXY') { + } else if ( euler.order === 'YXZ' ) { - var ce = c * e, cf = c * f, de = d * e, df = d * f; + 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 ] = de * b - cf; + te[ 8 ] = a * d; - te[1] = cf + de * b; - te[5] = a * e; - te[9] = df - ce * b; + te[ 1 ] = a * f; + te[ 5 ] = a * e; + te[ 9 ] = - b; - te[2] = -a * d; - te[6] = b; - te[10] = a * c; + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; - } else if (euler.order === 'ZYX') { + } else if ( euler.order === 'ZXY' ) { - var ae = a * e, af = a * f, be = b * e, bf = b * f; + var ce = c * e, cf = c * f, de = d * e, df = d * f; - te[0] = c * e; - te[4] = be * d - af; - te[8] = ae * d + bf; + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - te[1] = c * f; - te[5] = bf * d + ae; - te[9] = af * d - be; + te[ 1 ] = cf + de * b; + te[ 5 ] = a * e; + te[ 9 ] = df - ce * b; - te[2] = -d; - te[6] = b * c; - te[10] = a * c; + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; - } else if (euler.order === 'YZX') { + } else if ( euler.order === 'ZYX' ) { - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + var ae = a * e, af = a * f, be = b * e, bf = b * f; - te[0] = c * e; - te[4] = bd - ac * f; - te[8] = bc * f + ad; + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - te[1] = f; - te[5] = a * e; - te[9] = -b * e; + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - te[2] = -d * e; - te[6] = ad * f + bc; - te[10] = ac - bd * f; + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - } else if (euler.order === 'XZY') { + } else if ( euler.order === 'YZX' ) { - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + 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 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; - te[1] = ac * f + bd; - te[5] = a * e; - te[9] = ad * f - bc; + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - te[2] = bc * f - ad; - te[6] = b * e; - te[10] = bd * f + ac; + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - } + } else if ( euler.order === 'XZY' ) { - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - return this; + 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; - setRotationFromQuaternion: function (q) { + } - THREE.warn('THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().'); + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - return this.makeRotationFromQuaternion(q); + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - }, + return this; - makeRotationFromQuaternion: function (q) { + }, - var te = this.elements; + setRotationFromQuaternion: function ( q ) { - var x = q.x, y = q.y, z = q.z, w = q.w; - var x2 = x + x, y2 = y + y, z2 = z + z; - var xx = x * x2, xy = x * y2, xz = x * z2; - var yy = y * y2, yz = y * z2, zz = z * z2; - var wx = w * x2, wy = w * y2, wz = w * z2; + console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - te[0] = 1 - ( yy + zz ); - te[4] = xy - wz; - te[8] = xz + wy; + return this.makeRotationFromQuaternion( q ); - 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 ); + makeRotationFromQuaternion: function ( q ) { - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; + var te = this.elements; - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; + var x = q.x, y = q.y, z = q.z, w = q.w; + var x2 = x + x, y2 = y + y, z2 = z + z; + var xx = x * x2, xy = x * y2, xz = x * z2; + var yy = y * y2, yz = y * z2, zz = z * z2; + var wx = w * x2, wy = w * y2, wz = w * z2; - return this; + 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; - lookAt: function () { + te[ 2 ] = xz - wy; + te[ 6 ] = yz + wx; + te[ 10 ] = 1 - ( xx + yy ); - var x, y, z; + // last column + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - return function (eye, target, up) { + // bottom row + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - if (x === undefined) x = new THREE.Vector3(); - if (y === undefined) y = new THREE.Vector3(); - if (z === undefined) z = new THREE.Vector3(); + return this; - var te = this.elements; + }, - z.subVectors(eye, target).normalize(); + lookAt: function () { - if (z.length() === 0) { + var x, y, z; - z.z = 1; + return function ( eye, target, up ) { - } + if ( x === undefined ) x = new THREE.Vector3(); + if ( y === undefined ) y = new THREE.Vector3(); + if ( z === undefined ) z = new THREE.Vector3(); - x.crossVectors(up, z).normalize(); + var te = this.elements; - if (x.length() === 0) { + z.subVectors( eye, target ).normalize(); - z.x += 0.0001; - x.crossVectors(up, z).normalize(); + if ( z.length() === 0 ) { - } + z.z = 1; - y.crossVectors(z, x); + } + x.crossVectors( up, z ).normalize(); - 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; + if ( x.length() === 0 ) { - return this; + z.x += 0.0001; + x.crossVectors( up, z ).normalize(); - }; + } - }(), + y.crossVectors( z, x ); - multiply: function (m, n) { - if (n !== undefined) { + 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; - THREE.warn('THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.'); - return this.multiplyMatrices(m, n); + return this; - } + }; - return this.multiplyMatrices(this, m); + }(), - }, + multiply: function ( m, n ) { - multiplyMatrices: function (a, b) { + if ( n !== undefined ) { - var ae = a.elements; - var be = b.elements; - var te = this.elements; + console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); - 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]; + return this.multiplyMatrices( this, m ); - 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; + multiplyMatrices: function ( a, b ) { - 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; + var ae = a.elements; + var be = b.elements; + var te = this.elements; - 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; + 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 ]; - return this; + 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; - multiplyToArray: function (a, b, r) { + 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; - var te = this.elements; + 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; - this.multiplyMatrices(a, b); + 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; - 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; - return this; + }, - }, + multiplyToArray: function ( a, b, r ) { - multiplyScalar: function (s) { + var te = this.elements; - var te = this.elements; + this.multiplyMatrices( a, b ); - 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; + 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; + return this; - }, + }, - multiplyVector3: function (vector) { + multiplyScalar: function ( s ) { - THREE.warn('THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.'); - return vector.applyProjection(this); + 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; - multiplyVector4: function (vector) { + return this; - THREE.warn('THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.'); - return vector.applyMatrix4(this); + }, - }, + multiplyVector3: function ( vector ) { - multiplyVector3Array: function (a) { + console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + return vector.applyProjection( this ); - THREE.warn('THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.'); - return this.applyToVector3Array(a); + }, - }, + multiplyVector4: function ( vector ) { - applyToVector3Array: function () { + console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - var v1; + }, - return function applyToVector3Array(array, offset, length) { + multiplyVector3Array: function ( a ) { - if (v1 === undefined) v1 = new THREE.Vector3(); - if (offset === undefined) offset = 0; - if (length === undefined) length = array.length; + console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + return this.applyToVector3Array( a ); - for (var i = 0, j = offset; i < length; i += 3, j += 3) { + }, - v1.x = array[j]; - v1.y = array[j + 1]; - v1.z = array[j + 2]; + applyToVector3Array: function () { - v1.applyMatrix4(this); + var v1; - array[j] = v1.x; - array[j + 1] = v1.y; - array[j + 2] = v1.z; + return function ( array, offset, length ) { - } + if ( v1 === undefined ) v1 = new THREE.Vector3(); + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = array.length; - return array; + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { - }; + v1.fromArray( array, j ); + v1.applyMatrix4( this ); + v1.toArray( array, j ); - }(), + } - applyToBuffer: function () { + return array; - var v1; + }; - return function applyToBuffer(buffer, offset, length) { + }(), - if (v1 === undefined) v1 = new THREE.Vector3(); - if (offset === undefined) offset = 0; - if (length === undefined) length = buffer.length / buffer.itemSize; + applyToBuffer: function () { - for (var i = 0, j = offset; i < length; i++, j++) { + var v1; - v1.x = buffer.getX(j); - v1.y = buffer.getY(j); - v1.z = buffer.getZ(j); + return function applyToBuffer( buffer, offset, length ) { - v1.applyMatrix4(this); + if ( v1 === undefined ) v1 = new THREE.Vector3(); + if ( offset === undefined ) offset = 0; + if ( length === undefined ) length = buffer.length / buffer.itemSize; - buffer.setXYZ(v1.x, v1.y, v1.z); + for ( var i = 0, j = offset; i < length; i ++, j ++ ) { - } + v1.x = buffer.getX( j ); + v1.y = buffer.getY( j ); + v1.z = buffer.getZ( j ); - return buffer; + v1.applyMatrix4( this ); - }; + buffer.setXYZ( v1.x, v1.y, v1.z ); - }(), + } - rotateAxis: function (v) { + return buffer; - THREE.warn('THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.'); + }; - v.transformDirection(this); + }(), - }, + rotateAxis: function ( v ) { - crossVector: function (vector) { + console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - THREE.warn('THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.'); - return vector.applyMatrix4(this); + v.transformDirection( this ); - }, + }, - determinant: function () { + crossVector: function ( vector ) { - var te = this.elements; + console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - 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 ) + determinant: function () { - return ( - n41 * ( - +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 - ) + - n43 * ( - +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 - ) + 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 ]; - }, + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - transpose: function () { + return ( + n41 * ( + + 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 + ) + + n43 * ( + + 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 + ) - 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[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; + transpose: function () { - return this; + 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; - flattenToArrayOffset: function (array, offset) { + 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; - var te = this.elements; + return this; - 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]; + flattenToArrayOffset: function ( array, offset ) { - array[offset + 8] = te[8]; - array[offset + 9] = te[9]; - array[offset + 10] = te[10]; - array[offset + 11] = te[11]; + var te = this.elements; - array[offset + 12] = te[12]; - array[offset + 13] = te[13]; - array[offset + 14] = te[14]; - array[offset + 15] = te[15]; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - return array; + 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 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - getPosition: function () { + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - var v1; + return array; - return function () { + }, - if (v1 === undefined) v1 = new THREE.Vector3(); - THREE.warn('THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.'); + getPosition: function () { - var te = this.elements; - return v1.set(te[12], te[13], te[14]); + var v1; - }; + return function () { - }(), + if ( v1 === undefined ) v1 = new THREE.Vector3(); + console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - setPosition: function (v) { + var te = this.elements; + return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); - var te = this.elements; + }; - te[12] = v.x; - te[13] = v.y; - te[14] = v.z; + }(), - return this; + setPosition: function ( v ) { - }, + var te = this.elements; - getInverse: function (m, throwOnInvertible) { + te[ 12 ] = v.x; + te[ 13 ] = v.y; + te[ 14 ] = v.z; - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements; - var me = m.elements; + return this; - 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; + getInverse: function ( m, throwOnInvertible ) { - var det = n11 * te[0] + n21 * te[4] + n31 * te[8] + n41 * te[12]; + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements; + var me = m.elements; - if (det == 0) { + 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 ]; - var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; + 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; - if (throwOnInvertible || false) { + var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; - throw new Error(msg); + if ( det === 0 ) { - } else { + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; - THREE.warn(msg); + if ( throwOnInvertible || false ) { - } + throw new Error( msg ); - this.identity(); + } else { - return this; + console.warn( msg ); - } + } - this.multiplyScalar(1 / det); + this.identity(); - return this; + return this; - }, + } - translate: function (v) { + this.multiplyScalar( 1 / det ); - THREE.error('THREE.Matrix4: .translate() has been removed.'); + return this; - }, + }, - rotateX: function (angle) { + translate: function ( v ) { - THREE.error('THREE.Matrix4: .rotateX() has been removed.'); + console.error( 'THREE.Matrix4: .translate() has been removed.' ); - }, + }, - rotateY: function (angle) { + rotateX: function ( angle ) { - THREE.error('THREE.Matrix4: .rotateY() has been removed.'); + console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - }, + }, - rotateZ: function (angle) { + rotateY: function ( angle ) { - THREE.error('THREE.Matrix4: .rotateZ() has been removed.'); + console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - }, + }, - rotateByAxis: function (axis, angle) { + rotateZ: function ( angle ) { - THREE.error('THREE.Matrix4: .rotateByAxis() has been removed.'); + console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - }, + }, - scale: function (v) { + rotateByAxis: function ( axis, angle ) { - var te = this.elements; - var x = v.x, y = v.y, z = v.z; + console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - 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; + scale: function ( v ) { - }, + var te = this.elements; + var x = v.x, y = v.y, z = v.z; - getMaxScaleOnAxis: function () { + 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; - var te = this.elements; + return this; - 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))); + getMaxScaleOnAxis: function () { - }, + var te = this.elements; - makeTranslation: function (x, y, z) { + 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 ]; - this.set( - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - ); + return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); - return this; + }, - }, + makeTranslation: function ( x, y, z ) { - makeRotationX: function (theta) { + this.set( - var c = Math.cos(theta), s = Math.sin(theta); + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 - this.set( - 1, 0, 0, 0, - 0, c, -s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - ); + ); - return this; + return this; - }, + }, - makeRotationY: function (theta) { + makeRotationX: function ( theta ) { - var c = Math.cos(theta), s = Math.sin(theta); + var c = Math.cos( theta ), s = Math.sin( theta ); - this.set( - c, 0, s, 0, - 0, 1, 0, 0, - -s, 0, c, 0, - 0, 0, 0, 1 - ); + this.set( - return this; + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 - }, + ); - makeRotationZ: function (theta) { + return this; - var c = Math.cos(theta), s = Math.sin(theta); + }, - this.set( - c, -s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ); + makeRotationY: function ( theta ) { - return this; + var c = Math.cos( theta ), s = Math.sin( theta ); - }, + this.set( - makeRotationAxis: function (axis, angle) { + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 - // Based on http://www.gamedev.net/reference/articles/article1199.asp + ); - var c = Math.cos(angle); - var s = Math.sin(angle); - var t = 1 - c; - var x = axis.x, y = axis.y, z = axis.z; - var tx = t * x, ty = t * y; + return this; - this.set( - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - ); + }, - return this; + makeRotationZ: function ( theta ) { - }, + var c = Math.cos( theta ), s = Math.sin( theta ); - makeScale: function (x, y, z) { + this.set( - this.set( - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - ); + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - return this; + ); - }, + return this; - compose: function (position, quaternion, scale) { + }, - this.makeRotationFromQuaternion(quaternion); - this.scale(scale); - this.setPosition(position); + makeRotationAxis: function ( axis, angle ) { - return this; + // Based on http://www.gamedev.net/reference/articles/article1199.asp - }, + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var t = 1 - c; + var x = axis.x, y = axis.y, z = axis.z; + var tx = t * x, ty = t * y; - decompose: function () { + this.set( - var vector, matrix; + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 - return function (position, quaternion, scale) { + ); - if (vector === undefined) vector = new THREE.Vector3(); - if (matrix === undefined) matrix = new THREE.Matrix4(); + return this; - 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(); + makeScale: function ( x, y, z ) { - // if determine is negative, we need to invert one scale - var det = this.determinant(); - if (det < 0) { + this.set( - sx = -sx; + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - } + ); - position.x = te[12]; - position.y = te[13]; - position.z = te[14]; + return this; - // scale the rotation part + }, - matrix.elements.set(this.elements); // at this point matrix is incomplete so we can't use .copy() + compose: function ( position, quaternion, scale ) { - var invSX = 1 / sx; - var invSY = 1 / sy; - var invSZ = 1 / sz; + this.makeRotationFromQuaternion( quaternion ); + this.scale( scale ); + this.setPosition( position ); - matrix.elements[0] *= invSX; - matrix.elements[1] *= invSX; - matrix.elements[2] *= invSX; + return this; - matrix.elements[4] *= invSY; - matrix.elements[5] *= invSY; - matrix.elements[6] *= invSY; + }, - matrix.elements[8] *= invSZ; - matrix.elements[9] *= invSZ; - matrix.elements[10] *= invSZ; + decompose: function () { - quaternion.setFromRotationMatrix(matrix); + var vector, matrix; - scale.x = sx; - scale.y = sy; - scale.z = sz; + return function ( position, quaternion, scale ) { - return this; + if ( vector === undefined ) vector = new THREE.Vector3(); + if ( matrix === undefined ) matrix = new THREE.Matrix4(); - }; + 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(); - makeFrustum: function (left, right, bottom, top, near, far) { + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if ( det < 0 ) { - var te = this.elements; - var x = 2 * near / ( right - left ); - var y = 2 * near / ( top - bottom ); + sx = - sx; - var a = ( right + left ) / ( right - left ); - var b = ( top + bottom ) / ( top - bottom ); - 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; + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - return this; + // scale the rotation part - }, + matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() - makePerspective: function (fov, aspect, near, far) { + var invSX = 1 / sx; + var invSY = 1 / sy; + var invSZ = 1 / sz; - var ymax = near * Math.tan(THREE.Math.degToRad(fov * 0.5)); - var ymin = -ymax; - var xmin = ymin * aspect; - var xmax = ymax * aspect; + matrix.elements[ 0 ] *= invSX; + matrix.elements[ 1 ] *= invSX; + matrix.elements[ 2 ] *= invSX; - return this.makeFrustum(xmin, xmax, ymin, ymax, near, far); + matrix.elements[ 4 ] *= invSY; + matrix.elements[ 5 ] *= invSY; + matrix.elements[ 6 ] *= invSY; - }, + matrix.elements[ 8 ] *= invSZ; + matrix.elements[ 9 ] *= invSZ; + matrix.elements[ 10 ] *= invSZ; - makeOrthographic: function (left, right, top, bottom, near, far) { + quaternion.setFromRotationMatrix( matrix ); - var te = this.elements; - var w = right - left; - var h = top - bottom; - var p = far - near; + scale.x = sx; + scale.y = sy; + scale.z = sz; - var x = ( right + left ) / w; - var y = ( top + bottom ) / h; - var z = ( far + near ) / p; + return this; - 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; + }(), - }, + makeFrustum: function ( left, right, bottom, top, near, far ) { - fromArray: function (array) { + var te = this.elements; + var x = 2 * near / ( right - left ); + var y = 2 * near / ( top - bottom ); - this.elements.set(array); + var a = ( right + left ) / ( right - left ); + var b = ( top + bottom ) / ( top - bottom ); + var c = - ( far + near ) / ( far - near ); + var d = - 2 * far * near / ( far - near ); - return this; + 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; - toArray: function () { + }, - var te = this.elements; + makePerspective: function ( fov, aspect, near, far ) { - return [ - te[0], te[1], te[2], te[3], - te[4], te[5], te[6], te[7], - te[8], te[9], te[10], te[11], - te[12], te[13], te[14], te[15] - ]; + var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); + var ymin = - ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; - }, + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); - clone: function () { + }, - return new THREE.Matrix4().fromArray(this.elements); + makeOrthographic: function ( left, right, top, bottom, near, far ) { - } + var te = this.elements; + var w = right - left; + var h = top - bottom; + var p = far - near; + + var x = ( right + left ) / w; + 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; + + return this; + + }, + + equals: function ( matrix ) { + + var te = this.elements; + var me = matrix.elements; + + for ( var i = 0; i < 16; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; + + }, + + fromArray: function ( array ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { + + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], + te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], + te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], + te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] + ]; + + } }; // File:src/math/Ray.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Ray = function (origin, direction) { +THREE.Ray = function ( origin, direction ) { - this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); - this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); + this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); + this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); }; THREE.Ray.prototype = { - constructor: THREE.Ray, + constructor: THREE.Ray, - set: function (origin, direction) { + set: function ( origin, direction ) { - this.origin.copy(origin); - this.direction.copy(direction); + this.origin.copy( origin ); + this.direction.copy( direction ); - return this; + return this; - }, + }, - copy: function (ray) { + clone: function () { - this.origin.copy(ray.origin); - this.direction.copy(ray.direction); + return new this.constructor().copy( this ); - return this; + }, - }, + copy: function ( ray ) { - at: function (t, optionalTarget) { + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); - var result = optionalTarget || new THREE.Vector3(); + return this; - return result.copy(this.direction).multiplyScalar(t).add(this.origin); + }, - }, + at: function ( t, optionalTarget ) { - recast: function () { + var result = optionalTarget || new THREE.Vector3(); - var v1 = new THREE.Vector3(); + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - return function (t) { + }, - this.origin.copy(this.at(t, v1)); + recast: function () { - return this; + var v1 = new THREE.Vector3(); - }; + return function ( t ) { - }(), + this.origin.copy( this.at( t, v1 ) ); - closestPointToPoint: function (point, optionalTarget) { + return this; - var result = optionalTarget || new THREE.Vector3(); - result.subVectors(point, this.origin); - var directionDistance = result.dot(this.direction); + }; - if (directionDistance < 0) { + }(), - return result.copy(this.origin); + closestPointToPoint: function ( point, optionalTarget ) { - } + var result = optionalTarget || new THREE.Vector3(); + result.subVectors( point, this.origin ); + var directionDistance = result.dot( this.direction ); - return result.copy(this.direction).multiplyScalar(directionDistance).add(this.origin); + if ( directionDistance < 0 ) { - }, + return result.copy( this.origin ); - distanceToPoint: function () { + } - var v1 = new THREE.Vector3(); + return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - return function (point) { + }, - var directionDistance = v1.subVectors(point, this.origin).dot(this.direction); + distanceToPoint: function ( point ) { - // point behind the ray + return Math.sqrt( this.distanceSqToPoint( point ) ); - if (directionDistance < 0) { + }, - return this.origin.distanceTo(point); + distanceSqToPoint: function () { - } + var v1 = new THREE.Vector3(); - v1.copy(this.direction).multiplyScalar(directionDistance).add(this.origin); + return function ( point ) { - return v1.distanceTo(point); + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); - }; + // point behind the ray - }(), + if ( directionDistance < 0 ) { - distanceSqToSegment: function () { + return this.origin.distanceToSquared( point ); - var segCenter = new THREE.Vector3(); - var segDir = new THREE.Vector3(); - var diff = new THREE.Vector3(); + } - return function (v0, v1, optionalPointOnRay, optionalPointOnSegment) { + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - // 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 + return v1.distanceToSquared( point ); - 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; + }(), - if (det > 0) { + distanceSqToSegment: function () { - // The ray and segment are not parallel. + var segCenter = new THREE.Vector3(); + var segDir = new THREE.Vector3(); + var diff = new THREE.Vector3(); - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - if (s0 >= 0) { + // 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 (s1 >= -extDet) { + segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + segDir.copy( v1 ).sub( v0 ).normalize(); + diff.copy( this.origin ).sub( segCenter ); - if (s1 <= extDet) { + 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; - // region 0 - // Minimum at interior points of ray and segment. + if ( det > 0 ) { - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + // The ray and segment are not parallel. - } else { + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - // region 1 + if ( s0 >= 0 ) { - s1 = segExtent; - s0 = Math.max(0, -( a01 * s1 + b0 )); - sqrDist = -s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + if ( s1 >= - extDet ) { - } + if ( s1 <= extDet ) { - } else { + // region 0 + // Minimum at interior points of ray and segment. - // region 5 + 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 - } else { + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - if (s1 <= -extDet) { + } - // region 4 + } 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; + // region 5 - } else if (s1 <= extDet) { + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - // region 3 + } - s0 = 0; - s1 = Math.min(Math.max(-segExtent, -b1), segExtent); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } else { - } else { + if ( s1 <= - extDet ) { - // region 2 + // 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; + 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 if ( s1 <= extDet ) { - } + // region 3 - } else { + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - // Ray and segment are parallel. + } else { - s1 = ( a01 > 0 ) ? -segExtent : segExtent; - s0 = Math.max(0, -( a01 * s1 + b0 )); - sqrDist = -s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + // region 2 - } + 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; - if (optionalPointOnRay) { + } - optionalPointOnRay.copy(this.direction).multiplyScalar(s0).add(this.origin); + } - } + } else { - if (optionalPointOnSegment) { + // Ray and segment are parallel. - optionalPointOnSegment.copy(segDir).multiplyScalar(s1).add(segCenter); + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - return sqrDist; + if ( optionalPointOnRay ) { - }; + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - }(), + } + if ( optionalPointOnSegment ) { - isIntersectionSphere: function (sphere) { + optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); - return this.distanceToPoint(sphere.center) <= sphere.radius; + } - }, + return sqrDist; - 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) { + isIntersectionSphere: function ( sphere ) { - v1.subVectors(sphere.center, this.origin); + return this.distanceToPoint( sphere.center ) <= sphere.radius; - var tca = v1.dot(this.direction); + }, - var d2 = v1.dot(v1) - tca * tca; + intersectSphere: function () { - var radius2 = sphere.radius * sphere.radius; + // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/ - if (d2 > radius2) return null; + var v1 = new THREE.Vector3(); - var thc = Math.sqrt(radius2 - d2); + return function ( sphere, optionalTarget ) { - // t0 = first intersect point - entrance on front of sphere - var t0 = tca - thc; + v1.subVectors( sphere.center, this.origin ); - // t1 = second intersect point - exit point on back of sphere - var t1 = tca + thc; + var tca = v1.dot( this.direction ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if (t0 < 0 && t1 < 0) return null; + var d2 = v1.dot( v1 ) - tca * tca; - // 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); + var radius2 = sphere.radius * sphere.radius; - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at(t0, optionalTarget); + if ( d2 > radius2 ) return null; - } + var thc = Math.sqrt( radius2 - d2 ); - }(), + // t0 = first intersect point - entrance on front of sphere + var t0 = tca - thc; - isIntersectionPlane: function (plane) { + // t1 = second intersect point - exit point on back of sphere + var t1 = tca + thc; - // check if the ray lies on the plane first + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) return null; - var distToPoint = plane.distanceToPoint(this.origin); + // 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 ); - if (distToPoint === 0) { + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, optionalTarget ); - return true; + } - } + }(), - var denominator = plane.normal.dot(this.direction); + isIntersectionPlane: function ( plane ) { - if (denominator * distToPoint < 0) { + // check if the ray lies on the plane first - return true; + var distToPoint = plane.distanceToPoint( this.origin ); - } + if ( distToPoint === 0 ) { - // ray origin is behind the plane (and is pointing behind it) + return true; - return false; + } - }, + var denominator = plane.normal.dot( this.direction ); - distanceToPlane: function (plane) { + if ( denominator * distToPoint < 0 ) { - var denominator = plane.normal.dot(this.direction); - if (denominator == 0) { + return true; - // line is coplanar, return origin - if (plane.distanceToPoint(this.origin) == 0) { + } - return 0; + // ray origin is behind the plane (and is pointing behind it) - } + return false; - // Null is preferable to undefined since undefined means.... it is undefined + }, - return null; + distanceToPlane: function ( plane ) { - } + var denominator = plane.normal.dot( this.direction ); + if ( denominator === 0 ) { - var t = -( this.origin.dot(plane.normal) + plane.constant ) / denominator; + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - // Return if the ray never intersects the plane + return 0; - return t >= 0 ? t : null; + } - }, + // Null is preferable to undefined since undefined means.... it is undefined - intersectPlane: function (plane, optionalTarget) { + return null; - var t = this.distanceToPlane(plane); + } - if (t === null) { + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - return null; - } + // Return if the ray never intersects the plane - return this.at(t, optionalTarget); + return t >= 0 ? t : null; - }, + }, - isIntersectionBox: function () { + intersectPlane: function ( plane, optionalTarget ) { - var v = new THREE.Vector3(); + var t = this.distanceToPlane( plane ); - return function (box) { + if ( t === null ) { - return this.intersectBox(box, v) !== null; + return null; - }; + } - }(), + return this.at( t, optionalTarget ); - intersectBox: function (box, optionalTarget) { + }, - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + isIntersectionBox: function () { - var tmin, tmax, tymin, tymax, tzmin, tzmax; + var v = new THREE.Vector3(); - var invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + return function ( box ) { - var origin = this.origin; + return this.intersectBox( box, v ) !== null; - if (invdirx >= 0) { + }; - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + }(), - } else { + intersectBox: function ( box, optionalTarget ) { - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; - } + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - if (invdiry >= 0) { + var tmin, tmax, tymin, tymax, tzmin, tzmax; - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } else { + var origin = this.origin; - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; - } + if ( invdirx >= 0 ) { - if (( tmin > tymax ) || ( tymin > tmax )) return null; + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN + } else { - if (tymin > tmin || tmin !== tmin) tmin = tymin; + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; - if (tymax < tmax || tmax !== tmax) tmax = tymax; + } - if (invdirz >= 0) { + if ( invdiry >= 0 ) { - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - } else { + } else { - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; - } + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; - if (( tmin > tzmax ) || ( tzmin > tmax )) return null; + } - if (tzmin > tmin || tmin !== tmin) tmin = tzmin; + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - if (tzmax < tmax || tmax !== tmax) tmax = tzmax; + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN - //return point closest to the ray (positive side) + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - if (tmax < 0) return null; + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - return this.at(tmin >= 0 ? tmin : tmax, optionalTarget); + if ( invdirz >= 0 ) { - }, + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - intersectTriangle: function () { + } else { - // Compute the offset origin, edges, and normal. - var diff = new THREE.Vector3(); - var edge1 = new THREE.Vector3(); - var edge2 = new THREE.Vector3(); - var normal = new THREE.Vector3(); + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - return function (a, b, c, backfaceCulling, optionalTarget) { + } - // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - edge1.subVectors(b, a); - edge2.subVectors(c, a); - normal.crossVectors(edge1, edge2); + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - var DdN = this.direction.dot(normal); - var sign; + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - if (DdN > 0) { + //return point closest to the ray (positive side) - if (backfaceCulling) return null; - sign = 1; + if ( tmax < 0 ) return null; - } else if (DdN < 0) { + return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); - sign = -1; - DdN = -DdN; + }, - } else { + intersectTriangle: function () { - return null; + // Compute the offset origin, edges, and normal. + var diff = new THREE.Vector3(); + var edge1 = new THREE.Vector3(); + var edge2 = new THREE.Vector3(); + var normal = new THREE.Vector3(); - } + return function ( a, b, c, backfaceCulling, optionalTarget ) { - diff.subVectors(this.origin, a); - var DdQxE2 = sign * this.direction.dot(edge2.crossVectors(diff, edge2)); + // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp - // b1 < 0, no intersection - if (DdQxE2 < 0) { + edge1.subVectors( b, a ); + edge2.subVectors( c, a ); + normal.crossVectors( edge1, edge2 ); - return null; + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + var DdN = this.direction.dot( normal ); + var sign; - } + if ( DdN > 0 ) { - var DdE1xQ = sign * this.direction.dot(edge1.cross(diff)); + if ( backfaceCulling ) return null; + sign = 1; - // b2 < 0, no intersection - if (DdE1xQ < 0) { + } else if ( DdN < 0 ) { - return null; + sign = - 1; + DdN = - DdN; - } + } else { - // b1+b2 > 1, no intersection - if (DdQxE2 + DdE1xQ > DdN) { + return null; - return null; + } - } + diff.subVectors( this.origin, a ); + var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); - // Line intersects triangle, check if ray does. - var QdN = -sign * diff.dot(normal); + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - // t < 0, no intersection - if (QdN < 0) { + return null; - return null; + } - } + var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); - // Ray intersects triangle. - return this.at(QdN / DdN, optionalTarget); + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - }; + return null; - }(), + } - applyMatrix4: function (matrix4) { + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - this.direction.add(this.origin).applyMatrix4(matrix4); - this.origin.applyMatrix4(matrix4); - this.direction.sub(this.origin); - this.direction.normalize(); + return null; - return this; - }, + } - equals: function (ray) { + // Line intersects triangle, check if ray does. + var QdN = - sign * diff.dot( normal ); - return ray.origin.equals(this.origin) && ray.direction.equals(this.direction); + // t < 0, no intersection + if ( QdN < 0 ) { - }, + return null; - clone: function () { + } - return new THREE.Ray().copy(this); + // Ray intersects triangle. + return this.at( QdN / DdN, optionalTarget ); - } + }; + + }(), + + applyMatrix4: function ( matrix4 ) { + + this.direction.add( this.origin ).applyMatrix4( matrix4 ); + this.origin.applyMatrix4( matrix4 ); + this.direction.sub( this.origin ); + this.direction.normalize(); + + return this; + + }, + + equals: function ( ray ) { + + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + + } }; // File:src/math/Sphere.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io * @author mrdoob / http://mrdoob.com/ */ -THREE.Sphere = function (center, radius) { +THREE.Sphere = function ( center, radius ) { - this.center = ( center !== undefined ) ? center : new THREE.Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; + this.center = ( center !== undefined ) ? center : new THREE.Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; }; THREE.Sphere.prototype = { - constructor: THREE.Sphere, + constructor: THREE.Sphere, - set: function (center, radius) { + set: function ( center, radius ) { - this.center.copy(center); - this.radius = radius; + this.center.copy( center ); + this.radius = radius; - return this; - }, + return this; - setFromPoints: function () { + }, - var box = new THREE.Box3(); + setFromPoints: function () { - return function (points, optionalCenter) { + var box = new THREE.Box3(); - var center = this.center; + return function ( points, optionalCenter ) { - if (optionalCenter !== undefined) { + var center = this.center; - center.copy(optionalCenter); + if ( optionalCenter !== undefined ) { - } else { + center.copy( optionalCenter ); - box.setFromPoints(points).center(center); + } else { - } + box.setFromPoints( points ).center( center ); - var maxRadiusSq = 0; + } - for (var i = 0, il = points.length; i < il; i++) { + var maxRadiusSq = 0; - maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i])); + for ( var i = 0, il = points.length; i < il; i ++ ) { - } + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - this.radius = Math.sqrt(maxRadiusSq); + } - return this; + this.radius = Math.sqrt( maxRadiusSq ); - }; + return this; - }(), + }; - copy: function (sphere) { + }(), - this.center.copy(sphere.center); - this.radius = sphere.radius; + clone: function () { - return this; + return new this.constructor().copy( this ); - }, + }, - empty: function () { + copy: function ( sphere ) { - return ( this.radius <= 0 ); + this.center.copy( sphere.center ); + this.radius = sphere.radius; - }, + return this; - containsPoint: function (point) { + }, - return ( point.distanceToSquared(this.center) <= ( this.radius * this.radius ) ); + empty: function () { - }, + return ( this.radius <= 0 ); - distanceToPoint: function (point) { + }, - return ( point.distanceTo(this.center) - this.radius ); + containsPoint: function ( point ) { - }, + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - intersectsSphere: function (sphere) { + }, - var radiusSum = this.radius + sphere.radius; + distanceToPoint: function ( point ) { - return sphere.center.distanceToSquared(this.center) <= ( radiusSum * radiusSum ); + return ( point.distanceTo( this.center ) - this.radius ); - }, + }, - clampPoint: function (point, optionalTarget) { + intersectsSphere: function ( sphere ) { - var deltaLengthSq = this.center.distanceToSquared(point); + var radiusSum = this.radius + sphere.radius; - var result = optionalTarget || new THREE.Vector3(); - result.copy(point); + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - if (deltaLengthSq > ( this.radius * this.radius )) { + }, - result.sub(this.center).normalize(); - result.multiplyScalar(this.radius).add(this.center); + clampPoint: function ( point, optionalTarget ) { - } + var deltaLengthSq = this.center.distanceToSquared( point ); - return result; + var result = optionalTarget || new THREE.Vector3(); + result.copy( point ); - }, + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - getBoundingBox: function (optionalTarget) { + result.sub( this.center ).normalize(); + result.multiplyScalar( this.radius ).add( this.center ); - var box = optionalTarget || new THREE.Box3(); + } - box.set(this.center, this.center); - box.expandByScalar(this.radius); + return result; - return box; + }, - }, + getBoundingBox: function ( optionalTarget ) { - applyMatrix4: function (matrix) { + var box = optionalTarget || new THREE.Box3(); - this.center.applyMatrix4(matrix); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + box.set( this.center, this.center ); + box.expandByScalar( this.radius ); - return this; + return box; - }, + }, - translate: function (offset) { + applyMatrix4: function ( matrix ) { - this.center.add(offset); + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - return this; + return this; - }, + }, - equals: function (sphere) { + translate: function ( offset ) { - return sphere.center.equals(this.center) && ( sphere.radius === this.radius ); + this.center.add( offset ); - }, + return this; - clone: function () { + }, - return new THREE.Sphere().copy(this); + equals: function ( sphere ) { - } + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + } }; @@ -6512,405 +6488,406 @@ THREE.Sphere.prototype = { /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Frustum = function (p0, p1, p2, p3, p4, p5) { +THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { - this.planes = [ + this.planes = [ - ( p0 !== undefined ) ? p0 : new THREE.Plane(), - ( p1 !== undefined ) ? p1 : new THREE.Plane(), - ( p2 !== undefined ) ? p2 : new THREE.Plane(), - ( p3 !== undefined ) ? p3 : new THREE.Plane(), - ( p4 !== undefined ) ? p4 : new THREE.Plane(), - ( p5 !== undefined ) ? p5 : new THREE.Plane() + ( p0 !== undefined ) ? p0 : new THREE.Plane(), + ( p1 !== undefined ) ? p1 : new THREE.Plane(), + ( p2 !== undefined ) ? p2 : new THREE.Plane(), + ( p3 !== undefined ) ? p3 : new THREE.Plane(), + ( p4 !== undefined ) ? p4 : new THREE.Plane(), + ( p5 !== undefined ) ? p5 : new THREE.Plane() - ]; + ]; }; THREE.Frustum.prototype = { - constructor: THREE.Frustum, + constructor: THREE.Frustum, - set: function (p0, p1, p2, p3, p4, p5) { + set: function ( p0, p1, p2, p3, p4, p5 ) { - var planes = this.planes; + 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; + return this; - }, + }, - copy: function (frustum) { + clone: function () { - var planes = this.planes; + return new this.constructor().copy( this ); - for (var i = 0; i < 6; i++) { + }, - planes[i].copy(frustum.planes[i]); + copy: function ( frustum ) { - } + var planes = this.planes; - return this; + for ( var i = 0; i < 6; i ++ ) { - }, + planes[ i ].copy( frustum.planes[ i ] ); - setFromMatrix: function (m) { + } - 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]; + return this; - planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize(); - planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize(); - planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize(); - planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize(); - planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize(); - planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize(); + }, - return this; + setFromMatrix: function ( m ) { - }, + 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 ]; - intersectsObject: function () { + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - var sphere = new THREE.Sphere(); + return this; - return function (object) { + }, - var geometry = object.geometry; + intersectsObject: function () { - if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); + var sphere = new THREE.Sphere(); - sphere.copy(geometry.boundingSphere); - sphere.applyMatrix4(object.matrixWorld); + return function ( object ) { - return this.intersectsSphere(sphere); + var geometry = object.geometry; - }; + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - }(), + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); - intersectsSphere: function (sphere) { + return this.intersectsSphere( sphere ); - var planes = this.planes; - var center = sphere.center; - var negRadius = -sphere.radius; + }; - for (var i = 0; i < 6; i++) { + }(), - var distance = planes[i].distanceToPoint(center); + intersectsSphere: function ( sphere ) { - if (distance < negRadius) { + var planes = this.planes; + var center = sphere.center; + var negRadius = - sphere.radius; - return false; + for ( var i = 0; i < 6; i ++ ) { - } + var distance = planes[ i ].distanceToPoint( center ); - } + if ( distance < negRadius ) { - return true; + return false; - }, + } - intersectsBox: function () { + } - var p1 = new THREE.Vector3(), - p2 = new THREE.Vector3(); + return true; - return function (box) { + }, - var planes = this.planes; + intersectsBox: function () { - for (var i = 0; i < 6; i++) { + var p1 = new THREE.Vector3(), + p2 = new THREE.Vector3(); - var plane = planes[i]; + return function ( box ) { - p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; - p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; - p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; - p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; - p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; - p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; + var planes = this.planes; - var d1 = plane.distanceToPoint(p1); - var d2 = plane.distanceToPoint(p2); + for ( var i = 0; i < 6 ; i ++ ) { - // if both outside plane, no intersection + var plane = planes[ i ]; - if (d1 < 0 && d2 < 0) { + p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; + p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; + p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; + p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; + p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; + p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; - return false; + var d1 = plane.distanceToPoint( p1 ); + var d2 = plane.distanceToPoint( p2 ); - } - } + // if both outside plane, no intersection - return true; - }; + if ( d1 < 0 && d2 < 0 ) { - }(), + return false; + } - containsPoint: function (point) { + } - var planes = this.planes; + return true; - for (var i = 0; i < 6; i++) { + }; - if (planes[i].distanceToPoint(point) < 0) { + }(), - return false; - } + containsPoint: function ( point ) { - } + var planes = this.planes; - return true; + for ( var i = 0; i < 6; i ++ ) { - }, + if ( planes[ i ].distanceToPoint( point ) < 0 ) { - clone: function () { + return false; - return new THREE.Frustum().copy(this); + } - } + } + + return true; + + } }; // File:src/math/Plane.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ -THREE.Plane = function (normal, constant) { +THREE.Plane = function ( normal, constant ) { - this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3(1, 0, 0); - this.constant = ( constant !== undefined ) ? constant : 0; + this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; }; THREE.Plane.prototype = { - constructor: THREE.Plane, - - set: function (normal, constant) { + constructor: THREE.Plane, - this.normal.copy(normal); - this.constant = constant; + set: function ( normal, constant ) { - return this; + this.normal.copy( normal ); + this.constant = constant; - }, + return this; - setComponents: function (x, y, z, w) { + }, - this.normal.set(x, y, z); - this.constant = w; + setComponents: function ( x, y, z, w ) { - return this; + this.normal.set( x, y, z ); + this.constant = w; - }, + return this; - setFromNormalAndCoplanarPoint: function (normal, point) { + }, - this.normal.copy(normal); - this.constant = -point.dot(this.normal); // must be this.normal, not normal, as this.normal is normalized + setFromNormalAndCoplanarPoint: function ( normal, point ) { - return this; + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized - }, + return this; - setFromCoplanarPoints: function () { + }, - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + setFromCoplanarPoints: function () { - return function (a, b, c) { + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - var normal = v1.subVectors(c, b).cross(v2.subVectors(a, b)).normalize(); + return function ( a, b, c ) { - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); - this.setFromNormalAndCoplanarPoint(normal, a); + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - return this; + this.setFromNormalAndCoplanarPoint( normal, a ); - }; + return this; - }(), + }; + }(), - copy: function (plane) { + clone: function () { - this.normal.copy(plane.normal); - this.constant = plane.constant; + return new this.constructor().copy( this ); - return this; + }, - }, + copy: function ( plane ) { - normalize: function () { + this.normal.copy( plane.normal ); + this.constant = plane.constant; - // Note: will lead to a divide by zero if the plane is invalid. + return this; - var inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar(inverseNormalLength); - this.constant *= inverseNormalLength; + }, - return this; + normalize: function () { - }, + // Note: will lead to a divide by zero if the plane is invalid. - negate: function () { + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; - this.constant *= -1; - this.normal.negate(); + return this; - return this; + }, - }, + negate: function () { - distanceToPoint: function (point) { + this.constant *= - 1; + this.normal.negate(); - return this.normal.dot(point) + this.constant; + return this; - }, + }, - distanceToSphere: function (sphere) { + distanceToPoint: function ( point ) { - return this.distanceToPoint(sphere.center) - sphere.radius; + return this.normal.dot( point ) + this.constant; - }, + }, - projectPoint: function (point, optionalTarget) { + distanceToSphere: function ( sphere ) { - return this.orthoPoint(point, optionalTarget).sub(point).negate(); + return this.distanceToPoint( sphere.center ) - sphere.radius; - }, + }, - orthoPoint: function (point, optionalTarget) { + projectPoint: function ( point, optionalTarget ) { - var perpendicularMagnitude = this.distanceToPoint(point); + return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); - var result = optionalTarget || new THREE.Vector3(); - return result.copy(this.normal).multiplyScalar(perpendicularMagnitude); + }, - }, + orthoPoint: function ( point, optionalTarget ) { - isIntersectionLine: function (line) { + var perpendicularMagnitude = this.distanceToPoint( point ); - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); - var startSign = this.distanceToPoint(line.start); - var endSign = this.distanceToPoint(line.end); + }, - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + isIntersectionLine: function ( line ) { - }, + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - intersectLine: function () { + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); - var v1 = new THREE.Vector3(); + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - return function (line, optionalTarget) { + }, - var result = optionalTarget || new THREE.Vector3(); + intersectLine: function () { - var direction = line.delta(v1); + var v1 = new THREE.Vector3(); - var denominator = this.normal.dot(direction); + return function ( line, optionalTarget ) { - if (denominator == 0) { + var result = optionalTarget || new THREE.Vector3(); - // line is coplanar, return origin - if (this.distanceToPoint(line.start) == 0) { + var direction = line.delta( v1 ); - return result.copy(line.start); + var denominator = this.normal.dot( direction ); - } + if ( denominator === 0 ) { - // Unsure if this is the correct method to handle this case. - return undefined; + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { - } + return result.copy( line.start ); - var t = -( line.start.dot(this.normal) + this.constant ) / denominator; + } - if (t < 0 || t > 1) { + // Unsure if this is the correct method to handle this case. + return undefined; - return undefined; + } - } + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - return result.copy(direction).multiplyScalar(t).add(line.start); + if ( t < 0 || t > 1 ) { - }; + return undefined; - }(), + } + return result.copy( direction ).multiplyScalar( t ).add( line.start ); - coplanarPoint: function (optionalTarget) { + }; - var result = optionalTarget || new THREE.Vector3(); - return result.copy(this.normal).multiplyScalar(-this.constant); + }(), - }, - applyMatrix4: function () { + coplanarPoint: function ( optionalTarget ) { - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var m1 = new THREE.Matrix3(); + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); - return function (matrix, optionalNormalMatrix) { + }, - // compute new normal based on theory here: - // http://www.songho.ca/opengl/gl_normaltransform.html - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix(matrix); - var newNormal = v1.copy(this.normal).applyMatrix3(normalMatrix); + applyMatrix4: function () { - var newCoplanarPoint = this.coplanarPoint(v2); - newCoplanarPoint.applyMatrix4(matrix); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var m1 = new THREE.Matrix3(); - this.setFromNormalAndCoplanarPoint(newNormal, newCoplanarPoint); + return function ( matrix, optionalNormalMatrix ) { - return this; + // compute new normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); - }; + var newCoplanarPoint = this.coplanarPoint( v2 ); + newCoplanarPoint.applyMatrix4( matrix ); - }(), + this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); - translate: function (offset) { + return this; - this.constant = this.constant - offset.dot(this.normal); + }; - return this; + }(), - }, + translate: function ( offset ) { - equals: function (plane) { + this.constant = this.constant - offset.dot( this.normal ); - return plane.normal.equals(this.normal) && ( plane.constant == this.constant ); + return this; - }, + }, - clone: function () { + equals: function ( plane ) { - return new THREE.Plane().copy(this); + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - } + } }; @@ -6923,166 +6900,176 @@ THREE.Plane.prototype = { THREE.Math = { - generateUUID: function () { + generateUUID: function () { - // http://www.broofa.com/Tools/Math.uuid.htm + // http://www.broofa.com/Tools/Math.uuid.htm - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); - var uuid = new Array(36); - var rnd = 0, r; + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); + var uuid = new Array( 36 ); + var rnd = 0, r; - return function () { + return function () { - for (var i = 0; i < 36; i++) { + for ( var i = 0; i < 36; i ++ ) { - if (i == 8 || i == 13 || i == 18 || i == 23) { + if ( i === 8 || i === 13 || i === 18 || i === 23 ) { - uuid[i] = '-'; + uuid[ i ] = '-'; - } else if (i == 14) { + } else if ( i === 14 ) { - uuid[i] = '4'; + uuid[ i ] = '4'; - } else { + } else { - if (rnd <= 0x02) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; - r = rnd & 0xf; - rnd = rnd >> 4; - uuid[i] = chars[( i == 19 ) ? ( r & 0x3 ) | 0x8 : r]; + if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; - } - } + } - return uuid.join(''); + } - }; + return uuid.join( '' ); - }(), + }; - // Clamp value to range + }(), - clamp: function (x, a, b) { + // Clamp value to range - return ( x < a ) ? a : ( ( x > b ) ? b : x ); + clamp: function ( x, a, b ) { - }, + return ( x < a ) ? a : ( ( x > b ) ? b : x ); - // Clamp value to range to range + }, - mapLinear: function (x, a1, a2, b1, b2) { + // compute euclidian modulo of m % n + // https://en.wikipedia.org/wiki/Modulo_operation - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + euclideanModulo: function ( n, m ) { - }, + return ( ( n % m ) + m ) % m; - // http://en.wikipedia.org/wiki/Smoothstep + }, - smoothstep: function (x, min, max) { + // Linear mapping from range to range - if (x <= min) return 0; - if (x >= max) return 1; + mapLinear: function ( x, a1, a2, b1, b2 ) { - x = ( x - min ) / ( max - min ); + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - return x * x * ( 3 - 2 * x ); + }, - }, + // http://en.wikipedia.org/wiki/Smoothstep - smootherstep: function (x, min, max) { + smoothstep: function ( x, min, max ) { - if (x <= min) return 0; - if (x >= max) return 1; + 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 * ( 3 - 2 * x ); - }, + }, - // Random float from <0, 1> with 16 bits of randomness - // (standard Math.random() creates repetitive patterns when applied over larger space) + smootherstep: function ( x, min, max ) { - random16: function () { + if ( x <= min ) return 0; + if ( x >= max ) return 1; - return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; + x = ( x - min ) / ( max - min ); - }, + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - // Random integer from interval + }, - randInt: function (low, high) { + // Random float from <0, 1> with 16 bits of randomness + // (standard Math.random() creates repetitive patterns when applied over larger space) - return Math.floor(this.randFloat(low, high)); + random16: function () { - }, + return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; - // Random float from interval + }, - randFloat: function (low, high) { + // Random integer from interval - return low + Math.random() * ( high - low ); + randInt: function ( low, high ) { - }, + return low + Math.floor( Math.random() * ( high - low + 1 ) ); - // Random float from <-range/2, range/2> interval + }, - randFloatSpread: function (range) { + // Random float from interval - return range * ( 0.5 - Math.random() ); + randFloat: function ( low, high ) { - }, + return low + Math.random() * ( high - low ); - degToRad: function () { + }, - var degreeToRadiansFactor = Math.PI / 180; + // Random float from <-range/2, range/2> interval - return function (degrees) { + randFloatSpread: function ( range ) { - return degrees * degreeToRadiansFactor; + return range * ( 0.5 - Math.random() ); - }; + }, - }(), + degToRad: function () { - radToDeg: function () { + var degreeToRadiansFactor = Math.PI / 180; - var radianToDegreesFactor = 180 / Math.PI; + return function ( degrees ) { - return function (radians) { + return degrees * degreeToRadiansFactor; - return radians * radianToDegreesFactor; + }; - }; + }(), - }(), + radToDeg: function () { - isPowerOfTwo: function (value) { + var radianToDegreesFactor = 180 / Math.PI; - return ( value & ( value - 1 ) ) === 0 && value !== 0; + return function ( radians ) { - }, + return radians * radianToDegreesFactor; - nextPowerOfTwo: function (value) { + }; - value--; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value++; + }(), - return value; + 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; + + } }; @@ -7096,365 +7083,367 @@ THREE.Math = { * @author alteredq / http://alteredqualia.com/ */ -THREE.Spline = function (points) { +THREE.Spline = function ( points ) { - this.points = points; + this.points = points; - var c = [], v3 = {x: 0, y: 0, z: 0}, - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; + var c = [], v3 = { x: 0, y: 0, z: 0 }, + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; - this.initFromArray = function (a) { + this.initFromArray = function ( a ) { - this.points = []; + 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]}; + this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; - } + } - }; + }; - this.getPoint = function (k) { + this.getPoint = function ( k ) { - point = ( this.points.length - 1 ) * k; - intPoint = Math.floor(point); - weight = point - intPoint; + point = ( this.points.length - 1 ) * k; + intPoint = Math.floor( point ); + weight = point - intPoint; - c[0] = intPoint === 0 ? intPoint : intPoint - 1; - c[1] = intPoint; - c[2] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; - c[3] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; - pa = this.points[c[0]]; - pb = this.points[c[1]]; - pc = this.points[c[2]]; - pd = this.points[c[3]]; + pa = this.points[ c[ 0 ] ]; + pb = this.points[ c[ 1 ] ]; + pc = this.points[ c[ 2 ] ]; + pd = this.points[ c[ 3 ] ]; - w2 = weight * weight; - w3 = weight * w2; + w2 = weight * weight; + w3 = weight * w2; - v3.x = interpolate(pa.x, pb.x, pc.x, pd.x, weight, w2, w3); - v3.y = interpolate(pa.y, pb.y, pc.y, pd.y, weight, w2, w3); - v3.z = interpolate(pa.z, pb.z, pc.z, pd.z, weight, w2, w3); + v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); + v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); + v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); - return v3; + return v3; - }; + }; - this.getControlPointsArray = function () { + this.getControlPointsArray = function () { - var i, p, l = this.points.length, - coords = []; + var i, p, l = this.points.length, + coords = []; - for (i = 0; i < l; i++) { + for ( i = 0; i < l; i ++ ) { - p = this.points[i]; - coords[i] = [p.x, p.y, p.z]; + p = this.points[ i ]; + coords[ i ] = [ p.x, p.y, p.z ]; - } + } - return coords; + return coords; - }; + }; - // approximate length by summing linear segments + // approximate length by summing linear segments - this.getLength = function (nSubDivisions) { + this.getLength = function ( nSubDivisions ) { - var i, index, nSamples, position, - point = 0, intPoint = 0, oldIntPoint = 0, - oldPosition = new THREE.Vector3(), - tmpVec = new THREE.Vector3(), - chunkLengths = [], - totalLength = 0; + var i, index, nSamples, position, + point = 0, intPoint = 0, oldIntPoint = 0, + oldPosition = new THREE.Vector3(), + tmpVec = new THREE.Vector3(), + chunkLengths = [], + totalLength = 0; - // first point has 0 length + // first point has 0 length - chunkLengths[0] = 0; + chunkLengths[ 0 ] = 0; - if (!nSubDivisions) nSubDivisions = 100; + if ( ! nSubDivisions ) nSubDivisions = 100; - nSamples = this.points.length * nSubDivisions; + nSamples = this.points.length * nSubDivisions; - oldPosition.copy(this.points[0]); + oldPosition.copy( this.points[ 0 ] ); - for (i = 1; i < nSamples; i++) { + for ( i = 1; i < nSamples; i ++ ) { - index = i / nSamples; + index = i / nSamples; - position = this.getPoint(index); - tmpVec.copy(position); + position = this.getPoint( index ); + tmpVec.copy( position ); - totalLength += tmpVec.distanceTo(oldPosition); + totalLength += tmpVec.distanceTo( oldPosition ); - oldPosition.copy(position); + oldPosition.copy( position ); - point = ( this.points.length - 1 ) * index; - intPoint = Math.floor(point); + point = ( this.points.length - 1 ) * index; + intPoint = Math.floor( point ); - if (intPoint != oldIntPoint) { + if ( intPoint !== oldIntPoint ) { - chunkLengths[intPoint] = totalLength; - oldIntPoint = intPoint; + chunkLengths[ intPoint ] = totalLength; + oldIntPoint = intPoint; - } + } - } + } - // last point ends with total length + // last point ends with total length - chunkLengths[chunkLengths.length] = totalLength; + chunkLengths[ chunkLengths.length ] = totalLength; - return {chunks: chunkLengths, total: totalLength}; + return { chunks: chunkLengths, total: totalLength }; - }; + }; - this.reparametrizeByArcLength = function (samplingCoef) { + this.reparametrizeByArcLength = function ( samplingCoef ) { - var i, j, - index, indexCurrent, indexNext, - realDistance, - sampling, position, - newpoints = [], - tmpVec = new THREE.Vector3(), - sl = this.getLength(); + var i, j, + index, indexCurrent, indexNext, + realDistance, + sampling, position, + newpoints = [], + tmpVec = new THREE.Vector3(), + sl = this.getLength(); - newpoints.push(tmpVec.copy(this.points[0]).clone()); + 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 ] ); + //tmpVec.copy( this.points[ i - 1 ] ); + //linearDistance = tmpVec.distanceTo( this.points[ i ] ); - realDistance = sl.chunks[i] - sl.chunks[i - 1]; + realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; - sampling = Math.ceil(samplingCoef * realDistance / sl.total); + sampling = Math.ceil( samplingCoef * realDistance / sl.total ); - indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); - indexNext = i / ( this.points.length - 1 ); + 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 ); + index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); - position = this.getPoint(index); - newpoints.push(tmpVec.copy(position).clone()); + position = this.getPoint( index ); + newpoints.push( tmpVec.copy( position ).clone() ); - } + } - newpoints.push(tmpVec.copy(this.points[i]).clone()); + newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); - } + } - this.points = newpoints; + this.points = newpoints; - }; + }; - // Catmull-Rom + // Catmull-Rom - function interpolate(p0, p1, p2, p3, t, t2, t3) { + function interpolate( p0, p1, p2, p3, t, t2, t3 ) { - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( -3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - } + } }; // File:src/math/Triangle.js /** - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io * @author mrdoob / http://mrdoob.com/ */ -THREE.Triangle = function (a, b, c) { +THREE.Triangle = function ( a, b, c ) { - this.a = ( a !== undefined ) ? a : new THREE.Vector3(); - this.b = ( b !== undefined ) ? b : new THREE.Vector3(); - this.c = ( c !== undefined ) ? c : new THREE.Vector3(); + this.a = ( a !== undefined ) ? a : new THREE.Vector3(); + this.b = ( b !== undefined ) ? b : new THREE.Vector3(); + this.c = ( c !== undefined ) ? c : new THREE.Vector3(); }; THREE.Triangle.normal = function () { - var v0 = new THREE.Vector3(); + var v0 = new THREE.Vector3(); - return function (a, b, c, optionalTarget) { + return function ( a, b, c, optionalTarget ) { - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - result.subVectors(c, b); - v0.subVectors(a, b); - result.cross(v0); + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); - var resultLengthSq = result.lengthSq(); - if (resultLengthSq > 0) { + var resultLengthSq = result.lengthSq(); + if ( resultLengthSq > 0 ) { - return result.multiplyScalar(1 / Math.sqrt(resultLengthSq)); + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); - } + } - return result.set(0, 0, 0); + return result.set( 0, 0, 0 ); - }; + }; }(); -// static/instance method to calculate barycoordinates +// static/instance method to calculate barycentric coordinates // based on: http://www.blackpawn.com/texts/pointinpoly/default.html THREE.Triangle.barycoordFromPoint = function () { - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - return function (point, a, b, c, optionalTarget) { + return function ( point, a, b, c, optionalTarget ) { - v0.subVectors(c, a); - v1.subVectors(b, a); - v2.subVectors(point, a); + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); - var dot00 = v0.dot(v0); - var dot01 = v0.dot(v1); - var dot02 = v0.dot(v2); - var dot11 = v1.dot(v1); - var dot12 = v1.dot(v2); + var dot00 = v0.dot( v0 ); + var dot01 = v0.dot( v1 ); + var dot02 = v0.dot( v2 ); + var dot11 = v1.dot( v1 ); + var dot12 = v1.dot( v2 ); - var denom = ( dot00 * dot11 - dot01 * dot01 ); + var denom = ( dot00 * dot11 - dot01 * dot01 ); - var result = optionalTarget || new THREE.Vector3(); + var result = optionalTarget || new THREE.Vector3(); - // colinear or singular triangle - 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); - } + // collinear or singular triangle + if ( denom === 0 ) { - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return result.set( - 2, - 1, - 1 ); - // barycoordinates must always sum to 1 - return result.set(1 - u - v, v, u); + } - }; + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + + // barycentric coordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); + + }; }(); THREE.Triangle.containsPoint = function () { - var v1 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - return function (point, a, b, c) { + return function ( point, a, b, c ) { - var result = THREE.Triangle.barycoordFromPoint(point, a, b, c, v1); + var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - }; + }; }(); THREE.Triangle.prototype = { - constructor: THREE.Triangle, + constructor: THREE.Triangle, - set: function (a, b, c) { + set: function ( a, b, c ) { - this.a.copy(a); - this.b.copy(b); - this.c.copy(c); + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - return this; + return this; - }, + }, - setFromPointsAndIndices: function (points, i0, i1, i2) { + 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; + return this; - }, + }, - copy: function (triangle) { + clone: function () { - this.a.copy(triangle.a); - this.b.copy(triangle.b); - this.c.copy(triangle.c); + return new this.constructor().copy( this ); - return this; + }, - }, + copy: function ( triangle ) { - area: function () { + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); + return this; - return function () { + }, - v0.subVectors(this.c, this.b); - v1.subVectors(this.a, this.b); + area: function () { - return v0.cross(v1).length() * 0.5; + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); - }; + return function () { - }(), + v0.subVectors( this.c, this.b ); + v1.subVectors( this.a, this.b ); - midpoint: function (optionalTarget) { + return v0.cross( v1 ).length() * 0.5; - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3); + }; - }, + }(), - normal: function (optionalTarget) { + midpoint: function ( optionalTarget ) { - return THREE.Triangle.normal(this.a, this.b, this.c, optionalTarget); + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - }, + }, - plane: function (optionalTarget) { + normal: function ( optionalTarget ) { - var result = optionalTarget || new THREE.Plane(); + return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); - return result.setFromCoplanarPoints(this.a, this.b, this.c); + }, - }, + plane: function ( optionalTarget ) { - barycoordFromPoint: function (point, optionalTarget) { + var result = optionalTarget || new THREE.Plane(); - return THREE.Triangle.barycoordFromPoint(point, this.a, this.b, this.c, optionalTarget); + return result.setFromCoplanarPoints( this.a, this.b, this.c ); - }, + }, - containsPoint: function (point) { + barycoordFromPoint: function ( point, optionalTarget ) { - return THREE.Triangle.containsPoint(point, this.a, this.b, this.c); + return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); - }, + }, - equals: function (triangle) { + containsPoint: function ( point ) { - return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c); + return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); - }, + }, - clone: function () { + equals: function ( triangle ) { - return new THREE.Triangle().copy(this); + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - } + } }; @@ -7464,72 +7453,77 @@ THREE.Triangle.prototype = { * @author alteredq / http://alteredqualia.com/ */ -THREE.Clock = function (autoStart) { +THREE.Clock = function ( autoStart ) { - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - this.running = false; + this.running = false; }; THREE.Clock.prototype = { - constructor: THREE.Clock, + constructor: THREE.Clock, - start: function () { + _now: function () { - this.startTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + return self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); - this.oldTime = this.startTime; - this.running = true; - }, + }, - stop: function () { + start: function () { - this.getElapsedTime(); - this.running = false; + this.startTime = this._now(); - }, + this.oldTime = this.startTime; + this.running = true; - getElapsedTime: function () { + }, - this.getDelta(); - return this.elapsedTime; + stop: function () { - }, + this.getElapsedTime(); + this.running = false; - getDelta: function () { + }, - var diff = 0; + getElapsedTime: function () { - if (this.autoStart && !this.running) { + this.getDelta(); + return this.elapsedTime; - this.start(); + }, - } + getDelta: function () { - if (this.running) { + var diff = 0; - var newTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); + if ( this.autoStart && ! this.running ) { - diff = 0.001 * ( newTime - this.oldTime ); - this.oldTime = newTime; + this.start(); - this.elapsedTime += diff; + } - } + if ( this.running ) { - return diff; + var newTime = this._now(); - } + diff = 0.001 * ( newTime - this.oldTime ); + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } }; @@ -7539,108 +7533,107 @@ THREE.Clock.prototype = { * https://github.com/mrdoob/eventdispatcher.js/ */ -THREE.EventDispatcher = function () { -}; +THREE.EventDispatcher = function () {}; THREE.EventDispatcher.prototype = { - constructor: THREE.EventDispatcher, + constructor: THREE.EventDispatcher, - apply: function (object) { + apply: function ( object ) { - object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; - object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; - object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; - object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; + object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; + object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; + object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; + object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; - }, + }, - addEventListener: function (type, listener) { + addEventListener: function ( type, listener ) { - if (this._listeners === undefined) this._listeners = {}; + if ( this._listeners === undefined ) this._listeners = {}; - var listeners = this._listeners; + var listeners = this._listeners; - if (listeners[type] === undefined) { + if ( listeners[ type ] === undefined ) { - listeners[type] = []; + listeners[ type ] = []; - } + } - if (listeners[type].indexOf(listener) === -1) { + if ( listeners[ type ].indexOf( listener ) === - 1 ) { - listeners[type].push(listener); + listeners[ type ].push( listener ); - } + } - }, + }, - hasEventListener: function (type, listener) { + hasEventListener: function ( type, listener ) { - if (this._listeners === undefined) return false; + if ( this._listeners === undefined ) return false; - var listeners = this._listeners; + var listeners = this._listeners; - if (listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1) { + if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { - return true; + return true; - } + } - return false; + return false; - }, + }, - removeEventListener: function (type, listener) { + removeEventListener: function ( type, listener ) { - if (this._listeners === undefined) return; + if ( this._listeners === undefined ) return; - var listeners = this._listeners; - var listenerArray = listeners[type]; + var listeners = this._listeners; + var listenerArray = listeners[ type ]; - if (listenerArray !== undefined) { + if ( listenerArray !== undefined ) { - var index = listenerArray.indexOf(listener); + var index = listenerArray.indexOf( listener ); - if (index !== -1) { + if ( index !== - 1 ) { - listenerArray.splice(index, 1); + listenerArray.splice( index, 1 ); - } + } - } + } - }, + }, - dispatchEvent: function (event) { + dispatchEvent: function ( event ) { - if (this._listeners === undefined) return; + if ( this._listeners === undefined ) return; - var listeners = this._listeners; - var listenerArray = listeners[event.type]; + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; - if (listenerArray !== undefined) { + if ( listenerArray !== undefined ) { - event.target = this; + event.target = this; - var array = []; - var length = listenerArray.length; + var array = []; + var length = listenerArray.length; - for (var i = 0; i < length; i++) { + for ( var i = 0; i < length; i ++ ) { - array[i] = listenerArray[i]; + array[ i ] = listenerArray[ i ]; - } + } - for (var i = 0; i < length; i++) { + for ( var i = 0; i < length; i ++ ) { - array[i].call(this, event); + array[ i ].call( this, event ); - } + } - } + } - } + } }; @@ -7648,129 +7641,139 @@ THREE.EventDispatcher.prototype = { /** * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://exocortex.com/ + * @author bhouston / http://clara.io/ * @author stephomi / http://stephaneginier.com/ */ -( function (THREE) { +( function ( THREE ) { + + THREE.Raycaster = function ( origin, direction, near, far ) { + + this.ray = new THREE.Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) - THREE.Raycaster = function (origin, direction, near, far) { + this.near = near || 0; + this.far = far || Infinity; - this.ray = new THREE.Ray(origin, direction); - // direction is assumed to be normalized (for accurate distance calculations) + this.params = { + Mesh: {}, + Line: {}, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; - this.near = near || 0; - this.far = far || Infinity; + Object.defineProperties( this.params, { + PointCloud: { + get: function () { + console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); + return this.Points; + } + } + } ); - this.params = { - Sprite: {}, - Mesh: {}, - PointCloud: {threshold: 1}, - LOD: {}, - Line: {} - }; + }; - }; + function descSort( a, b ) { - var descSort = function (a, b) { + return a.distance - b.distance; - return a.distance - b.distance; + } - }; + var intersectObject = function ( object, raycaster, intersects, recursive ) { - var intersectObject = function (object, raycaster, intersects, recursive) { + if ( object.visible === false ) return; - object.raycast(raycaster, intersects); + object.raycast( raycaster, intersects ); - if (recursive === true) { + if ( recursive === true ) { - var children = object.children; + var children = object.children; - for (var i = 0, l = children.length; i < l; i++) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - intersectObject(children[i], raycaster, intersects, true); + intersectObject( children[ i ], raycaster, intersects, true ); - } + } - } + } - }; + }; - // + // - THREE.Raycaster.prototype = { + THREE.Raycaster.prototype = { - constructor: THREE.Raycaster, + constructor: THREE.Raycaster, - precision: 0.0001, - linePrecision: 1, + linePrecision: 1, - set: function (origin, direction) { + set: function ( origin, direction ) { - // direction is assumed to be normalized (for accurate distance calculations) + // direction is assumed to be normalized (for accurate distance calculations) - this.ray.set(origin, direction); + this.ray.set( origin, direction ); - }, + }, - setFromCamera: function (coords, camera) { + setFromCamera: function ( coords, camera ) { - if (camera instanceof THREE.PerspectiveCamera) { + if ( camera instanceof THREE.PerspectiveCamera ) { - this.ray.origin.setFromMatrixPosition(camera.matrixWorld); - this.ray.direction.set(coords.x, coords.y, 0.5).unproject(camera).sub(this.ray.origin).normalize(); + this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - } else if (camera instanceof THREE.OrthographicCamera) { + } else if ( camera instanceof THREE.OrthographicCamera ) { - this.ray.origin.set(coords.x, coords.y, -1).unproject(camera); - this.ray.direction.set(0, 0, -1).transformDirection(camera.matrixWorld); + this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - } else { + } else { - THREE.error('THREE.Raycaster: Unsupported camera type.'); + console.error( 'THREE.Raycaster: Unsupported camera type.' ); - } + } - }, + }, - intersectObject: function (object, recursive) { + intersectObject: function ( object, recursive ) { - var intersects = []; + var intersects = []; - intersectObject(object, this, intersects, recursive); + intersectObject( object, this, intersects, recursive ); - intersects.sort(descSort); + intersects.sort( descSort ); - return intersects; + return intersects; - }, + }, - intersectObjects: function (objects, recursive) { + intersectObjects: function ( objects, recursive ) { - var intersects = []; + var intersects = []; - if (objects instanceof Array === false) { + if ( Array.isArray( objects ) === false ) { - THREE.warn('THREE.Raycaster.intersectObjects: objects is not an Array.'); - return intersects; + console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; - } + } - for (var i = 0, l = objects.length; i < l; i++) { + for ( var i = 0, l = objects.length; i < l; i ++ ) { - intersectObject(objects[i], this, intersects, recursive); + intersectObject( objects[ i ], this, intersects, recursive ); - } + } - intersects.sort(descSort); + intersects.sort( descSort ); - return intersects; + return intersects; - } + } - }; + }; -}(THREE) ); +}( THREE ) ); // File:src/core/Object3D.js @@ -7779,705 +7782,734 @@ THREE.EventDispatcher.prototype = { * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley + * @author elephantatwork / www.elephantatwork.ch */ THREE.Object3D = function () { - Object.defineProperty(this, 'id', {value: THREE.Object3DIdCount++}); + Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } ); + + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = THREE.Object3D.DefaultUp.clone(); - this.uuid = THREE.Math.generateUUID(); + var position = new THREE.Vector3(); + var rotation = new THREE.Euler(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3( 1, 1, 1 ); - this.name = ''; - this.type = 'Object3D'; + var onRotationChange = function () { - this.parent = undefined; - this.children = []; + quaternion.setFromEuler( rotation, false ); - this.up = THREE.Object3D.DefaultUp.clone(); + }; - var position = new THREE.Vector3(); - var rotation = new THREE.Euler(); - var quaternion = new THREE.Quaternion(); - var scale = new THREE.Vector3(1, 1, 1); + var onQuaternionChange = function () { - var onRotationChange = function () { - quaternion.setFromEuler(rotation, false); - }; + rotation.setFromQuaternion( quaternion, undefined, false ); - var onQuaternionChange = function () { - rotation.setFromQuaternion(quaternion, undefined, false); - }; + }; - rotation.onChange(onRotationChange); - quaternion.onChange(onQuaternionChange); + rotation.onChange( onRotationChange ); + quaternion.onChange( onQuaternionChange ); - Object.defineProperties(this, { - position: { - enumerable: true, - value: position - }, - rotation: { - enumerable: true, - value: rotation - }, - quaternion: { - enumerable: true, - value: quaternion - }, - scale: { - enumerable: true, - value: scale - } - }); + Object.defineProperties( this, { + position: { + enumerable: true, + value: position + }, + rotation: { + enumerable: true, + value: rotation + }, + quaternion: { + enumerable: true, + value: quaternion + }, + scale: { + enumerable: true, + value: scale + }, + modelViewMatrix: { + value: new THREE.Matrix4() + }, + normalMatrix: { + value: new THREE.Matrix3() + } + } ); - this.rotationAutoUpdate = true; + this.rotationAutoUpdate = true; - this.matrix = new THREE.Matrix4(); - this.matrixWorld = new THREE.Matrix4(); + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); - this.matrixAutoUpdate = true; - this.matrixWorldNeedsUpdate = false; + this.matrixAutoUpdate = THREE.Object3D.DefaultMatrixAutoUpdate; + this.matrixWorldNeedsUpdate = false; - this.visible = true; + this.visible = true; - this.castShadow = false; - this.receiveShadow = false; + this.castShadow = false; + this.receiveShadow = false; - this.frustumCulled = true; - this.renderOrder = 0; + this.frustumCulled = true; + this.renderOrder = 0; - this.userData = {}; + this.userData = {}; }; -THREE.Object3D.DefaultUp = new THREE.Vector3(0, 1, 0); +THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 ); +THREE.Object3D.DefaultMatrixAutoUpdate = true; THREE.Object3D.prototype = { - constructor: THREE.Object3D, + constructor: THREE.Object3D, - get eulerOrder() { + get eulerOrder () { - THREE.warn('THREE.Object3D: .eulerOrder has been moved to .rotation.order.'); + console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - return this.rotation.order; + return this.rotation.order; - }, + }, - set eulerOrder(value) { + set eulerOrder ( value ) { - THREE.warn('THREE.Object3D: .eulerOrder has been moved to .rotation.order.'); + console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); - this.rotation.order = value; + this.rotation.order = value; - }, + }, - get useQuaternion() { + get useQuaternion () { - THREE.warn('THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.'); + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - }, + }, - set useQuaternion(value) { + set useQuaternion ( value ) { - THREE.warn('THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.'); + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - }, + }, - applyMatrix: function (matrix) { + set renderDepth ( value ) { - this.matrix.multiplyMatrices(matrix, this.matrix); + console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); - this.matrix.decompose(this.position, this.quaternion, this.scale); + }, - }, + applyMatrix: function ( matrix ) { - setRotationFromAxisAngle: function (axis, angle) { + this.matrix.multiplyMatrices( matrix, this.matrix ); - // assumes axis is normalized + this.matrix.decompose( this.position, this.quaternion, this.scale ); - this.quaternion.setFromAxisAngle(axis, angle); + }, - }, + setRotationFromAxisAngle: function ( axis, angle ) { - setRotationFromEuler: function (euler) { + // assumes axis is normalized - this.quaternion.setFromEuler(euler, true); + this.quaternion.setFromAxisAngle( axis, angle ); - }, + }, - setRotationFromMatrix: function (m) { + setRotationFromEuler: function ( euler ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + this.quaternion.setFromEuler( euler, true ); - this.quaternion.setFromRotationMatrix(m); + }, - }, + setRotationFromMatrix: function ( m ) { - setRotationFromQuaternion: function (q) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - // assumes q is normalized + this.quaternion.setFromRotationMatrix( m ); - this.quaternion.copy(q); + }, - }, + setRotationFromQuaternion: function ( q ) { - rotateOnAxis: function () { + // assumes q is normalized - // rotate object on axis in object space - // axis is assumed to be normalized + this.quaternion.copy( q ); - var q1 = new THREE.Quaternion(); + }, - return function (axis, angle) { + rotateOnAxis: function () { - q1.setFromAxisAngle(axis, angle); + // rotate object on axis in object space + // axis is assumed to be normalized - this.quaternion.multiply(q1); + var q1 = new THREE.Quaternion(); - return this; + return function ( axis, angle ) { - } + q1.setFromAxisAngle( axis, angle ); - }(), + this.quaternion.multiply( q1 ); - rotateX: function () { + return this; - var v1 = new THREE.Vector3(1, 0, 0); + }; - return function (angle) { + }(), - return this.rotateOnAxis(v1, angle); + rotateX: function () { - }; + var v1 = new THREE.Vector3( 1, 0, 0 ); - }(), + return function ( angle ) { - rotateY: function () { + return this.rotateOnAxis( v1, angle ); - var v1 = new THREE.Vector3(0, 1, 0); + }; - return function (angle) { + }(), - return this.rotateOnAxis(v1, angle); + rotateY: function () { - }; + var v1 = new THREE.Vector3( 0, 1, 0 ); - }(), + return function ( angle ) { - rotateZ: function () { + return this.rotateOnAxis( v1, angle ); - var v1 = new THREE.Vector3(0, 0, 1); + }; - return function (angle) { + }(), - return this.rotateOnAxis(v1, angle); + rotateZ: function () { - }; + var v1 = new THREE.Vector3( 0, 0, 1 ); - }(), + return function ( angle ) { - translateOnAxis: function () { + return this.rotateOnAxis( v1, angle ); - // translate object by distance along axis in object space - // axis is assumed to be normalized + }; - var v1 = new THREE.Vector3(); + }(), - return function (axis, distance) { + translateOnAxis: function () { - v1.copy(axis).applyQuaternion(this.quaternion); + // translate object by distance along axis in object space + // axis is assumed to be normalized - this.position.add(v1.multiplyScalar(distance)); + var v1 = new THREE.Vector3(); - return this; + return function ( axis, distance ) { - } + v1.copy( axis ).applyQuaternion( this.quaternion ); - }(), + this.position.add( v1.multiplyScalar( distance ) ); - translate: function (distance, axis) { + return this; - THREE.warn('THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.'); - return this.translateOnAxis(axis, distance); + }; - }, + }(), - translateX: function () { + translate: function ( distance, axis ) { - var v1 = new THREE.Vector3(1, 0, 0); + console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + return this.translateOnAxis( axis, distance ); - return function (distance) { + }, - return this.translateOnAxis(v1, distance); + translateX: function () { - }; + var v1 = new THREE.Vector3( 1, 0, 0 ); - }(), + return function ( distance ) { - translateY: function () { + return this.translateOnAxis( v1, distance ); - var v1 = new THREE.Vector3(0, 1, 0); + }; - return function (distance) { + }(), - return this.translateOnAxis(v1, distance); + translateY: function () { - }; + var v1 = new THREE.Vector3( 0, 1, 0 ); - }(), + return function ( distance ) { - translateZ: function () { + return this.translateOnAxis( v1, distance ); - var v1 = new THREE.Vector3(0, 0, 1); + }; - return function (distance) { + }(), - return this.translateOnAxis(v1, distance); + translateZ: function () { - }; + var v1 = new THREE.Vector3( 0, 0, 1 ); - }(), + return function ( distance ) { - localToWorld: function (vector) { + return this.translateOnAxis( v1, distance ); - return vector.applyMatrix4(this.matrixWorld); + }; - }, + }(), - worldToLocal: function () { + localToWorld: function ( vector ) { - var m1 = new THREE.Matrix4(); + return vector.applyMatrix4( this.matrixWorld ); - return function (vector) { + }, - return vector.applyMatrix4(m1.getInverse(this.matrixWorld)); + worldToLocal: function () { - }; + var m1 = new THREE.Matrix4(); - }(), + return function ( vector ) { - lookAt: function () { + return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); - // This routine does not support objects with rotated and/or translated parent(s) + }; - var m1 = new THREE.Matrix4(); + }(), - return function (vector) { + lookAt: function () { - m1.lookAt(vector, this.position, this.up); + // This routine does not support objects with rotated and/or translated parent(s) - this.quaternion.setFromRotationMatrix(m1); + var m1 = new THREE.Matrix4(); - }; + return function ( vector ) { - }(), + m1.lookAt( vector, this.position, this.up ); - add: function (object) { + this.quaternion.setFromRotationMatrix( m1 ); - if (arguments.length > 1) { + }; - for (var i = 0; i < arguments.length; i++) { + }(), - this.add(arguments[i]); + add: function ( object ) { - } + if ( arguments.length > 1 ) { - return this; + for ( var i = 0; i < arguments.length; i ++ ) { - } + this.add( arguments[ i ] ); - if (object === this) { + } - THREE.error("THREE.Object3D.add: object can't be added as a child of itself.", object); - return this; + return this; - } + } - if (object instanceof THREE.Object3D) { + if ( object === this ) { - if (object.parent !== undefined) { + console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; - object.parent.remove(object); + } - } + if ( object instanceof THREE.Object3D ) { - object.parent = this; - object.dispatchEvent({type: 'added'}); + if ( object.parent !== null ) { - this.children.push(object); + object.parent.remove( object ); - } else { + } - THREE.error("THREE.Object3D.add: object not an instance of THREE.Object3D.", object); + object.parent = this; + object.dispatchEvent( { type: 'added' } ); - } + this.children.push( object ); - return this; + } else { - }, + console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - remove: function (object) { + } - if (arguments.length > 1) { + return this; - for (var i = 0; i < arguments.length; i++) { + }, - this.remove(arguments[i]); + remove: function ( object ) { - } + if ( arguments.length > 1 ) { - } + for ( var i = 0; i < arguments.length; i ++ ) { - var index = this.children.indexOf(object); + this.remove( arguments[ i ] ); - if (index !== -1) { + } - object.parent = undefined; + } - object.dispatchEvent({type: 'removed'}); + var index = this.children.indexOf( object ); - this.children.splice(index, 1); + if ( index !== - 1 ) { - } + object.parent = null; - }, + object.dispatchEvent( { type: 'removed' } ); - getChildByName: function (name) { + this.children.splice( index, 1 ); - THREE.warn('THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().'); - return this.getObjectByName(name); + } - }, + }, - getObjectById: function (id) { + getChildByName: function ( name ) { - return this.getObjectByProperty('id', id); + console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); - }, + }, - getObjectByName: function (name) { + getObjectById: function ( id ) { - return this.getObjectByProperty('name', name); + return this.getObjectByProperty( 'id', id ); - }, + }, - getObjectByProperty: function (name, value) { + getObjectByName: function ( name ) { - if (this[name] === value) return this; + return this.getObjectByProperty( 'name', name ); - for (var i = 0, l = this.children.length; i < l; i++) { + }, - var child = this.children[i]; - var object = child.getObjectByProperty(name, value); + getObjectByProperty: function ( name, value ) { - if (object !== undefined) { + if ( this[ name ] === value ) return this; - return object; + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - } + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); - } + if ( object !== undefined ) { - return undefined; + return object; - }, + } - getWorldPosition: function (optionalTarget) { + } - var result = optionalTarget || new THREE.Vector3(); + return undefined; - this.updateMatrixWorld(true); + }, - return result.setFromMatrixPosition(this.matrixWorld); + getWorldPosition: function ( optionalTarget ) { - }, + var result = optionalTarget || new THREE.Vector3(); - getWorldQuaternion: function () { + this.updateMatrixWorld( true ); - var position = new THREE.Vector3(); - var scale = new THREE.Vector3(); + return result.setFromMatrixPosition( this.matrixWorld ); - return function (optionalTarget) { + }, - var result = optionalTarget || new THREE.Quaternion(); + getWorldQuaternion: function () { - this.updateMatrixWorld(true); + var position = new THREE.Vector3(); + var scale = new THREE.Vector3(); - this.matrixWorld.decompose(position, result, scale); + return function ( optionalTarget ) { - return result; + var result = optionalTarget || new THREE.Quaternion(); - } + this.updateMatrixWorld( true ); - }(), + this.matrixWorld.decompose( position, result, scale ); - getWorldRotation: function () { + return result; - var quaternion = new THREE.Quaternion(); + }; - return function (optionalTarget) { + }(), - var result = optionalTarget || new THREE.Euler(); + getWorldRotation: function () { - this.getWorldQuaternion(quaternion); + var quaternion = new THREE.Quaternion(); - return result.setFromQuaternion(quaternion, this.rotation.order, false); + return function ( optionalTarget ) { - } + var result = optionalTarget || new THREE.Euler(); - }(), + this.getWorldQuaternion( quaternion ); - getWorldScale: function () { + return result.setFromQuaternion( quaternion, this.rotation.order, false ); - var position = new THREE.Vector3(); - var quaternion = new THREE.Quaternion(); + }; - return function (optionalTarget) { + }(), - var result = optionalTarget || new THREE.Vector3(); + getWorldScale: function () { - this.updateMatrixWorld(true); + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); - this.matrixWorld.decompose(position, quaternion, result); + return function ( optionalTarget ) { - return result; + var result = optionalTarget || new THREE.Vector3(); - } + this.updateMatrixWorld( true ); - }(), + this.matrixWorld.decompose( position, quaternion, result ); - getWorldDirection: function () { + return result; - var quaternion = new THREE.Quaternion(); + }; - return function (optionalTarget) { + }(), - var result = optionalTarget || new THREE.Vector3(); + getWorldDirection: function () { - this.getWorldQuaternion(quaternion); + var quaternion = new THREE.Quaternion(); - return result.set(0, 0, 1).applyQuaternion(quaternion); + return function ( optionalTarget ) { - } + var result = optionalTarget || new THREE.Vector3(); - }(), + this.getWorldQuaternion( quaternion ); - raycast: function () { - }, + return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); - traverse: function (callback) { + }; - callback(this); + }(), - for (var i = 0, l = this.children.length; i < l; i++) { + raycast: function () {}, - this.children[i].traverse(callback); + traverse: function ( callback ) { - } + callback( this ); - }, + var children = this.children; - traverseVisible: function (callback) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - if (this.visible === false) return; + children[ i ].traverse( callback ); - callback(this); + } - for (var i = 0, l = this.children.length; i < l; i++) { + }, - this.children[i].traverseVisible(callback); + traverseVisible: function ( callback ) { - } + if ( this.visible === false ) return; - }, + callback( this ); - traverseAncestors: function (callback) { + var children = this.children; - if (this.parent) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - callback(this.parent); + children[ i ].traverseVisible( callback ); - this.parent.traverseAncestors(callback); + } - } + }, - }, + traverseAncestors: function ( callback ) { - updateMatrix: function () { + var parent = this.parent; - this.matrix.compose(this.position, this.quaternion, this.scale); + if ( parent !== null ) { - this.matrixWorldNeedsUpdate = true; + callback( parent ); - }, + parent.traverseAncestors( callback ); - updateMatrixWorld: function (force) { + } - if (this.matrixAutoUpdate === true) this.updateMatrix(); + }, - if (this.matrixWorldNeedsUpdate === true || force === true) { + updateMatrix: function () { - if (this.parent === undefined) { + this.matrix.compose( this.position, this.quaternion, this.scale ); - this.matrixWorld.copy(this.matrix); + this.matrixWorldNeedsUpdate = true; - } else { + }, - this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix); + updateMatrixWorld: function ( force ) { - } + if ( this.matrixAutoUpdate === true ) this.updateMatrix(); - this.matrixWorldNeedsUpdate = false; + if ( this.matrixWorldNeedsUpdate === true || force === true ) { - force = true; + if ( this.parent === null ) { - } + this.matrixWorld.copy( this.matrix ); - // update children + } else { - for (var i = 0, l = this.children.length; i < l; i++) { + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - this.children[i].updateMatrixWorld(force); + } - } + this.matrixWorldNeedsUpdate = false; - }, + force = true; - toJSON: function (meta) { + } - var isRootObject = ( meta === undefined ); + // update children - // we will store all serialization data on 'data' - var data = {}; - var metadata; + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if (isRootObject) { + this.children[ i ].updateMatrixWorld( force ); - // initialize meta obj - meta = { - geometries: {}, - materials: {} - }; + } - // add metadata - metadata = { - version: 4.4, - type: 'Object', - generator: 'Object3D.toJSON' - } + }, - } + toJSON: function ( meta ) { - // standard Object3D serialization + var isRootObject = ( meta === undefined ); - data.type = this.type; - data.uuid = this.uuid; - if (this.name !== '') data.name = this.name; - if (JSON.stringify(this.userData) !== '{}') data.userData = this.userData; - if (this.visible !== true) data.visible = this.visible; + var data = {}; + var output = { object: data }; - data.matrix = this.matrix.toArray(); + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - if (this.children.length > 0) { + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {} + }; - data.children = []; + output.metadata = { + version: 4.4, + type: 'Object', + generator: 'Object3D.toJSON' + }; - for (var i = 0; i < this.children.length; i++) { + } - data.children.push(this.children[i].toJSON(meta).object); + // standard Object3D serialization - } + data.uuid = this.uuid; + data.type = this.type; - } + if ( this.name !== '' ) data.name = this.name; + if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + if ( this.visible !== true ) data.visible = this.visible; - // wrap serialized object with additional data + data.matrix = this.matrix.toArray(); - var output; + if ( this.children.length > 0 ) { - if (isRootObject) { + data.children = []; - output = { - metadata: metadata, - geometries: extractFromCache(meta.geometries), - materials: extractFromCache(meta.materials), - object: data - }; + for ( var i = 0; i < this.children.length; i ++ ) { - } else { + data.children.push( this.children[ i ].toJSON( meta ).object ); - output = {object: data}; + } - } + } - return output; + if ( isRootObject ) { - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache(cache) { - var values = []; - for (var key in cache) { - var data = cache[key]; - delete data.metadata; - values.push(data); - } - return values; - } + var geometries = extractFromCache( meta.geometries ); + var materials = extractFromCache( meta.materials ); + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); - }, + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; - clone: function (object, recursive) { + } - if (object === undefined) object = new THREE.Object3D(); - if (recursive === undefined) recursive = true; + return output; - object.name = this.name; + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache ( cache ) { - object.up.copy(this.up); + var values = []; + for ( var key in cache ) { - object.position.copy(this.position); - object.quaternion.copy(this.quaternion); - object.scale.copy(this.scale); + var data = cache[ key ]; + delete data.metadata; + values.push( data ); - object.rotationAutoUpdate = this.rotationAutoUpdate; + } + return values; - object.matrix.copy(this.matrix); - object.matrixWorld.copy(this.matrixWorld); + } - object.matrixAutoUpdate = this.matrixAutoUpdate; - object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + }, - object.visible = this.visible; + clone: function ( recursive ) { - object.castShadow = this.castShadow; - object.receiveShadow = this.receiveShadow; + return new this.constructor().copy( this, recursive ); - object.frustumCulled = this.frustumCulled; + }, - object.userData = JSON.parse(JSON.stringify(this.userData)); + copy: function ( source, recursive ) { - if (recursive === true) { + if ( recursive === undefined ) recursive = true; - for (var i = 0; i < this.children.length; i++) { + this.name = source.name; - var child = this.children[i]; - object.add(child.clone()); + this.up.copy( source.up ); - } + this.position.copy( source.position ); + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); - } + this.rotationAutoUpdate = source.rotationAutoUpdate; - return object; + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - } + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + + this.visible = source.visible; + + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; + + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; + + this.userData = JSON.parse( JSON.stringify( source.userData ) ); + + if ( recursive === true ) { + + for ( var i = 0; i < source.children.length; i ++ ) { + + var child = source.children[ i ]; + this.add( child.clone() ); + + } + + } + + return this; + + } }; -THREE.EventDispatcher.prototype.apply(THREE.Object3D.prototype); +THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); THREE.Object3DIdCount = 0; @@ -8488,54 +8520,58 @@ THREE.Object3DIdCount = 0; * @author alteredq / http://alteredqualia.com/ */ -THREE.Face3 = function (a, b, c, normal, color) { +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { - this.a = a; - this.b = b; - this.c = c; + this.a = a; + this.b = b; + this.c = c; - this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); - this.vertexNormals = normal instanceof Array ? normal : []; + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = Array.isArray( normal ) ? normal : []; - this.color = color instanceof THREE.Color ? color : new THREE.Color(); - this.vertexColors = color instanceof Array ? color : []; + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = Array.isArray( color ) ? color : []; - this.vertexTangents = []; + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; }; THREE.Face3.prototype = { - constructor: THREE.Face3, + constructor: THREE.Face3, - clone: function () { + clone: function () { - var face = new THREE.Face3(this.a, this.b, this.c); + return new this.constructor().copy( this ); - face.normal.copy(this.normal); - face.color.copy(this.color); + }, - for (var i = 0, il = this.vertexNormals.length; i < il; i++) { + copy: function ( source ) { - face.vertexNormals[i] = this.vertexNormals[i].clone(); + this.a = source.a; + this.b = source.b; + this.c = source.c; - } + this.normal.copy( source.normal ); + this.color.copy( source.color ); - for (var i = 0, il = this.vertexColors.length; i < il; i++) { + this.materialIndex = source.materialIndex; - face.vertexColors[i] = this.vertexColors[i].clone(); + for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { - } + this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); - for (var i = 0, il = this.vertexTangents.length; i < il; i++) { + } - face.vertexTangents[i] = this.vertexTangents[i].clone(); + for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { - } + this.vertexColors[ i ] = source.vertexColors[ i ].clone(); - return face; + } - } + return this; + + } }; @@ -8545,10 +8581,10 @@ THREE.Face3.prototype = { * @author mrdoob / http://mrdoob.com/ */ -THREE.Face4 = function (a, b, c, d, normal, color, materialIndex) { +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - THREE.warn('THREE.Face4 has been removed. A THREE.Face3 will be created instead.'); - return new THREE.Face3(a, b, c, normal, color, materialIndex); + console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); + return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; @@ -8558,337 +8594,376 @@ THREE.Face4 = function (a, b, c, d, normal, color, materialIndex) { * @author mrdoob / http://mrdoob.com/ */ -THREE.BufferAttribute = function (array, itemSize) { +THREE.BufferAttribute = function ( array, itemSize ) { + + this.uuid = THREE.Math.generateUUID(); + + this.array = array; + this.itemSize = itemSize; - this.array = array; - this.itemSize = itemSize; + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; - this.needsUpdate = false; + this.version = 0; }; THREE.BufferAttribute.prototype = { - constructor: THREE.BufferAttribute, + constructor: THREE.BufferAttribute, - get length() { + get length() { - return this.array.length; + console.warn( 'THREE.BufferAttribute: .length has been deprecated. Please use .count.' ); + return this.array.length; - }, + }, - copyAt: function (index1, attribute, index2) { + get count() { - index1 *= this.itemSize; - index2 *= attribute.itemSize; + return this.array.length / this.itemSize; - for (var i = 0, l = this.itemSize; i < l; i++) { + }, - this.array[index1 + i] = attribute.array[index2 + i]; + set needsUpdate( value ) { - } + if ( value === true ) this.version ++; - return this; + }, - }, + setDynamic: function ( value ) { - copyArray: function (array) { + this.dynamic = value; - this.array.set(array); + return this; - return this; + }, - }, + copy: function ( source ) { - copyColorsArray: function (colors) { + this.array = new source.array.constructor( source.array ); + this.itemSize = source.itemSize; - var array = this.array, offset = 0; + this.dynamic = source.dynamic; - for (var i = 0, l = colors.length; i < l; i++) { + return this; - var color = colors[i]; + }, - if (color === undefined) { + copyAt: function ( index1, attribute, index2 ) { - console.warn('THREE.BufferAttribute.copyColorsArray(): color is undefined', i); - color = new THREE.Color(); + index1 *= this.itemSize; + index2 *= attribute.itemSize; - } + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - array[offset++] = color.r; - array[offset++] = color.g; - array[offset++] = color.b; + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - } + } - return this; + return this; - }, + }, - copyFacesArray: function (faces) { + copyArray: function ( array ) { - var array = this.array, offset = 0; + this.array.set( array ); - for (var i = 0, l = faces.length; i < l; i++) { + return this; - var face = faces[i]; + }, - array[offset++] = face.a; - array[offset++] = face.b; - array[offset++] = face.c; + copyColorsArray: function ( colors ) { - } + var array = this.array, offset = 0; - return this; + for ( var i = 0, l = colors.length; i < l; i ++ ) { - }, + var color = colors[ i ]; - copyVector2sArray: function (vectors) { + if ( color === undefined ) { - var array = this.array, offset = 0; + console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); + color = new THREE.Color(); - for (var i = 0, l = vectors.length; i < l; i++) { + } - var vector = vectors[i]; + array[ offset ++ ] = color.r; + array[ offset ++ ] = color.g; + array[ offset ++ ] = color.b; - if (vector === undefined) { + } - console.warn('THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i); - vector = new THREE.Vector2(); + return this; - } + }, - array[offset++] = vector.x; - array[offset++] = vector.y; + copyIndicesArray: function ( indices ) { - } + var array = this.array, offset = 0; - return this; + for ( var i = 0, l = indices.length; i < l; i ++ ) { - }, + var index = indices[ i ]; - copyVector3sArray: function (vectors) { + array[ offset ++ ] = index.a; + array[ offset ++ ] = index.b; + array[ offset ++ ] = index.c; - var array = this.array, offset = 0; + } - for (var i = 0, l = vectors.length; i < l; i++) { + return this; - var vector = vectors[i]; + }, - if (vector === undefined) { + copyVector2sArray: function ( vectors ) { - console.warn('THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i); - vector = new THREE.Vector3(); + var array = this.array, offset = 0; - } + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - array[offset++] = vector.x; - array[offset++] = vector.y; - array[offset++] = vector.z; + var vector = vectors[ i ]; - } + if ( vector === undefined ) { - return this; + console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); + vector = new THREE.Vector2(); - }, + } - set: function (value, offset) { + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; - if (offset === undefined) offset = 0; + } - this.array.set(value, offset); + return this; - return this; + }, - }, + copyVector3sArray: function ( vectors ) { - setX: function (index, x) { + var array = this.array, offset = 0; - this.array[index * this.itemSize] = x; + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - return this; + var vector = vectors[ i ]; - }, + if ( vector === undefined ) { - setY: function (index, y) { + console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); + vector = new THREE.Vector3(); - this.array[index * this.itemSize + 1] = y; + } - return this; + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; - }, + } - setZ: function (index, z) { + return this; - this.array[index * this.itemSize + 2] = z; + }, - return this; + copyVector4sArray: function ( vectors ) { - }, + var array = this.array, offset = 0; - setW: function (index, w) { + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - this.array[index * this.itemSize + 3] = w; + var vector = vectors[ i ]; - return this; + if ( vector === undefined ) { - }, + console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); + vector = new THREE.Vector4(); - getX: function (index) { + } - return this.array[index * this.itemSize]; + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; + array[ offset ++ ] = vector.w; - }, + } - getY: function (index) { + return this; - return this.array[index * this.itemSize + 1]; + }, - }, + set: function ( value, offset ) { - getZ: function (index) { + if ( offset === undefined ) offset = 0; - return this.array[index * this.itemSize + 2]; + this.array.set( value, offset ); - }, + return this; - getW: function (index) { + }, - return this.array[index * this.itemSize + 3]; + getX: function ( index ) { - }, + return this.array[ index * this.itemSize ]; - setXY: function (index, x, y) { + }, - index *= this.itemSize; + setX: function ( index, x ) { - this.array[index + 0] = x; - this.array[index + 1] = y; + this.array[ index * this.itemSize ] = x; - return this; + return this; - }, + }, - setXYZ: function (index, x, y, z) { + getY: function ( index ) { - index *= this.itemSize; + return this.array[ index * this.itemSize + 1 ]; - this.array[index + 0] = x; - this.array[index + 1] = y; - this.array[index + 2] = z; + }, - return this; + setY: function ( index, y ) { - }, + this.array[ index * this.itemSize + 1 ] = y; - setXYZW: function (index, x, y, z, w) { + return this; - index *= this.itemSize; + }, - this.array[index + 0] = x; - this.array[index + 1] = y; - this.array[index + 2] = z; - this.array[index + 3] = w; + getZ: function ( index ) { - return this; + return this.array[ index * this.itemSize + 2 ]; - }, + }, - clone: function () { + setZ: function ( index, z ) { - return new THREE.BufferAttribute(new this.array.constructor(this.array), this.itemSize); + this.array[ index * this.itemSize + 2 ] = z; - } + return this; -}; + }, -// + getW: function ( index ) { -THREE.Int8Attribute = function (data, itemSize) { + return this.array[ index * this.itemSize + 3 ]; - THREE.warn('THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + }, -}; + setW: function ( index, w ) { + + this.array[ index * this.itemSize + 3 ] = w; + + return this; + + }, + + setXY: function ( index, x, y ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + + return this; + + }, + + setXYZ: function ( index, x, y, z ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + + return this; -THREE.Uint8Attribute = function (data, itemSize) { + }, - THREE.warn('THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + setXYZW: function ( index, x, y, z, w ) { + + index *= this.itemSize; + + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + } }; -THREE.Uint8ClampedAttribute = function (data, itemSize) { +// - THREE.warn('THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); +THREE.Int8Attribute = function ( array, itemSize ) { + return new THREE.BufferAttribute( new Int8Array( array ), itemSize ); }; -THREE.Int16Attribute = function (data, itemSize) { +THREE.Uint8Attribute = function ( array, itemSize ) { - THREE.warn('THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Uint8Array( array ), itemSize ); }; -THREE.Uint16Attribute = function (data, itemSize) { +THREE.Uint8ClampedAttribute = function ( array, itemSize ) { - THREE.warn('THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Uint8ClampedArray( array ), itemSize ); }; -THREE.Int32Attribute = function (data, itemSize) { +THREE.Int16Attribute = function ( array, itemSize ) { - THREE.warn('THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Int16Array( array ), itemSize ); }; -THREE.Uint32Attribute = function (data, itemSize) { +THREE.Uint16Attribute = function ( array, itemSize ) { - THREE.warn('THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Uint16Array( array ), itemSize ); }; -THREE.Float32Attribute = function (data, itemSize) { +THREE.Int32Attribute = function ( array, itemSize ) { - THREE.warn('THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Int32Array( array ), itemSize ); }; -THREE.Float64Attribute = function (data, itemSize) { +THREE.Uint32Attribute = function ( array, itemSize ) { - THREE.warn('THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.'); - return new THREE.BufferAttribute(data, itemSize); + return new THREE.BufferAttribute( new Uint32Array( array ), itemSize ); }; -// File:src/core/DynamicBufferAttribute.js +THREE.Float32Attribute = function ( array, itemSize ) { -/** - * @author benaadams / https://twitter.com/ben_a_adams - * @author mrdoob / http://mrdoob.com/ - */ + return new THREE.BufferAttribute( new Float32Array( array ), itemSize ); -THREE.DynamicBufferAttribute = function (array, itemSize) { +}; - THREE.BufferAttribute.call(this, array, itemSize); +THREE.Float64Attribute = function ( array, itemSize ) { - this.updateRange = {offset: 0, count: -1}; + return new THREE.BufferAttribute( new Float64Array( array ), itemSize ); }; -THREE.DynamicBufferAttribute.prototype = Object.create(THREE.BufferAttribute.prototype); -THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; -THREE.DynamicBufferAttribute.prototype.clone = function () { +// Deprecated + +THREE.DynamicBufferAttribute = function ( array, itemSize ) { - return new THREE.DynamicBufferAttribute(new this.array.constructor(this.array), this.itemSize); + console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); + return new THREE.BufferAttribute( array, itemSize ).setDynamic( true ); }; @@ -8898,21 +8973,24 @@ THREE.DynamicBufferAttribute.prototype.clone = function () { * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.InstancedBufferAttribute = function (array, itemSize, meshPerAttribute, dynamic) { +THREE.InstancedBufferAttribute = function ( array, itemSize, meshPerAttribute ) { - THREE.DynamicBufferAttribute.call(this, array, itemSize); + THREE.BufferAttribute.call( this, array, itemSize ); - this.dynamic = dynamic || false; - this.meshPerAttribute = meshPerAttribute || 1; + this.meshPerAttribute = meshPerAttribute || 1; }; -THREE.InstancedBufferAttribute.prototype = Object.create(THREE.DynamicBufferAttribute.prototype); +THREE.InstancedBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); THREE.InstancedBufferAttribute.prototype.constructor = THREE.InstancedBufferAttribute; -THREE.InstancedBufferAttribute.prototype.clone = function () { +THREE.InstancedBufferAttribute.prototype.copy = function ( source ) { + + THREE.BufferAttribute.prototype.copy.call( this, source ); + + this.meshPerAttribute = source.meshPerAttribute; - return new THREE.InstancedBufferAttribute(new this.array.constructor(this.array), this.itemSize, this.meshPerAttribute, this.dynamic); + return this; }; @@ -8922,58 +9000,88 @@ THREE.InstancedBufferAttribute.prototype.clone = function () { * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.InterleavedBuffer = function (array, stride, dynamic) { +THREE.InterleavedBuffer = function ( array, stride ) { - this.array = array; - this.stride = stride; + this.uuid = THREE.Math.generateUUID(); - this.needsUpdate = false; + this.array = array; + this.stride = stride; - this.dynamic = dynamic || false; - this.updateRange = {offset: 0, count: -1}; + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; + + this.version = 0; }; THREE.InterleavedBuffer.prototype = { - constructor: THREE.InterleavedBuffer, + constructor: THREE.InterleavedBuffer, - get length() { + get length () { - return this.array.length; + return this.array.length; - }, + }, - copyAt: function (index1, attribute, index2) { + get count () { - index1 *= this.stride; - index2 *= attribute.stride; + return this.array.length / this.stride; - for (var i = 0, l = this.stride; i < l; i++) { + }, - this.array[index1 + i] = attribute.array[index2 + i]; + set needsUpdate( value ) { - } + if ( value === true ) this.version ++; - return this; + }, - }, + setDynamic: function ( value ) { - set: function (value, offset) { + this.dynamic = value; - if (offset === undefined) offset = 0; + return this; - this.array.set(value, offset); + }, - return this; + copy: function ( source ) { - }, + this.array = new source.array.constructor( source.array ); + this.stride = source.stride; + this.dynamic = source.dynamic; - clone: function () { + }, - return new THREE.InterleavedBuffer(new this.array.constructor(this.array), this.stride, this.dynamic); + copyAt: function ( index1, attribute, index2 ) { - } + index1 *= this.stride; + index2 *= attribute.stride; + + for ( var i = 0, l = this.stride; i < l; i ++ ) { + + this.array[ index1 + i ] = attribute.array[ index2 + i ]; + + } + + return this; + + }, + + set: function ( value, offset ) { + + if ( offset === undefined ) offset = 0; + + this.array.set( value, offset ); + + return this; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + } }; @@ -8983,20 +9091,24 @@ THREE.InterleavedBuffer.prototype = { * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.InstancedInterleavedBuffer = function (array, stride, dynamic, meshPerAttribute) { +THREE.InstancedInterleavedBuffer = function ( array, stride, meshPerAttribute ) { - THREE.InterleavedBuffer.call(this, array, stride, dynamic); + THREE.InterleavedBuffer.call( this, array, stride ); - this.meshPerAttribute = meshPerAttribute || 1; + this.meshPerAttribute = meshPerAttribute || 1; }; -THREE.InstancedInterleavedBuffer.prototype = Object.create(THREE.InterleavedBuffer.prototype); +THREE.InstancedInterleavedBuffer.prototype = Object.create( THREE.InterleavedBuffer.prototype ); THREE.InstancedInterleavedBuffer.prototype.constructor = THREE.InstancedInterleavedBuffer; -THREE.InstancedInterleavedBuffer.prototype.clone = function () { +THREE.InstancedInterleavedBuffer.prototype.copy = function ( source ) { + + THREE.InterleavedBuffer.prototype.copy.call( this, source ); - return new THREE.InstancedInterleavedBuffer(new this.array.constructor(this.array), this.stride, this.dynamic, this.meshPerAttribute); + this.meshPerAttribute = source.meshPerAttribute; + + return this; }; @@ -9006,116 +9118,125 @@ THREE.InstancedInterleavedBuffer.prototype.clone = function () { * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.InterleavedBufferAttribute = function (interleavedBuffer, itemSize, offset) { +THREE.InterleavedBufferAttribute = function ( interleavedBuffer, itemSize, offset ) { + + this.uuid = THREE.Math.generateUUID(); - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; }; THREE.InterleavedBufferAttribute.prototype = { - constructor: THREE.InterleavedBufferAttribute, + constructor: THREE.InterleavedBufferAttribute, - get length() { + get length() { - return this.itemSize * this.data.array.length / this.data.stride; + console.warn( 'THREE.BufferAttribute: .length has been deprecated. Please use .count.' ); + return this.array.length; - }, + }, - setX: function (index, x) { + get count() { - this.data.array[index * this.data.stride + this.offset] = x; + return this.data.array.length / this.data.stride; - return this; + }, - }, + setX: function ( index, x ) { - setY: function (index, y) { + this.data.array[ index * this.data.stride + this.offset ] = x; - this.data.array[index * this.data.stride + this.offset + 1] = y; + return this; - return this; + }, - }, + setY: function ( index, y ) { - setZ: function (index, z) { + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - this.data.array[index * this.data.stride + this.offset + 2] = z; + return this; - return this; + }, - }, + setZ: function ( index, z ) { - setW: function (index, w) { + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - this.data.array[index * this.data.stride + this.offset + 3] = w; + return this; - return this; + }, - }, + setW: function ( index, w ) { - getX: function (index) { + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - return this.data.array[index * this.data.stride + this.offset]; + return this; - }, + }, - getY: function (index) { + getX: function ( index ) { - return this.data.array[index * this.data.stride + this.offset + 1]; + return this.data.array[ index * this.data.stride + this.offset ]; - }, + }, - getZ: function (index) { + getY: function ( index ) { - return this.data.array[index * this.data.stride + this.offset + 2]; + return this.data.array[ index * this.data.stride + this.offset + 1 ]; - }, + }, - getW: function (index) { + getZ: function ( index ) { - return this.data.array[index * this.data.stride + this.offset + 3]; + return this.data.array[ index * this.data.stride + this.offset + 2 ]; - }, + }, - setXY: function (index, x, y) { + getW: function ( index ) { - index = index * this.data.stride + this.offset; + return this.data.array[ index * this.data.stride + this.offset + 3 ]; - this.data.array[index + 0] = x; - this.data.array[index + 1] = y; + }, - return this; + setXY: function ( index, x, y ) { - }, + index = index * this.data.stride + this.offset; - setXYZ: function (index, x, y, z) { + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; - index = index * this.data.stride + this.offset; + return this; - this.data.array[index + 0] = x; - this.data.array[index + 1] = y; - this.data.array[index + 2] = z; + }, - return this; + setXYZ: function ( index, x, y, z ) { - }, + index = index * this.data.stride + this.offset; - setXYZW: function (index, x, y, z, w) { + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; - index = index * this.data.stride + this.offset; + return this; - this.data.array[index + 0] = x; - this.data.array[index + 1] = y; - this.data.array[index + 2] = z; - this.data.array[index + 3] = w; + }, - return this; + setXYZW: function ( index, x, y, z, w ) { - } + index = index * this.data.stride + this.offset; + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; + + return this; + + } }; @@ -9127,5650 +9248,7820 @@ THREE.InterleavedBufferAttribute.prototype = { * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author zz85 / http://www.lab4games.net/zz85/blog - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ THREE.Geometry = function () { - Object.defineProperty(this, 'id', {value: THREE.GeometryIdCount++}); - - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - this.type = 'Geometry'; + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; + this.uuid = THREE.Math.generateUUID(); - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; + this.name = ''; + this.type = 'Geometry'; - this.skinWeights = []; - this.skinIndices = []; + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [ [] ]; - this.lineDistances = []; + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; - this.boundingBox = null; - this.boundingSphere = null; + this.skinWeights = []; + this.skinIndices = []; - this.hasTangents = false; + this.lineDistances = []; - // update flags + this.boundingBox = null; + this.boundingSphere = null; - this.verticesNeedUpdate = false; - this.elementsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.tangentsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; + // update flags - this.groupsNeedUpdate = false; + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + this.groupsNeedUpdate = false; }; THREE.Geometry.prototype = { - constructor: THREE.Geometry, + constructor: THREE.Geometry, - applyMatrix: function (matrix) { + applyMatrix: function ( matrix ) { - var normalMatrix = new THREE.Matrix3().getNormalMatrix(matrix); + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - for (var i = 0, il = this.vertices.length; i < il; i++) { + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - var vertex = this.vertices[i]; - vertex.applyMatrix4(matrix); + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); - } + } - for (var i = 0, il = this.faces.length; i < il; i++) { + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - var face = this.faces[i]; - face.normal.applyMatrix3(normalMatrix).normalize(); + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); - for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) { + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - face.vertexNormals[j].applyMatrix3(normalMatrix).normalize(); + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - } + } - } + } - if (this.boundingBox !== null) { + if ( this.boundingBox !== null ) { - this.computeBoundingBox(); + this.computeBoundingBox(); - } + } - if (this.boundingSphere !== null) { + if ( this.boundingSphere !== null ) { - this.computeBoundingSphere(); + this.computeBoundingSphere(); - } + } - this.verticesNeedUpdate = true; - this.normalsNeedUpdate = true; + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; - }, + }, - fromBufferGeometry: function (geometry) { + rotateX: function () { - var scope = this; + // rotate geometry around world x-axis - var attributes = geometry.attributes; + var m1; - 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; + return function rotateX( angle ) { - var tempNormals = []; - var tempUVs = []; + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - for (var i = 0, j = 0; i < vertices.length; i += 3, j += 2) { + m1.makeRotationX( angle ); - scope.vertices.push(new THREE.Vector3(vertices[i], vertices[i + 1], vertices[i + 2])); + this.applyMatrix( m1 ); - if (normals !== undefined) { + return this; - tempNormals.push(new THREE.Vector3(normals[i], normals[i + 1], normals[i + 2])); + }; - } + }(), - if (colors !== undefined) { + rotateY: function () { - scope.colors.push(new THREE.Color(colors[i], colors[i + 1], colors[i + 2])); + // rotate geometry around world y-axis - } + var m1; - if (uvs !== undefined) { + return function rotateY( angle ) { - tempUVs.push(new THREE.Vector2(uvs[j], uvs[j + 1])); + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - } + m1.makeRotationY( angle ); - } + this.applyMatrix( m1 ); - var addFace = function (a, b, c) { + return this; - 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) { + rotateZ: function () { - scope.faceVertexUvs[0].push([tempUVs[a].clone(), tempUVs[b].clone(), tempUVs[c].clone()]); + // rotate geometry around world z-axis - } + var m1; - }; + return function rotateZ( angle ) { - if (indices !== undefined) { + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - var drawcalls = geometry.drawcalls; + m1.makeRotationZ( angle ); - if (drawcalls.length > 0) { + this.applyMatrix( m1 ); - for (var i = 0; i < drawcalls.length; i++) { + return this; - var drawcall = drawcalls[i]; + }; - var start = drawcall.start; - var count = drawcall.count; - var index = drawcall.index; + }(), - for (var j = start, jl = start + count; j < jl; j += 3) { + translate: function () { - addFace(index + indices[j], index + indices[j + 1], index + indices[j + 2]); + // translate geometry - } + var m1; - } + return function translate( x, y, z ) { - } else { + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - for (var i = 0; i < indices.length; i += 3) { + m1.makeTranslation( x, y, z ); - addFace(indices[i], indices[i + 1], indices[i + 2]); + this.applyMatrix( m1 ); - } + return this; - } + }; - } else { + }(), - for (var i = 0; i < vertices.length / 3; i += 3) { + scale: function () { - addFace(i, i + 1, i + 2); + // scale geometry - } + var m1; - } + return function scale( x, y, z ) { - this.computeFaceNormals(); + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - if (geometry.boundingBox !== null) { + m1.makeScale( x, y, z ); - this.boundingBox = geometry.boundingBox.clone(); + this.applyMatrix( m1 ); - } + return this; - if (geometry.boundingSphere !== null) { + }; - this.boundingSphere = geometry.boundingSphere.clone(); + }(), - } + lookAt: function () { - return this; + var obj; - }, + return function lookAt( vector ) { - center: function () { + if ( obj === undefined ) obj = new THREE.Object3D(); - this.computeBoundingBox(); + obj.lookAt( vector ); - var offset = this.boundingBox.center().negate(); + obj.updateMatrix(); - this.applyMatrix(new THREE.Matrix4().setPosition(offset)); + this.applyMatrix( obj.matrix ); - return offset; + }; - }, + }(), - computeFaceNormals: function () { + fromBufferGeometry: function ( geometry ) { - var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + var scope = this; - for (var f = 0, fl = this.faces.length; f < fl; f++) { + var indices = geometry.index !== null ? geometry.index.array : undefined; + var attributes = geometry.attributes; - var face = this.faces[f]; + var vertices = attributes.position.array; + 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 uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; - var vA = this.vertices[face.a]; - var vB = this.vertices[face.b]; - var vC = this.vertices[face.c]; + if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; - cb.subVectors(vC, vB); - ab.subVectors(vA, vB); - cb.cross(ab); + var tempNormals = []; + var tempUVs = []; + var tempUVs2 = []; - cb.normalize(); + for ( var i = 0, j = 0, k = 0; i < vertices.length; i += 3, j += 2, k += 4 ) { - face.normal.copy(cb); + scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - } + if ( normals !== undefined ) { - }, + tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); - computeVertexNormals: function (areaWeighted) { + } - var v, vl, f, fl, face, vertices; + if ( colors !== undefined ) { - vertices = new Array(this.vertices.length); + scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); - for (v = 0, vl = this.vertices.length; v < vl; v++) { + } - vertices[v] = new THREE.Vector3(); + if ( uvs !== undefined ) { - } + tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) ); - if (areaWeighted) { + } - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm + if ( uvs2 !== undefined ) { - var vA, vB, vC; - var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + tempUVs2.push( new THREE.Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); - for (f = 0, fl = this.faces.length; f < fl; f++) { + } - face = this.faces[f]; + } - vA = this.vertices[face.a]; - vB = this.vertices[face.b]; - vC = this.vertices[face.c]; + function addFace( a, b, c ) { - cb.subVectors(vC, vB); - ab.subVectors(vA, vB); - cb.cross(ab); + 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() ] : []; - vertices[face.a].add(cb); - vertices[face.b].add(cb); - vertices[face.c].add(cb); + var face = new THREE.Face3( a, b, c, vertexNormals, vertexColors ); - } + scope.faces.push( face ); - } else { + if ( uvs !== undefined ) { - for (f = 0, fl = this.faces.length; f < fl; f++) { + scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - face = this.faces[f]; + } - vertices[face.a].add(face.normal); - vertices[face.b].add(face.normal); - vertices[face.c].add(face.normal); + if ( uvs2 !== undefined ) { - } + scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); - } + } - for (v = 0, vl = this.vertices.length; v < vl; v++) { + }; - vertices[v].normalize(); + if ( indices !== undefined ) { - } + var groups = geometry.groups; - for (f = 0, fl = this.faces.length; f < fl; f++) { + if ( groups.length > 0 ) { - face = this.faces[f]; + for ( var i = 0; i < groups.length; i ++ ) { - face.vertexNormals[0] = vertices[face.a].clone(); - face.vertexNormals[1] = vertices[face.b].clone(); - face.vertexNormals[2] = vertices[face.c].clone(); + var group = groups[ i ]; - } + var start = group.start; + var count = group.count; - }, + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - computeMorphNormals: function () { + addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ] ); - var i, il, f, fl, face; + } - // 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++) { + } else { - face = this.faces[f]; + for ( var i = 0; i < indices.length; i += 3 ) { - if (!face.__originalFaceNormal) { + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - face.__originalFaceNormal = face.normal.clone(); + } - } else { + } - face.__originalFaceNormal.copy(face.normal); + } else { - } + for ( var i = 0; i < vertices.length / 3; i += 3 ) { - if (!face.__originalVertexNormals) face.__originalVertexNormals = []; + addFace( i, i + 1, i + 2 ); - for (i = 0, il = face.vertexNormals.length; i < il; i++) { + } - if (!face.__originalVertexNormals[i]) { + } - face.__originalVertexNormals[i] = face.vertexNormals[i].clone(); + this.computeFaceNormals(); - } else { + if ( geometry.boundingBox !== null ) { - face.__originalVertexNormals[i].copy(face.vertexNormals[i]); + this.boundingBox = geometry.boundingBox.clone(); - } + } - } + if ( geometry.boundingSphere !== null ) { - } + this.boundingSphere = geometry.boundingSphere.clone(); - // use temp geometry to compute face and vertex normals for each morph + } - var tmpGeo = new THREE.Geometry(); - tmpGeo.faces = this.faces; + return this; - for (i = 0, il = this.morphTargets.length; i < il; i++) { + }, - // create on first access + center: function () { - if (!this.morphNormals[i]) { + this.computeBoundingBox(); - this.morphNormals[i] = {}; - this.morphNormals[i].faceNormals = []; - this.morphNormals[i].vertexNormals = []; + var offset = this.boundingBox.center().negate(); - var dstNormalsFace = this.morphNormals[i].faceNormals; - var dstNormalsVertex = this.morphNormals[i].vertexNormals; + this.translate( offset.x, offset.y, offset.z ); - var faceNormal, vertexNormals; + return offset; - for (f = 0, fl = this.faces.length; f < fl; f++) { + }, - faceNormal = new THREE.Vector3(); - vertexNormals = {a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3()}; + normalize: function () { - dstNormalsFace.push(faceNormal); - dstNormalsVertex.push(vertexNormals); + this.computeBoundingSphere(); - } + var center = this.boundingSphere.center; + var radius = this.boundingSphere.radius; - } + var s = radius === 0 ? 1 : 1.0 / radius; - var morphNormals = this.morphNormals[i]; + var matrix = new THREE.Matrix4(); + matrix.set( + s, 0, 0, - s * center.x, + 0, s, 0, - s * center.y, + 0, 0, s, - s * center.z, + 0, 0, 0, 1 + ); - // set vertices to morph target + this.applyMatrix( matrix ); - tmpGeo.vertices = this.morphTargets[i].vertices; + return this; - // compute morph normals + }, - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); + computeFaceNormals: function () { - // store morph normals + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - var faceNormal, vertexNormals; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - for (f = 0, fl = this.faces.length; f < fl; f++) { + var face = this.faces[ f ]; - face = this.faces[f]; + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; - faceNormal = morphNormals.faceNormals[f]; - vertexNormals = morphNormals.vertexNormals[f]; + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - faceNormal.copy(face.normal); + cb.normalize(); - vertexNormals.a.copy(face.vertexNormals[0]); - vertexNormals.b.copy(face.vertexNormals[1]); - vertexNormals.c.copy(face.vertexNormals[2]); + face.normal.copy( cb ); - } + } - } + }, - // restore original normals + computeVertexNormals: function ( areaWeighted ) { - for (f = 0, fl = this.faces.length; f < fl; f++) { + var v, vl, f, fl, face, vertices; - face = this.faces[f]; + vertices = new Array( this.vertices.length ); - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - } + vertices[ v ] = new THREE.Vector3(); - }, + } - computeTangents: function () { + if ( areaWeighted ) { - // based on http://www.terathon.com/code/tangent.html - // tangents go to vertices + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm - 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; + var vA, vB, vC; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - for (v = 0, vl = this.vertices.length; v < vl; v++) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - tan1[v] = new THREE.Vector3(); - tan2[v] = new THREE.Vector3(); + face = this.faces[ f ]; - } + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; - function handleTriangle(context, a, b, c, ua, ub, uc) { + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - vA = context.vertices[a]; - vB = context.vertices[b]; - vC = context.vertices[c]; + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); - uvA = uv[ua]; - uvB = uv[ub]; - uvC = uv[uc]; + } - 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; + } else { - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - 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); + face = this.faces[ f ]; - tan1[a].add(sdir); - tan1[b].add(sdir); - tan1[c].add(sdir); + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); - tan2[a].add(tdir); - tan2[b].add(tdir); - tan2[c].add(tdir); + } - } + } - for (f = 0, fl = this.faces.length; f < fl; f++) { + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - face = this.faces[f]; - uv = this.faceVertexUvs[0][f]; // use UV layer 0 for tangents + vertices[ v ].normalize(); - handleTriangle(this, face.a, face.b, face.c, 0, 1, 2); + } - } + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - var faceIndex = ['a', 'b', 'c', 'd']; + face = this.faces[ f ]; - for (f = 0, fl = this.faces.length; f < fl; f++) { + var vertexNormals = face.vertexNormals; - face = this.faces[f]; + if ( vertexNormals.length === 3 ) { - for (i = 0; i < Math.min(face.vertexNormals.length, 3); i++) { + vertexNormals[ 0 ].copy( vertices[ face.a ] ); + vertexNormals[ 1 ].copy( vertices[ face.b ] ); + vertexNormals[ 2 ].copy( vertices[ face.c ] ); - n.copy(face.vertexNormals[i]); + } else { - vertexIndex = face[faceIndex[i]]; + vertexNormals[ 0 ] = vertices[ face.a ].clone(); + vertexNormals[ 1 ] = vertices[ face.b ].clone(); + vertexNormals[ 2 ] = vertices[ face.c ].clone(); - t = tan1[vertexIndex]; + } - // Gram-Schmidt orthogonalize + } - tmp.copy(t); - tmp.sub(n.multiplyScalar(n.dot(t))).normalize(); + }, - // Calculate handedness + computeMorphNormals: function () { - tmp2.crossVectors(face.vertexNormals[i], t); - test = tmp2.dot(tan2[vertexIndex]); - w = ( test < 0.0 ) ? -1.0 : 1.0; + var i, il, f, fl, face; - face.vertexTangents[i] = new THREE.Vector4(tmp.x, tmp.y, tmp.z, w); + // 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 ]; - this.hasTangents = true; + if ( ! face.__originalFaceNormal ) { - }, + face.__originalFaceNormal = face.normal.clone(); - computeLineDistances: function () { + } else { - var d = 0; - var vertices = this.vertices; + face.__originalFaceNormal.copy( face.normal ); - for (var i = 0, il = vertices.length; i < il; i++) { + } - if (i > 0) { + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - d += vertices[i].distanceTo(vertices[i - 1]); + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - } + if ( ! face.__originalVertexNormals[ i ] ) { - this.lineDistances[i] = d; + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - } + } else { - }, + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - computeBoundingBox: function () { + } - if (this.boundingBox === null) { + } - this.boundingBox = new THREE.Box3(); + } - } + // use temp geometry to compute face and vertex normals for each morph - this.boundingBox.setFromPoints(this.vertices); + var tmpGeo = new THREE.Geometry(); + tmpGeo.faces = this.faces; - }, + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - computeBoundingSphere: function () { + // create on first access - if (this.boundingSphere === null) { + if ( ! this.morphNormals[ i ] ) { - this.boundingSphere = new THREE.Sphere(); + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; - } + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - this.boundingSphere.setFromPoints(this.vertices); + var faceNormal, vertexNormals; - }, + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - merge: function (geometry, matrix) { + faceNormal = new THREE.Vector3(); + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; - if (geometry instanceof THREE.Geometry === false) { + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); - 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]; + var morphNormals = this.morphNormals[ i ]; - if (matrix !== undefined) { + // set vertices to morph target - normalMatrix = new THREE.Matrix3().getNormalMatrix(matrix); + tmpGeo.vertices = this.morphTargets[ i ].vertices; - } + // compute morph normals - // vertices + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); - for (var i = 0, il = vertices2.length; i < il; i++) { + // store morph normals - var vertex = vertices2[i]; + var faceNormal, vertexNormals; - var vertexCopy = vertex.clone(); + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - if (matrix !== undefined) vertexCopy.applyMatrix4(matrix); + face = this.faces[ f ]; - vertices1.push(vertexCopy); + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; - } + faceNormal.copy( face.normal ); - // faces + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); - for (i = 0, il = faces2.length; i < il; i++) { + } - var face = faces2[i], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + } - faceCopy = new THREE.Face3(face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset); - faceCopy.normal.copy(face.normal); + // restore original normals - if (normalMatrix !== undefined) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - faceCopy.normal.applyMatrix3(normalMatrix).normalize(); + face = this.faces[ f ]; - } + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; - for (var j = 0, jl = faceVertexNormals.length; j < jl; j++) { + } - normal = faceVertexNormals[j].clone(); + }, - if (normalMatrix !== undefined) { + computeTangents: function () { - normal.applyMatrix3(normalMatrix).normalize(); + console.warn( 'THREE.Geometry: .computeTangents() has been removed.' ); - } + }, - faceCopy.vertexNormals.push(normal); + computeLineDistances: function () { - } + var d = 0; + var vertices = this.vertices; - faceCopy.color.copy(face.color); + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - for (var j = 0, jl = faceVertexColors.length; j < jl; j++) { + if ( i > 0 ) { - color = faceVertexColors[j]; - faceCopy.vertexColors.push(color.clone()); + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); - } + } - faces1.push(faceCopy); + this.lineDistances[ i ] = d; - } + } - // uvs + }, - for (i = 0, il = uvs2.length; i < il; i++) { + computeBoundingBox: function () { - var uv = uvs2[i], uvCopy = []; + if ( this.boundingBox === null ) { - if (uv === undefined) { + this.boundingBox = new THREE.Box3(); - continue; + } - } + this.boundingBox.setFromPoints( this.vertices ); - for (var j = 0, jl = uv.length; j < jl; j++) { + }, - uvCopy.push(uv[j].clone()); + computeBoundingSphere: function () { - } + if ( this.boundingSphere === null ) { - uvs1.push(uvCopy); + this.boundingSphere = new THREE.Sphere(); - } + } - }, + this.boundingSphere.setFromPoints( this.vertices ); - mergeMesh: function (mesh) { + }, - if (mesh instanceof THREE.Mesh === false) { + merge: function ( geometry, matrix, materialIndexOffset ) { - THREE.error('THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh); - return; + if ( geometry instanceof THREE.Geometry === false ) { - } + console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; - mesh.matrixAutoUpdate && mesh.updateMatrix(); + } - this.merge(mesh.geometry, mesh.matrix); + 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 ]; - }, + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ + if ( matrix !== undefined ) { - mergeVertices: function () { + normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) - var unique = [], changes = []; + } - 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; + // vertices - for (i = 0, il = this.vertices.length; i < il; i++) { + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - v = this.vertices[i]; - key = Math.round(v.x * precision) + '_' + Math.round(v.y * precision) + '_' + Math.round(v.z * precision); + var vertex = vertices2[ i ]; - if (verticesMap[key] === undefined) { + var vertexCopy = vertex.clone(); - verticesMap[key] = i; - unique.push(this.vertices[i]); - changes[i] = unique.length - 1; + if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); - } else { + vertices1.push( vertexCopy ); - //THREE.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[i] = changes[verticesMap[key]]; + } - } + // faces - } + for ( i = 0, il = faces2.length; i < il; i ++ ) { + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; + faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); - for (i = 0, il = this.faces.length; i < il; i++) { + if ( normalMatrix !== undefined ) { - face = this.faces[i]; + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - face.a = changes[face.a]; - face.b = changes[face.b]; - face.c = changes[face.c]; + } - indices = [face.a, face.b, face.c]; + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - var dupIndex = -1; + normal = faceVertexNormals[ j ].clone(); - // 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]) { + if ( normalMatrix !== undefined ) { - dupIndex = n; - faceIndicesToRemove.push(i); - break; + normal.applyMatrix3( normalMatrix ).normalize(); - } - } + } - } + faceCopy.vertexNormals.push( normal ); - for (i = faceIndicesToRemove.length - 1; i >= 0; i--) { - var idx = faceIndicesToRemove[i]; + } - this.faces.splice(idx, 1); + faceCopy.color.copy( face.color ); - for (j = 0, jl = this.faceVertexUvs.length; j < jl; j++) { + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { - this.faceVertexUvs[j].splice(idx, 1); + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); - } + } - } + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - // Use unique set of vertices + faces1.push( faceCopy ); - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; + } - }, + // uvs - toJSON: function () { + for ( i = 0, il = uvs2.length; i < il; i ++ ) { - // we will store all serialization data on 'data' - var data = {}; + var uv = uvs2[ i ], uvCopy = []; - // add metadata - data.metadata = { - version: 4.4, - type: 'Geometry', - generator: 'Geometry.toJSON' - }; + if ( uv === undefined ) { - // standard Geometry serialization + continue; - data.type = this.type; - data.uuid = this.uuid; - if (this.name !== '') data.name = this.name; + } - if (this.parameters !== undefined) { + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - var parameters = this.parameters; + uvCopy.push( uv[ j ].clone() ); - for (var key in parameters) { + } - if (parameters[key] !== undefined) data[key] = parameters[key]; + uvs1.push( uvCopy ); - } + } - return data; + }, - } + mergeMesh: function ( mesh ) { - var vertices = []; + if ( mesh instanceof THREE.Mesh === false ) { - for (var i = 0; i < this.vertices.length; i++) { + console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; - var vertex = this.vertices[i]; - vertices.push(vertex.x, vertex.y, vertex.z); + } - } + mesh.matrixAutoUpdate && mesh.updateMatrix(); - var faces = []; - var normals = []; - var normalsHash = {}; - var colors = []; - var colorsHash = {}; - var uvs = []; - var uvsHash = {}; + this.merge( mesh.geometry, mesh.matrix ); - for (var i = 0; i < this.faces.length; i++) { + }, - var face = this.faces[i]; + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ - 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; + mergeVertices: function () { - var faceType = 0; + var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) + var unique = [], changes = []; - 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); + var v, key; + var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i, il, face; + var indices, j, jl; - faces.push(faceType); - faces.push(face.a, face.b, face.c); + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { - if (hasFaceVertexUv) { + v = this.vertices[ i ]; + key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); - var faceVertexUvs = this.faceVertexUvs[0][i]; + if ( verticesMap[ key ] === undefined ) { - faces.push( - getUvIndex(faceVertexUvs[0]), - getUvIndex(faceVertexUvs[1]), - getUvIndex(faceVertexUvs[2]) - ); + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; - } + } else { - if (hasFaceNormal) { + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; - faces.push(getNormalIndex(face.normal)); + } - } + } - if (hasFaceVertexNormal) { - var vertexNormals = face.vertexNormals; + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; - faces.push( - getNormalIndex(vertexNormals[0]), - getNormalIndex(vertexNormals[1]), - getNormalIndex(vertexNormals[2]) - ); + for ( i = 0, il = this.faces.length; i < il; i ++ ) { - } + face = this.faces[ i ]; - if (hasFaceColor) { + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; - faces.push(getColorIndex(face.color)); + indices = [ face.a, face.b, face.c ]; - } + var dupIndex = - 1; - if (hasFaceVertexColor) { + // 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 ++ ) { - var vertexColors = face.vertexColors; + if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { - faces.push( - getColorIndex(vertexColors[0]), - getColorIndex(vertexColors[1]), - getColorIndex(vertexColors[2]) - ); + dupIndex = n; + faceIndicesToRemove.push( i ); + break; - } + } - } + } - function setBit(value, position, enabled) { + } - return enabled ? value | ( 1 << position ) : value & ( ~( 1 << position) ); + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - } + var idx = faceIndicesToRemove[ i ]; - function getNormalIndex(normal) { + this.faces.splice( idx, 1 ); - var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - if (normalsHash[hash] !== undefined) { + this.faceVertexUvs[ j ].splice( idx, 1 ); - return normalsHash[hash]; + } - } + } - normalsHash[hash] = normals.length / 3; - normals.push(normal.x, normal.y, normal.z); + // Use unique set of vertices - return normalsHash[hash]; + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; - } + }, - function getColorIndex(color) { + sortFacesByMaterialIndex: function () { - var hash = color.r.toString() + color.g.toString() + color.b.toString(); + function materialIndexSort( a, b ) { - if (colorsHash[hash] !== undefined) { + return a.materialIndex - b.materialIndex; - return colorsHash[hash]; + } - } + this.faces.sort( materialIndexSort ); - colorsHash[hash] = colors.length; - colors.push(color.getHex()); + }, - return colorsHash[hash]; + toJSON: function () { - } + var data = { + metadata: { + version: 4.4, + type: 'Geometry', + generator: 'Geometry.toJSON' + } + }; - function getUvIndex(uv) { + // standard Geometry serialization - var hash = uv.x.toString() + uv.y.toString(); + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; - if (uvsHash[hash] !== undefined) { + if ( this.parameters !== undefined ) { - return uvsHash[hash]; + var parameters = this.parameters; - } + for ( var key in parameters ) { - uvsHash[hash] = uvs.length / 2; - uvs.push(uv.x, uv.y); + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - return uvsHash[hash]; + } - } + return data; - data.data = {}; + } - data.data.vertices = vertices; - data.data.normals = normals; - if (colors.length > 0) data.data.colors = colors; - if (uvs.length > 0) data.data.uvs = [uvs]; // temporal backward compatibility - data.data.faces = faces; + var vertices = []; - return data; + for ( var i = 0; i < this.vertices.length; i ++ ) { - }, + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - clone: function () { + } - var geometry = new THREE.Geometry(); + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; - var vertices = this.vertices; + for ( var i = 0; i < this.faces.length; i ++ ) { - for (var i = 0, il = vertices.length; i < il; i++) { + var face = this.faces[ i ]; - geometry.vertices.push(vertices[i].clone()); + 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; - } + var faceType = 0; - var faces = this.faces; + 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 ); - for (var i = 0, il = faces.length; i < il; i++) { + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); - geometry.faces.push(faces[i].clone()); + if ( hasFaceVertexUv ) { - } + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; - for (var i = 0, il = this.faceVertexUvs.length; i < il; i++) { + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); - var faceVertexUvs = this.faceVertexUvs[i]; + } - if (geometry.faceVertexUvs[i] === undefined) { + if ( hasFaceNormal ) { - geometry.faceVertexUvs[i] = []; + faces.push( getNormalIndex( face.normal ) ); - } + } - for (var j = 0, jl = faceVertexUvs.length; j < jl; j++) { + if ( hasFaceVertexNormal ) { - var uvs = faceVertexUvs[j], uvsCopy = []; + var vertexNormals = face.vertexNormals; - for (var k = 0, kl = uvs.length; k < kl; k++) { + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); - var uv = uvs[k]; + } - uvsCopy.push(uv.clone()); + if ( hasFaceColor ) { - } + faces.push( getColorIndex( face.color ) ); - geometry.faceVertexUvs[i].push(uvsCopy); + } - } + if ( hasFaceVertexColor ) { - } + var vertexColors = face.vertexColors; - return geometry; + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); - }, + } - dispose: function () { + } - this.dispatchEvent({type: 'dispose'}); + function setBit( value, position, enabled ) { - } + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); -}; + } -THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype); + function getNormalIndex( normal ) { -THREE.GeometryIdCount = 0; + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); -// File:src/core/DynamicGeometry.js + if ( normalsHash[ hash ] !== undefined ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + return normalsHash[ hash ]; -THREE.DynamicGeometry = function () { + } - Object.defineProperty(this, 'id', {value: THREE.GeometryIdCount++}); + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); - this.uuid = THREE.Math.generateUUID(); + return normalsHash[ hash ]; - this.name = ''; - this.type = 'DynamicGeometry'; + } - this.vertices = []; - this.colors = []; - this.normals = []; - this.colors = []; - this.uvs = []; - this.faces = []; + function getColorIndex( color ) { - /* + var hash = color.r.toString() + color.g.toString() + color.b.toString(); - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; + if ( colorsHash[ hash ] !== undefined ) { - this.skinWeights = []; - this.skinIndices = []; + return colorsHash[ hash ]; - this.lineDistances = []; + } - */ + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); - this.boundingBox = null; - this.boundingSphere = null; + return colorsHash[ hash ]; - // update flags + } - this.verticesNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.uvsNeedUpdate = false; + function getUvIndex( uv ) { -}; + var hash = uv.x.toString() + uv.y.toString(); -THREE.DynamicGeometry.prototype = { + if ( uvsHash[ hash ] !== undefined ) { - constructor: THREE.DynamicGeometry, + return uvsHash[ hash ]; - computeBoundingBox: THREE.Geometry.prototype.computeBoundingBox, - computeBoundingSphere: THREE.Geometry.prototype.computeBoundingSphere, + } - computeFaceNormals: function () { + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); - THREE.warn('THREE.DynamicGeometry: computeFaceNormals() is not a method of this type of geometry.'); - return this; + return uvsHash[ hash ]; - }, + } - computeVertexNormals: function () { + data.data = {}; - THREE.warn('THREE.DynamicGeometry: computeVertexNormals () is not a method of this type of geometry.'); - return this; + data.data.vertices = vertices; + data.data.normals = normals; + if ( colors.length > 0 ) data.data.colors = colors; + if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility + data.data.faces = faces; - }, + return data; - fromGeometry: function (geometry) { + }, - this.vertices = geometry.vertices; - this.faces = geometry.faces; + clone: function () { - var faces = geometry.faces; - var faceVertexUvs = geometry.faceVertexUvs[0]; + return new this.constructor().copy( this ); - for (var i = 0, il = faces.length; i < il; i++) { + }, - var face = faces[i]; - var indices = [face.a, face.b, face.c]; + copy: function ( source ) { - var vertexNormals = face.vertexNormals; - var vertexColors = face.vertexColors; - var vertexUvs = faceVertexUvs[i]; + this.vertices = []; + this.faces = []; + this.faceVertexUvs = [ [] ]; - for (var j = 0, jl = vertexNormals.length; j < jl; j++) { + var vertices = source.vertices; - this.normals[indices[j]] = vertexNormals[j]; + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - } + this.vertices.push( vertices[ i ].clone() ); - for (var j = 0, jl = vertexColors.length; j < jl; j++) { + } - this.colors[indices[j]] = vertexColors[j]; + var faces = source.faces; - } + for ( var i = 0, il = faces.length; i < il; i ++ ) { - for (var j = 0, jl = vertexUvs.length; j < jl; j++) { + this.faces.push( faces[ i ].clone() ); - this.uvs[indices[j]] = vertexUvs[j]; + } - } + for ( var i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { - } + var faceVertexUvs = source.faceVertexUvs[ i ]; - return this; + if ( this.faceVertexUvs[ i ] === undefined ) { - }, + this.faceVertexUvs[ i ] = []; - dispose: function () { + } - this.dispatchEvent({type: 'dispose'}); + for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - } + var uvs = faceVertexUvs[ j ], uvsCopy = []; -}; - -THREE.EventDispatcher.prototype.apply(THREE.DynamicGeometry.prototype); + for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { -// File:src/core/BufferGeometry.js + var uv = uvs[ k ]; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + uvsCopy.push( uv.clone() ); -THREE.BufferGeometry = function () { + } - Object.defineProperty(this, 'id', {value: THREE.GeometryIdCount++}); + this.faceVertexUvs[ i ].push( uvsCopy ); - this.uuid = THREE.Math.generateUUID(); + } - this.name = ''; - this.type = 'BufferGeometry'; + } - this.attributes = {}; - this.attributesKeys = []; + return this; - this.drawcalls = []; - this.offsets = this.drawcalls; // backwards compatibility + }, - this.boundingBox = null; - this.boundingSphere = null; + dispose: function () { -}; + this.dispatchEvent( { type: 'dispose' } ); -THREE.BufferGeometry.prototype = { + } - constructor: THREE.BufferGeometry, +}; - addAttribute: function (name, attribute) { +THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - if (attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false) { +THREE.GeometryIdCount = 0; - THREE.warn('THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).'); +// File:src/core/DirectGeometry.js - this.attributes[name] = {array: arguments[1], itemSize: arguments[2]}; +/** + * @author mrdoob / http://mrdoob.com/ + */ - return; +THREE.DirectGeometry = function () { - } + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - this.attributes[name] = attribute; - this.attributesKeys = Object.keys(this.attributes); + this.uuid = THREE.Math.generateUUID(); - }, + this.name = ''; + this.type = 'DirectGeometry'; - getAttribute: function (name) { + this.indices = []; + this.vertices = []; + this.normals = []; + this.colors = []; + this.uvs = []; + this.uvs2 = []; - return this.attributes[name]; + this.groups = []; - }, + this.morphTargets = {}; - addDrawCall: function (start, count, indexOffset) { + this.skinWeights = []; + this.skinIndices = []; - this.drawcalls.push({ + // this.lineDistances = []; - start: start, - count: count, - index: indexOffset !== undefined ? indexOffset : 0 + this.boundingBox = null; + this.boundingSphere = null; - }); + // update flags - }, + this.verticesNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.groupsNeedUpdate = false; - applyMatrix: function (matrix) { +}; - var position = this.attributes.position; +THREE.DirectGeometry.prototype = { - if (position !== undefined) { + constructor: THREE.DirectGeometry, - matrix.applyToBuffer(position); - position.needsUpdate = true; + computeBoundingBox: THREE.Geometry.prototype.computeBoundingBox, + computeBoundingSphere: THREE.Geometry.prototype.computeBoundingSphere, - } + computeFaceNormals: function () { - var normal = this.attributes.normal; + console.warn( 'THREE.DirectGeometry: computeFaceNormals() is not a method of this type of geometry.' ); - if (normal !== undefined) { + }, - var normalMatrix = new THREE.Matrix3().getNormalMatrix(matrix); + computeVertexNormals: function () { - normalMatrix.applyToBuffer(normal); - normal.needsUpdate = true; + console.warn( 'THREE.DirectGeometry: computeVertexNormals() is not a method of this type of geometry.' ); - } + }, - if (this.boundingBox !== null) { + computeGroups: function ( geometry ) { - this.computeBoundingBox(); + var group; + var groups = []; + var materialIndex; - } + var faces = geometry.faces; - if (this.boundingSphere !== null) { + for ( var i = 0; i < faces.length; i ++ ) { - this.computeBoundingSphere(); + var face = faces[ i ]; - } + // materials - }, + if ( face.materialIndex !== materialIndex ) { - center: function () { + materialIndex = face.materialIndex; - this.computeBoundingBox(); + if ( group !== undefined ) { - var offset = this.boundingBox.center().negate(); + group.count = ( i * 3 ) - group.start; + groups.push( group ); - this.applyMatrix(new THREE.Matrix4().setPosition(offset)); + } - return offset; + group = { + start: i * 3, + materialIndex: materialIndex + }; - }, + } - setFromObject: function (object) { + } - console.log('THREE.BufferGeometry.setFromObject(). Converting ', object, this); + if ( group !== undefined ) { - var geometry = object.geometry; - var material = object.material; + group.count = ( i * 3 ) - group.start; + groups.push( group ); - if (object instanceof THREE.PointCloud || object instanceof THREE.Line) { + } - var positions = new Float32Array(geometry.vertices.length * 3); - var colors = new Float32Array(geometry.colors.length * 3); + this.groups = groups; - this.addAttribute('position', new THREE.BufferAttribute(positions, 3).copyVector3sArray(geometry.vertices)); - this.addAttribute('color', new THREE.BufferAttribute(colors, 3).copyColorsArray(geometry.colors)); - this.computeBoundingSphere(); + }, - } else if (object instanceof THREE.Mesh) { + fromGeometry: function ( geometry ) { - if (geometry instanceof THREE.DynamicGeometry) { + var faces = geometry.faces; + var vertices = geometry.vertices; + var faceVertexUvs = geometry.faceVertexUvs; - this.fromDynamicGeometry(geometry); + var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; - } else if (geometry instanceof THREE.Geometry) { + // morphs - this.fromGeometry(geometry, material); + var morphTargets = geometry.morphTargets; + var morphTargetsLength = morphTargets.length; - } + if ( morphTargetsLength > 0 ) { - } + var morphTargetsPosition = []; - if (material.attributes !== undefined) { + for ( var i = 0; i < morphTargetsLength; i ++ ) { - var attributes = material.attributes; + morphTargetsPosition[ i ] = []; - for (var name in attributes) { + } - var attribute = attributes[name]; + this.morphTargets.position = morphTargetsPosition; - var type = attribute.type; - var array = attribute.value; + } - switch (type) { + var morphNormals = geometry.morphNormals; + var morphNormalsLength = morphNormals.length; - case "f": - var floats = new Float32Array(array.length); - this.addAttribute(name, new THREE.BufferAttribute(floats, 1).copyArray(array)); - break; + if ( morphNormalsLength > 0 ) { - case "c": - var colors = new Float32Array(array.length * 3); - this.addAttribute(name, new THREE.BufferAttribute(colors, 3).copyColorsArray(array)); - break; + var morphTargetsNormal = []; - case "v3": - var colors = new Float32Array(array.length * 3); - this.addAttribute(name, new THREE.BufferAttribute(colors, 3).copyVector3sArray(array)); - break; + for ( var i = 0; i < morphNormalsLength; i ++ ) { - default: - console.warn('THREE.BufferGeometry.setFromObject(). TODO: attribute unsupported', type); - break; + morphTargetsNormal[ i ] = []; - } + } - } + this.morphTargets.normal = morphTargetsNormal; - } + } - return this; + // skins - }, + var skinIndices = geometry.skinIndices; + var skinWeights = geometry.skinWeights; - updateFromObject: function (object) { + var hasSkinIndices = skinIndices.length === vertices.length; + var hasSkinWeights = skinWeights.length === vertices.length; - var geometry = object.geometry; + // - if (geometry.verticesNeedUpdate === true) { + for ( var i = 0; i < faces.length; i ++ ) { - var attribute = this.attributes.position; + var face = faces[ i ]; - if (attribute !== undefined) { + this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); - attribute.copyVector3sArray(geometry.vertices); - attribute.needsUpdate = true; + var vertexNormals = face.vertexNormals; - } + if ( vertexNormals.length === 3 ) { - geometry.verticesNeedUpdate = false; + this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); - } + } else { - if (geometry.colorsNeedUpdate === true) { + var normal = face.normal; - var attribute = this.attributes.color; + this.normals.push( normal, normal, normal ); - if (attribute !== undefined) { + } - attribute.copyColorsArray(geometry.colors); - attribute.needsUpdate = true; + var vertexColors = face.vertexColors; - } + if ( vertexColors.length === 3 ) { - geometry.colorsNeedUpdate = false; + this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); - } + } else { - }, + var color = face.color; - updateFromMaterial: function (material) { + this.colors.push( color, color, color ); - if (material.attributes !== undefined) { + } - var attributes = material.attributes; + if ( hasFaceVertexUv === true ) { - for (var name in attributes) { + var vertexUvs = faceVertexUvs[ 0 ][ i ]; - var attribute = attributes[name]; + if ( vertexUvs !== undefined ) { - var type = attribute.type; - var array = attribute.value; + this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - switch (type) { + } else { - case "f": - this.attributes[name].copyArray(array); - this.attributes[name].needsUpdate = true; - break; + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); - case "c": - this.attributes[name].copyColorsArray(array); - this.attributes[name].needsUpdate = true; - break; + this.uvs.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ); - case "v3": - this.attributes[name].copyVector3sArray(array); - this.attributes[name].needsUpdate = true; - break; + } - } + } - } + if ( hasFaceVertexUv2 === true ) { - } + var vertexUvs = faceVertexUvs[ 1 ][ i ]; - }, + if ( vertexUvs !== undefined ) { - fromGeometry: function (geometry, material) { + this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - material = material || {'vertexColors': THREE.NoColors}; + } else { - var vertices = geometry.vertices; - var faces = geometry.faces; - var faceVertexUvs = geometry.faceVertexUvs; - var vertexColors = material.vertexColors; + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); - var hasFaceVertexUv = faceVertexUvs[0].length > 0; - var hasFaceVertexUv2 = faceVertexUvs[1] && faceVertexUvs[1].length > 0; + this.uvs2.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ); - var hasFaceVertexNormals = faces[0] && faces[0].vertexNormals.length == 3; + } - var positions = new Float32Array(faces.length * 3 * 3); - this.addAttribute('position', new THREE.BufferAttribute(positions, 3)); + } - var normals = new Float32Array(faces.length * 3 * 3); - this.addAttribute('normal', new THREE.BufferAttribute(normals, 3)); + // morphs - if (vertexColors !== THREE.NoColors) { + for ( var j = 0; j < morphTargetsLength; j ++ ) { - var colors = new Float32Array(faces.length * 3 * 3); - this.addAttribute('color', new THREE.BufferAttribute(colors, 3)); + var morphTarget = morphTargets[ j ].vertices; - } + morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); - if (hasFaceVertexUv === true) { + } - var uvs = new Float32Array(faces.length * 3 * 2); - this.addAttribute('uv', new THREE.BufferAttribute(uvs, 2)); + for ( var j = 0; j < morphNormalsLength; j ++ ) { - } + var morphNormal = morphNormals[ j ].vertexNormals[ i ]; - if (hasFaceVertexUv2 === true) { + morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); - var uvs2 = new Float32Array(faces.length * 3 * 2); - this.addAttribute('uv2', new THREE.BufferAttribute(uvs2, 2)); + } - } + // skins - for (var i = 0, i2 = 0, i3 = 0; i < faces.length; i++, i2 += 6, i3 += 9) { + if ( hasSkinIndices ) { - var face = faces[i]; + this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); - var a = vertices[face.a]; - var b = vertices[face.b]; - var c = vertices[face.c]; + } - positions[i3] = a.x; - positions[i3 + 1] = a.y; - positions[i3 + 2] = a.z; + if ( hasSkinWeights ) { - positions[i3 + 3] = b.x; - positions[i3 + 4] = b.y; - positions[i3 + 5] = b.z; + this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); - positions[i3 + 6] = c.x; - positions[i3 + 7] = c.y; - positions[i3 + 8] = c.z; + } - if (hasFaceVertexNormals === true) { + } - var na = face.vertexNormals[0]; - var nb = face.vertexNormals[1]; - var nc = face.vertexNormals[2]; + this.computeGroups( geometry ); - normals[i3] = na.x; - normals[i3 + 1] = na.y; - normals[i3 + 2] = na.z; + this.verticesNeedUpdate = geometry.verticesNeedUpdate; + this.normalsNeedUpdate = geometry.normalsNeedUpdate; + this.colorsNeedUpdate = geometry.colorsNeedUpdate; + this.uvsNeedUpdate = geometry.uvsNeedUpdate; + this.groupsNeedUpdate = geometry.groupsNeedUpdate; - normals[i3 + 3] = nb.x; - normals[i3 + 4] = nb.y; - normals[i3 + 5] = nb.z; + return this; - normals[i3 + 6] = nc.x; - normals[i3 + 7] = nc.y; - normals[i3 + 8] = nc.z; + }, - } else { + dispose: function () { - var n = face.normal; + this.dispatchEvent( { type: 'dispose' } ); - normals[i3] = n.x; - normals[i3 + 1] = n.y; - normals[i3 + 2] = n.z; + } - normals[i3 + 3] = n.x; - normals[i3 + 4] = n.y; - normals[i3 + 5] = n.z; +}; - normals[i3 + 6] = n.x; - normals[i3 + 7] = n.y; - normals[i3 + 8] = n.z; +THREE.EventDispatcher.prototype.apply( THREE.DirectGeometry.prototype ); - } +// File:src/core/BufferGeometry.js - if (vertexColors === THREE.FaceColors) { +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - var fc = face.color; +THREE.BufferGeometry = function () { - colors[i3] = fc.r; - colors[i3 + 1] = fc.g; - colors[i3 + 2] = fc.b; + Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); - colors[i3 + 3] = fc.r; - colors[i3 + 4] = fc.g; - colors[i3 + 5] = fc.b; + this.uuid = THREE.Math.generateUUID(); - colors[i3 + 6] = fc.r; - colors[i3 + 7] = fc.g; - colors[i3 + 8] = fc.b; + this.name = ''; + this.type = 'BufferGeometry'; - } else if (vertexColors === THREE.VertexColors) { + this.index = null; + this.attributes = {}; - var vca = face.vertexColors[0]; - var vcb = face.vertexColors[1]; - var vcc = face.vertexColors[2]; + this.morphAttributes = {}; - colors[i3] = vca.r; - colors[i3 + 1] = vca.g; - colors[i3 + 2] = vca.b; + this.groups = []; - colors[i3 + 3] = vcb.r; - colors[i3 + 4] = vcb.g; - colors[i3 + 5] = vcb.b; + this.boundingBox = null; + this.boundingSphere = null; - colors[i3 + 6] = vcc.r; - colors[i3 + 7] = vcc.g; - colors[i3 + 8] = vcc.b; + this.drawRange = { start: 0, count: Infinity }; - } +}; - if (hasFaceVertexUv === true) { +THREE.BufferGeometry.prototype = { - var uva = faceVertexUvs[0][i][0]; - var uvb = faceVertexUvs[0][i][1]; - var uvc = faceVertexUvs[0][i][2]; + constructor: THREE.BufferGeometry, - uvs[i2] = uva.x; - uvs[i2 + 1] = uva.y; + addIndex: function ( index ) { - uvs[i2 + 2] = uvb.x; - uvs[i2 + 3] = uvb.y; + console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); + this.setIndex( index ); - uvs[i2 + 4] = uvc.x; - uvs[i2 + 5] = uvc.y; + }, - } + getIndex: function () { - if (hasFaceVertexUv2 === true) { + return this.index; - var uva = faceVertexUvs[1][i][0]; - var uvb = faceVertexUvs[1][i][1]; - var uvc = faceVertexUvs[1][i][2]; + }, - uvs2[i2] = uva.x; - uvs2[i2 + 1] = uva.y; + setIndex: function ( index ) { - uvs2[i2 + 2] = uvb.x; - uvs2[i2 + 3] = uvb.y; + this.index = index; - uvs2[i2 + 4] = uvc.x; - uvs2[i2 + 5] = uvc.y; + }, - } + addAttribute: function ( name, attribute ) { - } + if ( attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false ) { - this.computeBoundingSphere(); + console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - return this; + this.addAttribute( name, new THREE.BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); - }, + return; - fromDynamicGeometry: function (geometry) { + } - var indices = new Uint16Array(geometry.faces.length * 3); - this.addAttribute('index', new THREE.BufferAttribute(indices, 1).copyFacesArray(geometry.faces)); + if ( name === 'index' ) { - var positions = new Float32Array(geometry.vertices.length * 3); - this.addAttribute('position', new THREE.BufferAttribute(positions, 3).copyVector3sArray(geometry.vertices)); + console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); + this.setIndex( attribute ); - var normals = new Float32Array(geometry.normals.length * 3); - this.addAttribute('normal', new THREE.BufferAttribute(normals, 3).copyVector3sArray(geometry.normals)); + return; - var colors = new Float32Array(geometry.colors.length * 3); - this.addAttribute('color', new THREE.BufferAttribute(colors, 3).copyVector3sArray(geometry.colors)); + } - var uvs = new Float32Array(geometry.uvs.length * 2); - this.addAttribute('uv', new THREE.BufferAttribute(uvs, 2).copyVector2sArray(geometry.uvs)); + this.attributes[ name ] = attribute; - this.computeBoundingSphere(); + }, - return this; + getAttribute: function ( name ) { - }, + return this.attributes[ name ]; - computeBoundingBox: function () { + }, - var vector = new THREE.Vector3(); + removeAttribute: function ( name ) { - return function () { + delete this.attributes[ name ]; - if (this.boundingBox === null) { + }, - this.boundingBox = new THREE.Box3(); + get drawcalls() { - } + console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); + return this.groups; - var positions = this.attributes.position; + }, - if (positions) { + get offsets() { - var bb = this.boundingBox; - bb.makeEmpty(); + console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); + return this.groups; - for (var i = 0, il = positions.length / positions.itemSize; i < il; i++) { + }, - vector.set(positions.getX(i), positions.getY(i), positions.getZ(i)); - bb.expandByPoint(vector); + addDrawCall: function ( start, count, indexOffset ) { - } + if ( indexOffset !== undefined ) { - } + console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); - if (positions === undefined || positions.length === 0) { + } - this.boundingBox.min.set(0, 0, 0); - this.boundingBox.max.set(0, 0, 0); + console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); + this.addGroup( start, count ); - } + }, - if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) { + clearDrawCalls: function () { - THREE.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.'); + console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); + this.clearGroups(); - } + }, - } + addGroup: function ( start, count, materialIndex ) { - }(), + this.groups.push( { - computeBoundingSphere: function () { + start: start, + count: count, + materialIndex: materialIndex !== undefined ? materialIndex : 0 - var box = new THREE.Box3(); - var vector = new THREE.Vector3(); + } ); - return function () { + }, - if (this.boundingSphere === null) { + clearGroups: function () { - this.boundingSphere = new THREE.Sphere(); + this.groups = []; - } + }, - var positions = this.attributes.position; + setDrawRange: function ( start, count ) { - if (positions) { + this.drawRange.start = start; + this.drawRange.count = count; - box.makeEmpty(); + }, - var center = this.boundingSphere.center; + applyMatrix: function ( matrix ) { - for (var i = 0, il = positions.length / positions.itemSize; i < il; i++) { + var position = this.attributes.position; - vector.set(positions.getX(i), positions.getY(i), positions.getZ(i)); - box.expandByPoint(vector); + if ( position !== undefined ) { - } + matrix.applyToVector3Array( position.array ); + position.needsUpdate = true; - 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 + var normal = this.attributes.normal; - var maxRadiusSq = 0; + if ( normal !== undefined ) { - for (var i = 0, il = positions.length / positions.itemSize; i < il; i++) { + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - vector.set(positions.getX(i), positions.getY(i), positions.getZ(i)); - maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector)); + normalMatrix.applyToVector3Array( normal.array ); + normal.needsUpdate = true; - } + } - this.boundingSphere.radius = Math.sqrt(maxRadiusSq); + if ( this.boundingBox !== null ) { - if (isNaN(this.boundingSphere.radius)) { + this.computeBoundingBox(); - THREE.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.'); + } - } + if ( this.boundingSphere !== null ) { - } + this.computeBoundingSphere(); - } + } - }(), + }, - computeFaceNormals: function () { + rotateX: function () { - // backwards compatibility + // rotate geometry around world x-axis - }, + var m1; - computeVertexNormals: function () { + return function rotateX( angle ) { - var attributes = this.attributes; + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - if (attributes.position) { + m1.makeRotationX( angle ); - var positions = attributes.position.array; + this.applyMatrix( m1 ); - if (attributes.normal === undefined) { + return this; - this.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(positions.length), 3)); + }; - } else { + }(), - // reset existing normals to zero + rotateY: function () { - var normals = attributes.normal.array; + // rotate geometry around world y-axis - for (var i = 0, il = normals.length; i < il; i++) { + var m1; - normals[i] = 0; + return function rotateY( angle ) { - } + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - } + m1.makeRotationY( angle ); - var normals = attributes.normal.array; + this.applyMatrix( m1 ); - var vA, vB, vC, + return this; - pA = new THREE.Vector3(), - pB = new THREE.Vector3(), - pC = new THREE.Vector3(), + }; - cb = new THREE.Vector3(), - ab = new THREE.Vector3(); + }(), - // indexed elements + rotateZ: function () { - if (attributes.index) { + // rotate geometry around world z-axis - var indices = attributes.index.array; + var m1; - var offsets = ( this.offsets.length > 0 ? this.offsets : [{ - start: 0, - count: indices.length, - index: 0 - }] ); + return function rotateZ( angle ) { - for (var j = 0, jl = offsets.length; j < jl; ++j) { + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - var start = offsets[j].start; - var count = offsets[j].count; - var index = offsets[j].index; + m1.makeRotationZ( angle ); - for (var i = start, il = start + count; i < il; i += 3) { + this.applyMatrix( m1 ); - vA = ( index + indices[i] ) * 3; - vB = ( index + indices[i + 1] ) * 3; - vC = ( index + indices[i + 2] ) * 3; + return this; - 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; + translate: function () { - normals[vB] += cb.x; - normals[vB + 1] += cb.y; - normals[vB + 2] += cb.z; + // translate geometry - normals[vC] += cb.x; - normals[vC + 1] += cb.y; - normals[vC + 2] += cb.z; + var m1; - } + return function translate( x, y, z ) { - } + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - } else { + m1.makeTranslation( x, y, z ); - // non-indexed elements (unconnected triangle soup) + this.applyMatrix( m1 ); - for (var i = 0, il = positions.length; i < il; i += 9) { + return this; - pA.fromArray(positions, i); - pB.fromArray(positions, i + 3); - pC.fromArray(positions, i + 6); + }; - 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; + scale: function () { - normals[i + 3] = cb.x; - normals[i + 4] = cb.y; - normals[i + 5] = cb.z; + // scale geometry - normals[i + 6] = cb.x; - normals[i + 7] = cb.y; - normals[i + 8] = cb.z; + var m1; - } + return function scale( x, y, z ) { - } + if ( m1 === undefined ) m1 = new THREE.Matrix4(); - this.normalizeNormals(); + m1.makeScale( x, y, z ); - attributes.normal.needsUpdate = true; + this.applyMatrix( m1 ); - } + return this; - }, + }; - computeTangents: function () { + }(), - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) + lookAt: function () { - if (this.attributes.index === undefined || - this.attributes.position === undefined || - this.attributes.normal === undefined || - this.attributes.uv === undefined) { + var obj; - THREE.warn('THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()'); - return; + return function lookAt( vector ) { - } + if ( obj === undefined ) obj = new THREE.Object3D(); - var indices = this.attributes.index.array; - var positions = this.attributes.position.array; - var normals = this.attributes.normal.array; - var uvs = this.attributes.uv.array; + obj.lookAt( vector ); - var nVertices = positions.length / 3; + obj.updateMatrix(); - if (this.attributes.tangent === undefined) { + this.applyMatrix( obj.matrix ); - this.addAttribute('tangent', new THREE.BufferAttribute(new Float32Array(4 * nVertices), 4)); + }; - } + }(), - var tangents = this.attributes.tangent.array; + center: function () { - var tan1 = [], tan2 = []; + this.computeBoundingBox(); - for (var k = 0; k < nVertices; k++) { + var offset = this.boundingBox.center().negate(); - tan1[k] = new THREE.Vector3(); - tan2[k] = new THREE.Vector3(); + this.translate( offset.x, offset.y, offset.z ); - } + return offset; - var vA = new THREE.Vector3(), - vB = new THREE.Vector3(), - vC = new THREE.Vector3(), + }, - uvA = new THREE.Vector2(), - uvB = new THREE.Vector2(), - uvC = new THREE.Vector2(), + setFromObject: function ( object ) { - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r; + // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); - var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + var geometry = object.geometry; - function handleTriangle(a, b, c) { + if ( object instanceof THREE.Points || object instanceof THREE.Line ) { - vA.fromArray(positions, a * 3); - vB.fromArray(positions, b * 3); - vC.fromArray(positions, c * 3); + var positions = new THREE.Float32Attribute( geometry.vertices.length * 3, 3 ); + var colors = new THREE.Float32Attribute( geometry.colors.length * 3, 3 ); - uvA.fromArray(uvs, a * 2); - uvB.fromArray(uvs, b * 2); - uvC.fromArray(uvs, c * 2); + this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); + this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); - x1 = vB.x - vA.x; - x2 = vC.x - vA.x; + if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { - y1 = vB.y - vA.y; - y2 = vC.y - vA.y; + var lineDistances = new THREE.Float32Attribute( geometry.lineDistances.length, 1 ); - z1 = vB.z - vA.z; - z2 = vC.z - vA.z; + this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; + } - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; + if ( geometry.boundingSphere !== null ) { - r = 1.0 / ( s1 * t2 - s2 * t1 ); + this.boundingSphere = geometry.boundingSphere.clone(); - 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 - ); + if ( geometry.boundingBox !== null ) { - tan1[a].add(sdir); - tan1[b].add(sdir); - tan1[c].add(sdir); + this.boundingBox = geometry.boundingBox.clone(); - tan2[a].add(tdir); - tan2[b].add(tdir); - tan2[c].add(tdir); + } - } + } else if ( object instanceof THREE.Mesh ) { - var i, il; - var j, jl; - var iA, iB, iC; + if ( geometry instanceof THREE.Geometry ) { - if (this.drawcalls.length === 0) { + this.fromGeometry( geometry ); - this.addDrawCall(0, indices.length, 0); + } - } + } - var drawcalls = this.drawcalls; + return this; - for (j = 0, jl = drawcalls.length; j < jl; ++j) { + }, - var start = drawcalls[j].start; - var count = drawcalls[j].count; - var index = drawcalls[j].index; + updateFromObject: function ( object ) { - for (i = start, il = start + count; i < il; i += 3) { + var geometry = object.geometry; - iA = index + indices[i]; - iB = index + indices[i + 1]; - iC = index + indices[i + 2]; + if ( object instanceof THREE.Mesh ) { - handleTriangle(iA, iB, iC); + var direct = geometry.__directGeometry; - } + if ( direct === undefined ) { - } + return this.fromGeometry( geometry ); - var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); - var n = new THREE.Vector3(), n2 = new THREE.Vector3(); - var w, t, test; + } - function handleVertex(v) { + direct.verticesNeedUpdate = geometry.verticesNeedUpdate; + direct.normalsNeedUpdate = geometry.normalsNeedUpdate; + direct.colorsNeedUpdate = geometry.colorsNeedUpdate; + direct.uvsNeedUpdate = geometry.uvsNeedUpdate; + direct.groupsNeedUpdate = geometry.groupsNeedUpdate; - n.fromArray(normals, v * 3); - n2.copy(n); + geometry.verticesNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.groupsNeedUpdate = false; - t = tan1[v]; + geometry = direct; - // Gram-Schmidt orthogonalize + } - tmp.copy(t); - tmp.sub(n.multiplyScalar(n.dot(t))).normalize(); + if ( geometry.verticesNeedUpdate === true ) { - // Calculate handedness + var attribute = this.attributes.position; - tmp2.crossVectors(n2, t); - test = tmp2.dot(tan2[v]); - w = ( test < 0.0 ) ? -1.0 : 1.0; + if ( attribute !== undefined ) { - tangents[v * 4] = tmp.x; - tangents[v * 4 + 1] = tmp.y; - tangents[v * 4 + 2] = tmp.z; - tangents[v * 4 + 3] = w; + attribute.copyVector3sArray( geometry.vertices ); + attribute.needsUpdate = true; - } + } - for (j = 0, jl = drawcalls.length; j < jl; ++j) { + geometry.verticesNeedUpdate = false; - var start = drawcalls[j].start; - var count = drawcalls[j].count; - var index = drawcalls[j].index; + } - for (i = start, il = start + count; i < il; i += 3) { + if ( geometry.normalsNeedUpdate === true ) { - iA = index + indices[i]; - iB = index + indices[i + 1]; - iC = index + indices[i + 2]; + var attribute = this.attributes.normal; - handleVertex(iA); - handleVertex(iB); - handleVertex(iC); + if ( attribute !== undefined ) { - } + attribute.copyVector3sArray( geometry.normals ); + attribute.needsUpdate = true; - } + } - }, + geometry.normalsNeedUpdate = false; - /* - 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 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks. - */ - computeOffsets: function (size) { + } - if (size === undefined) size = THREE.BufferGeometry.MaxIndex; + if ( geometry.colorsNeedUpdate === true ) { - var indices = this.attributes.index.array; - var vertices = this.attributes.position.array; + var attribute = this.attributes.color; - var facesCount = ( indices.length / 3 ); + if ( attribute !== undefined ) { - var UintArray = ( ( vertices.length / 3 ) > 65535 && THREE.BufferGeometry.MaxIndex > 65535 ) ? Uint32Array : Uint16Array; + attribute.copyColorsArray( geometry.colors ); + attribute.needsUpdate = true; - /* - THREE.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); - THREE.log("Faces to process: "+(indices.length/3)); - THREE.log("Reordering "+verticesCount+" vertices."); - */ + } - var sortedIndices = new UintArray(indices.length); + geometry.colorsNeedUpdate = false; - var indexPtr = 0; - var vertexPtr = 0; + } - var offsets = [{start: 0, count: 0, index: 0}]; - var offset = offsets[0]; + if ( geometry.lineDistancesNeedUpdate ) { - 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; - } + var attribute = this.attributes.lineDistance; - /* - Traverse every face and reorder vertices in the proper offsets of 65k. - We can have more than 'size' entries in the index buffer per offset, but only reference 'size' values. - */ - for (var findex = 0; findex < facesCount; findex++) { - newVerticeMaps = 0; + if ( attribute !== undefined ) { - 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]; - } - } + attribute.copyArray( geometry.lineDistances ); + attribute.needsUpdate = true; - 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; + } - //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; - } - } + geometry.lineDistancesNeedUpdate = false; - //Reindex the face. - for (var v = 0; v < 6; v += 2) { - var vid = faceVertices[v]; - var new_vid = faceVertices[v + 1]; + } - if (new_vid === -1) - new_vid = vertexPtr++; + if ( geometry.groupsNeedUpdate ) { - vertexMap[vid] = new_vid; - revVertexMap[new_vid] = vid; - sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit - offset.count++; - } - } + geometry.computeGroups( object.geometry ); + this.groups = geometry.groups; - /* 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 orderTime = Date.now(); - THREE.log("Reorder time: "+(orderTime-s)+"ms"); - THREE.log("Duplicated "+duplicatedVertices+" vertices."); - THREE.log("Compute Buffers time: "+(Date.now()-s)+"ms"); - THREE.log("Draw offsets: "+offsets.length); - */ - - return offsets; - - }, - - merge: function (geometry, offset) { - - if (geometry instanceof THREE.BufferGeometry === false) { - - THREE.error('THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry); - return; - - } - - if (offset === undefined) offset = 0; - - var attributes = this.attributes; - - for (var key in attributes) { - - if (geometry.attributes[key] === undefined) continue; - - var attribute1 = attributes[key]; - var attributeArray1 = attribute1.array; - - var attribute2 = geometry.attributes[key]; - var attributeArray2 = attribute2.array; - - var attributeSize = attribute2.itemSize; - - for (var i = 0, j = attributeSize * offset; i < attributeArray2.length; i++, j++) { - - attributeArray1[j] = attributeArray2[i]; - - } + geometry.groupsNeedUpdate = false; - } + } - return this; + return this; - }, + }, - normalizeNormals: function () { + fromGeometry: function ( geometry ) { - var normals = this.attributes.normal.array; + geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry ); - var x, y, z, n; + return this.fromDirectGeometry( geometry.__directGeometry ); - for (var i = 0, il = normals.length; i < il; i += 3) { + }, - x = normals[i]; - y = normals[i + 1]; - z = normals[i + 2]; + fromDirectGeometry: function ( geometry ) { - n = 1.0 / Math.sqrt(x * x + y * y + z * z); + var positions = new Float32Array( geometry.vertices.length * 3 ); + this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); - normals[i] *= n; - normals[i + 1] *= n; - normals[i + 2] *= n; + if ( geometry.normals.length > 0 ) { - } + var normals = new Float32Array( geometry.normals.length * 3 ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); - }, + } - /* - 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) { + if ( geometry.colors.length > 0 ) { - /* 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); - } + var colors = new Float32Array( geometry.colors.length * 3 ); + this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); - /* 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; - } - }, + if ( geometry.uvs.length > 0 ) { - toJSON: function () { + var uvs = new Float32Array( geometry.uvs.length * 2 ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); - // we will store all serialization data on 'data' - var data = {}; + } - // add metadata - data.metadata = { - version: 4.4, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - }; + if ( geometry.uvs2.length > 0 ) { - // standard BufferGeometry serialization + var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); + this.addAttribute( 'uv2', new THREE.BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); - data.type = this.type; - data.uuid = this.uuid; - if (this.name !== '') data.name = this.name; - data.data = {}; - data.data.attributes = {}; + } - var attributes = this.attributes; - var offsets = this.offsets; - var boundingSphere = this.boundingSphere; + if ( geometry.indices.length > 0 ) { - for (var key in attributes) { + var TypeArray = geometry.vertices.length > 65535 ? Uint32Array : Uint16Array; + var indices = new TypeArray( geometry.indices.length * 3 ); + this.setIndex( new THREE.BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); - var attribute = attributes[key]; + } - var array = Array.prototype.slice.call(attribute.array); + // groups - data.data.attributes[key] = { - itemSize: attribute.itemSize, - type: attribute.array.constructor.name, - array: array - } + this.groups = geometry.groups; - } + // morphs - if (offsets.length > 0) { + for ( var name in geometry.morphTargets ) { - data.data.offsets = JSON.parse(JSON.stringify(offsets)); + var array = []; + var morphTargets = geometry.morphTargets[ name ]; - } + for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { - if (boundingSphere !== null) { + var morphTarget = morphTargets[ i ]; - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - } + var attribute = new THREE.Float32Attribute( morphTarget.length * 3, 3 ); - } + array.push( attribute.copyVector3sArray( morphTarget ) ); - return data; + } - }, + this.morphAttributes[ name ] = array; - clone: function () { + } - var geometry = new THREE.BufferGeometry(); + // skinning - for (var attr in this.attributes) { + if ( geometry.skinIndices.length > 0 ) { - var sourceAttr = this.attributes[attr]; - geometry.addAttribute(attr, sourceAttr.clone()); + var skinIndices = new THREE.Float32Attribute( geometry.skinIndices.length * 4, 4 ); + this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); - } + } - for (var i = 0, il = this.offsets.length; i < il; i++) { + if ( geometry.skinWeights.length > 0 ) { - var offset = this.offsets[i]; + var skinWeights = new THREE.Float32Attribute( geometry.skinWeights.length * 4, 4 ); + this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); - geometry.offsets.push({ + } - start: offset.start, - index: offset.index, - count: offset.count + // - }); + if ( geometry.boundingSphere !== null ) { - } + this.boundingSphere = geometry.boundingSphere.clone(); - return geometry; + } - }, + if ( geometry.boundingBox !== null ) { - dispose: function () { + this.boundingBox = geometry.boundingBox.clone(); - this.dispatchEvent({type: 'dispose'}); + } - } + return this; -}; + }, -THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype); + computeBoundingBox: function () { -THREE.BufferGeometry.MaxIndex = 65535; + var vector = new THREE.Vector3(); -// File:src/core/InstancedBufferGeometry.js + return function () { -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ + if ( this.boundingBox === null ) { -THREE.InstancedBufferGeometry = function () { + this.boundingBox = new THREE.Box3(); - THREE.BufferGeometry.call(this); + } - this.type = 'InstancedBufferGeometry'; - this.maxInstancedCount = undefined; + var positions = this.attributes.position.array; -}; + if ( positions ) { -THREE.InstancedBufferGeometry.prototype = Object.create(THREE.BufferGeometry.prototype); -THREE.InstancedBufferGeometry.prototype.constructor = THREE.InstancedBufferGeometry; + var bb = this.boundingBox; + bb.makeEmpty(); -THREE.InstancedBufferGeometry.prototype.addDrawCall = function (start, count, indexOffset, instances) { + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - this.drawcalls.push({ + vector.fromArray( positions, i ); + bb.expandByPoint( vector ); - start: start, - count: count, - index: indexOffset !== undefined ? indexOffset : 0, - instances: instances + } - }); + } -}, + if ( positions === undefined || positions.length === 0 ) { - THREE.InstancedBufferGeometry.prototype.clone = function () { + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); - var geometry = new THREE.InstancedBufferGeometry(); + } - for (var attr in this.attributes) { + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - var sourceAttr = this.attributes[attr]; - geometry.addAttribute(attr, sourceAttr.clone()); + console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - } + } - for (var i = 0, il = this.offsets.length; i < il; i++) { + }; - var offset = this.offsets[i]; + }(), - geometry.offsets.push({ + computeBoundingSphere: function () { - start: offset.start, - index: offset.index, - count: offset.count, - instances: offset.instances + var box = new THREE.Box3(); + var vector = new THREE.Vector3(); - }); + return function () { - } + if ( this.boundingSphere === null ) { - return geometry; + this.boundingSphere = new THREE.Sphere(); - }; + } -THREE.EventDispatcher.prototype.apply(THREE.InstancedBufferGeometry.prototype); + var positions = this.attributes.position.array; -// File:src/cameras/Camera.js + if ( positions ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley - */ + box.makeEmpty(); -THREE.Camera = function () { + var center = this.boundingSphere.center; - THREE.Object3D.call(this); + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - this.type = 'Camera'; + vector.fromArray( positions, i ); + box.expandByPoint( vector ); - this.matrixWorldInverse = new THREE.Matrix4(); - this.projectionMatrix = new THREE.Matrix4(); + } -}; + box.center( center ); -THREE.Camera.prototype = Object.create(THREE.Object3D.prototype); -THREE.Camera.prototype.constructor = THREE.Camera; + // hoping to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case -THREE.Camera.prototype.getWorldDirection = function () { + var maxRadiusSq = 0; - var quaternion = new THREE.Quaternion(); + for ( var i = 0, il = positions.length; i < il; i += 3 ) { - return function (optionalTarget) { + vector.fromArray( positions, i ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - var result = optionalTarget || new THREE.Vector3(); + } - this.getWorldQuaternion(quaternion); + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - return result.set(0, 0, -1).applyQuaternion(quaternion); + if ( isNaN( this.boundingSphere.radius ) ) { - } + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); -}(); + } -THREE.Camera.prototype.lookAt = function () { + } - // This routine does not support cameras with rotated and/or translated parent(s) + }; - var m1 = new THREE.Matrix4(); + }(), - return function (vector) { + computeFaceNormals: function () { - m1.lookAt(this.position, vector, this.up); + // backwards compatibility - this.quaternion.setFromRotationMatrix(m1); + }, - }; + computeVertexNormals: function () { -}(); + var index = this.index; + var attributes = this.attributes; + var groups = this.groups; -THREE.Camera.prototype.clone = function (camera) { + if ( attributes.position ) { - if (camera === undefined) camera = new THREE.Camera(); + var positions = attributes.position.array; - THREE.Object3D.prototype.clone.call(this, camera); + if ( attributes.normal === undefined ) { - camera.matrixWorldInverse.copy(this.matrixWorldInverse); - camera.projectionMatrix.copy(this.projectionMatrix); + this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) ); - return camera; -}; + } else { -// File:src/cameras/CubeCamera.js + // reset existing normals to zero -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ + var normals = attributes.normal.array; -THREE.CubeCamera = function (near, far, cubeResolution) { + for ( var i = 0, il = normals.length; i < il; i ++ ) { - THREE.Object3D.call(this); + normals[ i ] = 0; - this.type = 'CubeCamera'; + } - var fov = 90, aspect = 1; + } - 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 normals = attributes.normal.array; - 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); + var vA, vB, vC, - 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); + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), - 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); + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); - 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); + // indexed elements - 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); + if ( index ) { - this.renderTarget = new THREE.WebGLRenderTargetCube(cubeResolution, cubeResolution, { - format: THREE.RGBFormat, - magFilter: THREE.LinearFilter, - minFilter: THREE.LinearFilter - }); + var indices = index.array; - this.updateCubeMap = function (renderer, scene) { + if ( groups.length === 0 ) { - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.generateMipmaps; + this.addGroup( 0, indices.length ); - renderTarget.generateMipmaps = false; + } - renderTarget.activeCubeFace = 0; - renderer.render(scene, cameraPX, renderTarget); + for ( var j = 0, jl = groups.length; j < jl; ++ j ) { - renderTarget.activeCubeFace = 1; - renderer.render(scene, cameraNX, renderTarget); + var group = groups[ j ]; - renderTarget.activeCubeFace = 2; - renderer.render(scene, cameraPY, renderTarget); + var start = group.start; + var count = group.count; - renderTarget.activeCubeFace = 3; - renderer.render(scene, cameraNY, renderTarget); + for ( var i = start, il = start + count; i < il; i += 3 ) { - renderTarget.activeCubeFace = 4; - renderer.render(scene, cameraPZ, renderTarget); + vA = indices[ i + 0 ] * 3; + vB = indices[ i + 1 ] * 3; + vC = indices[ i + 2 ] * 3; - renderTarget.generateMipmaps = generateMipmaps; + pA.fromArray( positions, vA ); + pB.fromArray( positions, vB ); + pC.fromArray( positions, vC ); - renderTarget.activeCubeFace = 5; - renderer.render(scene, cameraNZ, renderTarget); + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - renderer.setRenderTarget(null); + normals[ vA ] += cb.x; + normals[ vA + 1 ] += cb.y; + normals[ vA + 2 ] += cb.z; - }; + normals[ vB ] += cb.x; + normals[ vB + 1 ] += cb.y; + normals[ vB + 2 ] += cb.z; -}; + normals[ vC ] += cb.x; + normals[ vC + 1 ] += cb.y; + normals[ vC + 2 ] += cb.z; -THREE.CubeCamera.prototype = Object.create(THREE.Object3D.prototype); -THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; + } -// File:src/cameras/OrthographicCamera.js + } -/** - * @author alteredq / http://alteredqualia.com/ - */ + } else { -THREE.OrthographicCamera = function (left, right, top, bottom, near, far) { + // non-indexed elements (unconnected triangle soup) - THREE.Camera.call(this); + for ( var i = 0, il = positions.length; i < il; i += 9 ) { - this.type = 'OrthographicCamera'; + pA.fromArray( positions, i ); + pB.fromArray( positions, i + 3 ); + pC.fromArray( positions, i + 6 ); - this.zoom = 1; + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; - this.updateProjectionMatrix(); + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; -}; + } -THREE.OrthographicCamera.prototype = Object.create(THREE.Camera.prototype); -THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; + } -THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { + this.normalizeNormals(); - 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; + attributes.normal.needsUpdate = true; - this.projectionMatrix.makeOrthographic(cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far); + } -}; + }, -THREE.OrthographicCamera.prototype.clone = function () { + computeTangents: function () { - var camera = new THREE.OrthographicCamera(); + console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); - THREE.Camera.prototype.clone.call(this, camera); + }, - camera.zoom = this.zoom; + computeOffsets: function ( size ) { - camera.left = this.left; - camera.right = this.right; - camera.top = this.top; - camera.bottom = this.bottom; + console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.') - camera.near = this.near; - camera.far = this.far; + }, - camera.projectionMatrix.copy(this.projectionMatrix); + merge: function ( geometry, offset ) { - return camera; -}; + if ( geometry instanceof THREE.BufferGeometry === false ) { -THREE.OrthographicCamera.prototype.toJSON = function (meta) { + console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + } - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; + if ( offset === undefined ) offset = 0; - return data; + var attributes = this.attributes; -}; + for ( var key in attributes ) { -// File:src/cameras/PerspectiveCamera.js + if ( geometry.attributes[ key ] === undefined ) continue; -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; -THREE.PerspectiveCamera = function (fov, aspect, near, far) { + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; - THREE.Camera.call(this); + var attributeSize = attribute2.itemSize; - this.type = 'PerspectiveCamera'; + for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { - this.zoom = 1; + attributeArray1[ j ] = attributeArray2[ i ]; - 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; + } - this.updateProjectionMatrix(); + } -}; + return this; -THREE.PerspectiveCamera.prototype = Object.create(THREE.Camera.prototype); -THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; + }, + normalizeNormals: function () { -/** - * 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 - */ + var normals = this.attributes.normal.array; -THREE.PerspectiveCamera.prototype.setLens = function (focalLength, frameHeight) { + var x, y, z, n; - if (frameHeight === undefined) frameHeight = 24; + for ( var i = 0, il = normals.length; i < il; i += 3 ) { - this.fov = 2 * THREE.Math.radToDeg(Math.atan(frameHeight / ( focalLength * 2 ))); - this.updateProjectionMatrix(); + 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; -/** - * 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. - */ + } -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; + toJSON: function () { - this.updateProjectionMatrix(); + var data = { + metadata: { + version: 4.4, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' + } + }; -}; + // standard BufferGeometry serialization + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; -THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { + if ( this.parameters !== undefined ) { - var fov = THREE.Math.radToDeg(2 * Math.atan(Math.tan(THREE.Math.degToRad(this.fov) * 0.5) / this.zoom)); + var parameters = this.parameters; - if (this.fullWidth) { + for ( var key in parameters ) { - 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); + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - 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 - ); + } - } else { + return data; - this.projectionMatrix.makePerspective(fov, this.aspect, this.near, this.far); + } - } + data.data = { attributes: {} }; -}; + var index = this.index; -THREE.PerspectiveCamera.prototype.clone = function () { + if ( index !== null ) { - var camera = new THREE.PerspectiveCamera(); + var array = Array.prototype.slice.call( index.array ); - THREE.Camera.prototype.clone.call(this, camera); + data.data.index = { + type: index.array.constructor.name, + array: array + }; - camera.zoom = this.zoom; + } - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; + var attributes = this.attributes; - camera.projectionMatrix.copy(this.projectionMatrix); + for ( var key in attributes ) { - return camera; + var attribute = attributes[ key ]; -}; + var array = Array.prototype.slice.call( attribute.array ); -THREE.PerspectiveCamera.prototype.toJSON = function (meta) { + data.data.attributes[ key ] = { + itemSize: attribute.itemSize, + type: attribute.array.constructor.name, + array: array + }; - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + } - data.object.fov = this.fov; - data.object.aspect = this.aspect; - data.object.near = this.near; - data.object.far = this.far; + var groups = this.groups; - return data; + if ( groups.length > 0 ) { -}; + data.data.groups = JSON.parse( JSON.stringify( groups ) ); -// File:src/lights/Light.js + } -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + var boundingSphere = this.boundingSphere; -THREE.Light = function (color) { + if ( boundingSphere !== null ) { - THREE.Object3D.call(this); + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; - this.type = 'Light'; + } - this.color = new THREE.Color(color); + return data; -}; + }, -THREE.Light.prototype = Object.create(THREE.Object3D.prototype); -THREE.Light.prototype.constructor = THREE.Light; + clone: function () { -THREE.Light.prototype.clone = function (light) { + return new this.constructor().copy( this ); - if (light === undefined) light = new THREE.Light(); + }, - THREE.Object3D.prototype.clone.call(this, light); + copy: function ( source ) { - light.color.copy(this.color); + var index = source.index; - return light; + if ( index !== null ) { -}; + this.setIndex( index.clone() ); -// File:src/lights/AmbientLight.js + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + var attributes = source.attributes; -THREE.AmbientLight = function (color) { + for ( var name in attributes ) { - THREE.Light.call(this, color); + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); - this.type = 'AmbientLight'; + } -}; + var groups = source.groups; -THREE.AmbientLight.prototype = Object.create(THREE.Light.prototype); -THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; + for ( var i = 0, l = groups.length; i < l; i ++ ) { -THREE.AmbientLight.prototype.clone = function () { + var group = groups[ i ]; + this.addGroup( group.start, group.count ); - var light = new THREE.AmbientLight(); + } - THREE.Light.prototype.clone.call(this, light); + return this; - return light; + }, -}; + dispose: function () { -THREE.AmbientLight.prototype.toJSON = function (meta) { + this.dispatchEvent( { type: 'dispose' } ); - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + } - data.object.color = this.color.getHex(); +}; - return data; +THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); -}; +THREE.BufferGeometry.MaxIndex = 65535; -// File:src/lights/AreaLight.js +// File:src/core/InstancedBufferGeometry.js /** - * @author MPanknin / http://www.redplant.de/ - * @author alteredq / http://alteredqualia.com/ + * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.AreaLight = function (color, intensity) { - - THREE.Light.call(this, color); +THREE.InstancedBufferGeometry = function () { - this.type = 'AreaLight'; + THREE.BufferGeometry.call( this ); - this.normal = new THREE.Vector3(0, -1, 0); - this.right = new THREE.Vector3(1, 0, 0); + this.type = 'InstancedBufferGeometry'; + this.maxInstancedCount = undefined; - this.intensity = ( intensity !== undefined ) ? intensity : 1; +}; - this.width = 1.0; - this.height = 1.0; +THREE.InstancedBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.InstancedBufferGeometry.prototype.constructor = THREE.InstancedBufferGeometry; - this.constantAttenuation = 1.5; - this.linearAttenuation = 0.5; - this.quadraticAttenuation = 0.1; +THREE.InstancedBufferGeometry.prototype.addGroup = function ( start, count, instances ) { -}; + this.groups.push( { -THREE.AreaLight.prototype = Object.create(THREE.Light.prototype); -THREE.AreaLight.prototype.constructor = THREE.AreaLight; + start: start, + count: count, + instances: instances + } ); -// File:src/lights/DirectionalLight.js +}; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ +THREE.InstancedBufferGeometry.prototype.copy = function ( source ) { -THREE.DirectionalLight = function (color, intensity) { + var index = source.index; - THREE.Light.call(this, color); + if ( index !== null ) { - this.type = 'DirectionalLight'; + this.setIndex( index.clone() ); - this.position.set(0, 1, 0); - this.target = new THREE.Object3D(); + } - this.intensity = ( intensity !== undefined ) ? intensity : 1; + var attributes = source.attributes; - this.castShadow = false; - this.onlyShadow = false; + for ( var name in attributes ) { - // + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; + } - this.shadowCameraLeft = -500; - this.shadowCameraRight = 500; - this.shadowCameraTop = 500; - this.shadowCameraBottom = -500; + var groups = source.groups; - this.shadowCameraVisible = false; + for ( var i = 0, l = groups.length; i < l; i ++ ) { - this.shadowBias = 0; - this.shadowDarkness = 0.5; + var group = groups[ i ]; + this.addGroup( group.start, group.count, group.instances ); - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + } - // + return this; - this.shadowCascade = false; +}; - this.shadowCascadeOffset = new THREE.Vector3(0, 0, -1000); - this.shadowCascadeCount = 2; +THREE.EventDispatcher.prototype.apply( THREE.InstancedBufferGeometry.prototype ); - this.shadowCascadeBias = [0, 0, 0]; - this.shadowCascadeWidth = [512, 512, 512]; - this.shadowCascadeHeight = [512, 512, 512]; +// File:src/animation/AnimationAction.js - this.shadowCascadeNearZ = [-1.000, 0.990, 0.998]; - this.shadowCascadeFarZ = [0.990, 0.998, 1.000]; +/** + * + * A clip that has been explicitly scheduled. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - this.shadowCascadeArray = []; +THREE.AnimationAction = function ( clip, startTime, timeScale, weight, loop ) { - // + if( clip === undefined ) throw new Error( 'clip is null' ); + this.clip = clip; + this.localRoot = null; + this.startTime = startTime || 0; + this.timeScale = timeScale || 1; + this.weight = weight || 1; + this.loop = loop || THREE.LoopRepeat; + this.loopCount = 0; + this.enabled = true; // allow for easy disabling of the action. - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + this.actionTime = - this.startTime; + this.clipTime = 0; + this.propertyBindings = []; }; -THREE.DirectionalLight.prototype = Object.create(THREE.Light.prototype); -THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; +/* +THREE.LoopOnce = 2200; +THREE.LoopRepeat = 2201; +THREE.LoopPingPing = 2202; +*/ -THREE.DirectionalLight.prototype.clone = function () { +THREE.AnimationAction.prototype = { - var light = new THREE.DirectionalLight(); + constructor: THREE.AnimationAction, - THREE.Light.prototype.clone.call(this, light); + setLocalRoot: function( localRoot ) { - light.target = this.target.clone(); + this.localRoot = localRoot; - light.intensity = this.intensity; + return this; + + }, - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + updateTime: function( clipDeltaTime ) { - // + var previousClipTime = this.clipTime; + var previousLoopCount = this.loopCount; + var previousActionTime = this.actionTime; - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; + var duration = this.clip.duration; + + this.actionTime = this.actionTime + clipDeltaTime; + + if( this.loop === THREE.LoopOnce ) { - light.shadowCameraLeft = this.shadowCameraLeft; - light.shadowCameraRight = this.shadowCameraRight; - light.shadowCameraTop = this.shadowCameraTop; - light.shadowCameraBottom = this.shadowCameraBottom; + this.loopCount = 0; + this.clipTime = Math.min( Math.max( this.actionTime, 0 ), duration ); + + // if time is changed since last time, see if we have hit a start/end limit + if( this.clipTime !== previousClipTime ) { - light.shadowCameraVisible = this.shadowCameraVisible; + if( this.clipTime === duration ) { - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; + this.mixer.dispatchEvent( { type: 'finished', action: this, direction: 1 } ); - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; + } + else if( this.clipTime === 0 ) { - // + this.mixer.dispatchEvent( { type: 'finished', action: this, direction: -1 } ); - light.shadowCascade = this.shadowCascade; + } - light.shadowCascadeOffset.copy(this.shadowCascadeOffset); - light.shadowCascadeCount = this.shadowCascadeCount; + } - light.shadowCascadeBias = this.shadowCascadeBias.slice(0); - light.shadowCascadeWidth = this.shadowCascadeWidth.slice(0); - light.shadowCascadeHeight = this.shadowCascadeHeight.slice(0); + + return this.clipTime; - light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice(0); - light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice(0); + } + + this.loopCount = Math.floor( this.actionTime / duration ); + + var newClipTime = this.actionTime - this.loopCount * duration; + newClipTime = newClipTime % duration; + + // if we are ping pong looping, ensure that we go backwards when appropriate + if( this.loop == THREE.LoopPingPong ) { - return light; + if( Math.abs( this.loopCount % 2 ) === 1 ) { -}; + newClipTime = duration - newClipTime; -THREE.DirectionalLight.prototype.toJSON = function (meta) { + } - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + } - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + this.clipTime = newClipTime; - return data; + if( this.loopCount !== previousLoopCount ) { -}; + this.mixer.dispatchEvent( { type: 'loop', action: this, loopDelta: ( this.loopCount - this.loopCount ) } ); -// File:src/lights/HemisphereLight.js + } + + return this.clipTime; -/** - * @author alteredq / http://alteredqualia.com/ - */ + }, -THREE.HemisphereLight = function (skyColor, groundColor, intensity) { + syncWith: function( action ) { - THREE.Light.call(this, skyColor); + this.actionTime = action.actionTime; + this.timeScale = action.timeScale; - this.type = 'HemisphereLight'; + return this; + }, - this.position.set(0, 100, 0); + warpToDuration: function( duration ) { - this.groundColor = new THREE.Color(groundColor); - this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.timeScale = this.clip.duration / duration; -}; + return this; + }, -THREE.HemisphereLight.prototype = Object.create(THREE.Light.prototype); -THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; + init: function( time ) { -THREE.HemisphereLight.prototype.clone = function () { + this.clipTime = time - this.startTime; - var light = new THREE.HemisphereLight(); + return this; - THREE.Light.prototype.clone.call(this, light); + }, - light.groundColor.copy(this.groundColor); - light.intensity = this.intensity; + update: function( clipDeltaTime ) { - return light; + this.updateTime( clipDeltaTime ); -}; + var clipResults = this.clip.getAt( this.clipTime ); -THREE.HemisphereLight.prototype.toJSON = function (meta) { + return clipResults; + + }, - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + getTimeScaleAt: function( time ) { - data.object.color = this.color.getHex(); - data.object.groundColor = this.groundColor.getHex(); + if( this.timeScale.getAt ) { + // pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip + return this.timeScale.getAt( time ); - return data; + } -}; + return this.timeScale; -// File:src/lights/PointLight.js + }, -/** - * @author mrdoob / http://mrdoob.com/ - */ + getWeightAt: function( time ) { -THREE.PointLight = function (color, intensity, distance, decay) { + if( this.weight.getAt ) { + // pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip + return this.weight.getAt( time ); - THREE.Light.call(this, color); + } - this.type = 'PointLight'; + return this.weight; - 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. + } }; -THREE.PointLight.prototype = Object.create(THREE.Light.prototype); -THREE.PointLight.prototype.constructor = THREE.PointLight; +// File:src/animation/AnimationClip.js -THREE.PointLight.prototype.clone = function () { +/** + * + * Reusable set of Tracks that represent an animation. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - var light = new THREE.PointLight(); +THREE.AnimationClip = function ( name, duration, tracks ) { - THREE.Light.prototype.clone.call(this, light); + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : -1; - light.intensity = this.intensity; - light.distance = this.distance; - light.decay = this.decay; + // this means it should figure out its duration by scanning the tracks + if( this.duration < 0 ) { + for( var i = 0; i < this.tracks.length; i ++ ) { + var track = this.tracks[i]; + this.duration = Math.max( track.keys[ track.keys.length - 1 ].time ); + } + } - return light; + // maybe only do these on demand, as doing them here could potentially slow down loading + // but leaving these here during development as this ensures a lot of testing of these functions + this.trim(); + this.optimize(); + this.results = []; + }; -THREE.PointLight.prototype.toJSON = function (meta) { +THREE.AnimationClip.prototype = { - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + constructor: THREE.AnimationClip, - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - data.object.distance = this.distance; - data.object.decay = this.decay; + getAt: function( clipTime ) { - return data; - -}; + clipTime = Math.max( 0, Math.min( clipTime, this.duration ) ); -// File:src/lights/SpotLight.js + for( var i = 0; i < this.tracks.length; i ++ ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + var track = this.tracks[ i ]; -THREE.SpotLight = function (color, intensity, distance, angle, exponent, decay) { + this.results[ i ] = track.getAt( clipTime ); - THREE.Light.call(this, color); + } - this.type = 'SpotLight'; + return this.results; + }, - this.position.set(0, 1, 0); - this.target = new THREE.Object3D(); + trim: function() { - 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. + for( var i = 0; i < this.tracks.length; i ++ ) { - this.castShadow = false; - this.onlyShadow = false; + this.tracks[ i ].trim( 0, this.duration ); - // + } - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - this.shadowCameraFov = 50; + return this; - this.shadowCameraVisible = false; + }, - this.shadowBias = 0; - this.shadowDarkness = 0.5; + optimize: function() { - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; + for( var i = 0; i < this.tracks.length; i ++ ) { - // + this.tracks[ i ].optimize(); - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; + } -}; + return this; -THREE.SpotLight.prototype = Object.create(THREE.Light.prototype); -THREE.SpotLight.prototype.constructor = THREE.SpotLight; + } -THREE.SpotLight.prototype.clone = function () { +}; - var light = new THREE.SpotLight(); - THREE.Light.prototype.clone.call(this, light); +THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetSequence, fps ) { - light.target = this.target.clone(); - light.intensity = this.intensity; - light.distance = this.distance; - light.angle = this.angle; - light.exponent = this.exponent; - light.decay = this.decay; + var numMorphTargets = morphTargetSequence.length; + var tracks = []; - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; + for( var i = 0; i < numMorphTargets; i ++ ) { - // + var keys = []; - light.shadowCameraNear = this.shadowCameraNear; - light.shadowCameraFar = this.shadowCameraFar; - light.shadowCameraFov = this.shadowCameraFov; + keys.push( { time: ( i + numMorphTargets - 1 ) % numMorphTargets, value: 0 } ); + keys.push( { time: i, value: 1 } ); + keys.push( { time: ( i + 1 ) % numMorphTargets, value: 0 } ); - light.shadowCameraVisible = this.shadowCameraVisible; + keys.sort( THREE.KeyframeTrack.keyComparer ); - light.shadowBias = this.shadowBias; - light.shadowDarkness = this.shadowDarkness; + // if there is a key at the first frame, duplicate it as the last frame as well for perfect loop. + if( keys[0].time === 0 ) { + keys.push( { + time: numMorphTargets, + value: keys[0].value + }); + } - light.shadowMapWidth = this.shadowMapWidth; - light.shadowMapHeight = this.shadowMapHeight; + tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + morphTargetSequence[i].name + ']', keys ).scale( 1.0 / fps ) ); + } - return light; + return new THREE.AnimationClip( name, -1, tracks ); }; -THREE.SpotLight.prototype.toJSON = function (meta) { - - var data = THREE.Object3D.prototype.toJSON.call(this, meta); +THREE.AnimationClip.findByName = function( clipArray, name ) { - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - data.object.distance = this.distance; - data.object.angle = this.angle; - data.object.exponent = this.exponent; - data.object.decay = this.decay; + for( var i = 0; i < clipArray.length; i ++ ) { - return data; - -}; - -// File:src/loaders/Cache.js + if( clipArray[i].name === name ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + return clipArray[i]; -THREE.Cache = { + } + } - files: {}, + return null; - add: function (key, file) { +}; - // THREE.log( 'THREE.Cache', 'Adding key:', key ); +THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets, fps ) { + + var animationToMorphTargets = {}; - this.files[key] = file; + // tested with https://regex101.com/ on trick sequences such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; - }, + // sort morph target names into animation groups based patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { - get: function (key) { + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); + + if ( parts && parts.length > 1 ) { - // THREE.log( 'THREE.Cache', 'Checking key:', key ); + var name = parts[ 1 ]; - return this.files[key]; + var animationMorphTargets = animationToMorphTargets[ name ]; + if( ! animationMorphTargets ) { + animationToMorphTargets[ name ] = animationMorphTargets = []; + } - }, + animationMorphTargets.push( morphTarget ); - remove: function (key) { + } - delete this.files[key]; + } - }, + var clips = []; - clear: function () { + for( var name in animationToMorphTargets ) { - this.files = {} + clips.push( THREE.AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps ) ); + } - } + return clips; }; -// File:src/loaders/Loader.js +// parse the standard JSON format for clips +THREE.AnimationClip.parse = function( json ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + var tracks = []; -THREE.Loader = function (showStatus) { + for( var i = 0; i < json.tracks.length; i ++ ) { - this.showStatus = showStatus; - this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + tracks.push( THREE.KeyframeTrack.parse( json.tracks[i] ).scale( 1.0 / json.fps ) ); - this.imageLoader = new THREE.ImageLoader(); + } - this.onLoadStart = function () { - }; - this.onLoadProgress = function () { - }; - this.onLoadComplete = function () { - }; + return new THREE.AnimationClip( json.name, json.duration, tracks ); }; -THREE.Loader.prototype = { - constructor: THREE.Loader, +// parse the animation.hierarchy format +THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) { - crossOrigin: undefined, + if( ! animation ) { + console.error( " no animation in JSONLoader data" ); + return null; + } - addStatusElement: function () { + var convertTrack = function( trackName, animationKeys, propertyName, trackType, animationKeyToValueFunc ) { - var e = document.createElement('div'); + var keys = []; - 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; + for( var k = 0; k < animationKeys.length; k ++ ) { - e.innerHTML = 'Loading ...'; + var animationKey = animationKeys[k]; - return e; + if( animationKey[propertyName] !== undefined ) { - }, + keys.push( { time: animationKey.time, value: animationKeyToValueFunc( animationKey ) } ); + } + + } - updateProgress: function (progress) { + // only return track if there are actually keys. + if( keys.length > 0 ) { + + return new trackType( trackName, keys ); - var message = 'Loaded '; + } - if (progress.total) { + return null; - message += ( 100 * progress.loaded / progress.total ).toFixed(0) + '%'; + }; + var tracks = []; - } else { + var clipName = animation.name || 'default'; + var duration = animation.length || -1; // automatic length determination in AnimationClip. + var fps = animation.fps || 30; - message += ( progress.loaded / 1024 ).toFixed(2) + ' KB'; + var hierarchyTracks = animation.hierarchy || []; - } + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - this.statusDomElement.innerHTML = message; + var animationKeys = hierarchyTracks[ h ].keys; - }, + // skip empty tracks + if( ! animationKeys || animationKeys.length == 0 ) { + continue; + } - extractUrlBase: function (url) { + // process morph targets in a way exactly compatible with AnimationHandler.init( animation ) + if( animationKeys[0].morphTargets ) { - var parts = url.split('/'); + // figure out all morph targets used in this track + var morphTargetNames = {}; + for( var k = 0; k < animationKeys.length; k ++ ) { - if (parts.length === 1) return './'; + if( animationKeys[k].morphTargets ) { + for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { - parts.pop(); + morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1; + } + } - return parts.join('/') + '/'; + } - }, + // create a track for each morph target with all zero morphTargetInfluences except for the keys in which the morphTarget is named. + for( var morphTargetName in morphTargetNames ) { - initMaterials: function (materials, texturePath) { + var keys = []; - var array = []; + for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { - for (var i = 0; i < materials.length; ++i) { + var animationKey = animationKeys[k]; - array[i] = this.createMaterial(materials[i], texturePath); + keys.push( { + time: animationKey.time, + value: (( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ) + }); + + } - } + tracks.push( new THREE.NumberKeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) ); - return array; + } - }, + duration = morphTargetNames.length * ( fps || 1.0 ); - needsTangents: function (materials) { + } + else { - for (var i = 0, il = materials.length; i < il; i++) { + var boneName = nodeName + '.bones[' + bones[ h ].name + ']'; + + // track contains positions... + var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', THREE.VectorKeyframeTrack, function( animationKey ) { + return new THREE.Vector3().fromArray( animationKey.pos ) + } ); - var m = materials[i]; + if( positionTrack ) tracks.push( positionTrack ); + + // track contains quaternions... + var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', THREE.QuaternionKeyframeTrack, function( animationKey ) { + if( animationKey.rot.slerp ) { + return animationKey.rot.clone(); + } + else { + return new THREE.Quaternion().fromArray( animationKey.rot ); + } + } ); - if (m instanceof THREE.ShaderMaterial) return true; + if( quaternionTrack ) tracks.push( quaternionTrack ); - } + // track contains quaternions... + var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', THREE.VectorKeyframeTrack, function( animationKey ) { + return new THREE.Vector3().fromArray( animationKey.scl ) + } ); - return false; + if( scaleTrack ) tracks.push( scaleTrack ); - }, + } + } - createMaterial: function (m, texturePath) { + if( tracks.length === 0 ) { - var scope = this; + return null; - function nearest_pow2(n) { + } - var l = Math.log(n) / Math.LN2; - return Math.pow(2, Math.round(l)); + var clip = new THREE.AnimationClip( clipName, duration, tracks ); - } + return clip; - function create_texture(where, name, sourceFile, repeat, offset, wrap, anisotropy) { +}; - var fullPath = texturePath + sourceFile; +// File:src/animation/AnimationMixer.js - var texture; +/** + * + * Mixes together the AnimationClips scheduled by AnimationActions and applies them to the root and subtree + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - var loader = THREE.Loader.Handlers.get(fullPath); +THREE.AnimationMixer = function( root ) { - if (loader !== null) { + this.root = root; + this.time = 0; + this.timeScale = 1.0; + this.actions = []; + this.propertyBindingMap = {}; - texture = loader.load(fullPath); +}; - } else { +THREE.AnimationMixer.prototype = { - texture = new THREE.Texture(); + constructor: THREE.AnimationMixer, - loader = scope.imageLoader; - loader.crossOrigin = scope.crossOrigin; - loader.load(fullPath, function (image) { + addAction: function( action ) { - if (THREE.Math.isPowerOfTwo(image.width) === false || - THREE.Math.isPowerOfTwo(image.height) === false) { + // TODO: check for duplicate action names? Or provide each action with a UUID? - var width = nearest_pow2(image.width); - var height = nearest_pow2(image.height); + this.actions.push( action ); + action.init( this.time ); + action.mixer = this; - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; + var tracks = action.clip.tracks; - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0, width, height); + var root = action.localRoot || this.root; - texture.image = canvas; + for( var i = 0; i < tracks.length; i ++ ) { - } else { + var track = tracks[ i ]; - texture.image = image; + var propertyBindingKey = root.uuid + '-' + track.name; + var propertyBinding = this.propertyBindingMap[ propertyBindingKey ]; - } + if( propertyBinding === undefined ) { + + propertyBinding = new THREE.PropertyBinding( root, track.name ); + this.propertyBindingMap[ propertyBindingKey ] = propertyBinding; + + } - texture.needsUpdate = true; + // push in the same order as the tracks. + action.propertyBindings.push( propertyBinding ); + + // track usages of shared property bindings, because if we leave too many around, the mixer can get slow + propertyBinding.referenceCount += 1; - }); + } - } + }, - texture.sourceFile = sourceFile; + removeAllActions: function() { - if (repeat) { + for( var i = 0; i < this.actions.length; i ++ ) { - texture.repeat.set(repeat[0], repeat[1]); + this.actions[i].mixer = null; + + } - if (repeat[0] !== 1) texture.wrapS = THREE.RepeatWrapping; - if (repeat[1] !== 1) texture.wrapT = THREE.RepeatWrapping; + // unbind all property bindings + for( var properyBindingKey in this.propertyBindingMap ) { - } + this.propertyBindingMap[ properyBindingKey ].unbind(); - if (offset) { + } - texture.offset.set(offset[0], offset[1]); + this.actions = []; + this.propertyBindingMap = {}; - } + return this; - if (wrap) { + }, - var wrapMap = { - 'repeat': THREE.RepeatWrapping, - 'mirror': THREE.MirroredRepeatWrapping - }; + removeAction: function( action ) { - if (wrapMap[wrap[0]] !== undefined) texture.wrapS = wrapMap[wrap[0]]; - if (wrapMap[wrap[1]] !== undefined) texture.wrapT = wrapMap[wrap[1]]; + var index = this.actions.indexOf( action ); - } + if ( index !== - 1 ) { - if (anisotropy) { + this.actions.splice( index, 1 ); + action.mixer = null; - texture.anisotropy = anisotropy; + } - } - where[name] = texture; + // remove unused property bindings because if we leave them around the mixer can get slow + var root = action.localRoot || this.root; + var tracks = action.clip.tracks; - } + for( var i = 0; i < tracks.length; i ++ ) { + + var track = tracks[ i ]; - function rgb2hex(rgb) { + var propertyBindingKey = root.uuid + '-' + track.name; + var propertyBinding = this.propertyBindingMap[ propertyBindingKey ]; + + propertyBinding.referenceCount -= 1; - return ( rgb[0] * 255 << 16 ) + ( rgb[1] * 255 << 8 ) + rgb[2] * 255; + if( propertyBinding.referenceCount <= 0 ) { - } + propertyBinding.unbind(); - // defaults + delete this.propertyBindingMap[ propertyBindingKey ]; - var mtype = 'MeshLambertMaterial'; - var mpars = { - color: 0xeeeeee, - opacity: 1.0, - map: null, - lightMap: null, - normalMap: null, - bumpMap: null, - wireframe: false - }; + } + } - // parameters from model file + return this; - if (m.shading) { + }, - var shading = m.shading.toLowerCase(); + // can be optimized if needed + findActionByName: function( name ) { - if (shading === 'phong') mtype = 'MeshPhongMaterial'; - else if (shading === 'basic') mtype = 'MeshBasicMaterial'; + for( var i = 0; i < this.actions.length; i ++ ) { - } + if( this.actions[i].name === name ) return this.actions[i]; - if (m.blending !== undefined && THREE[m.blending] !== undefined) { + } - mpars.blending = THREE[m.blending]; + return null; - } + }, - if (m.transparent !== undefined) { + play: function( action, optionalFadeInDuration ) { - mpars.transparent = m.transparent; + action.startTime = this.time; + this.addAction( action ); - } + return this; - if (m.opacity !== undefined && m.opacity < 1.0) { + }, - mpars.transparent = true; + fadeOut: function( action, duration ) { - } + var keys = []; - if (m.depthTest !== undefined) { + keys.push( { time: this.time, value: 1 } ); + keys.push( { time: this.time + duration, value: 0 } ); + + action.weight = new THREE.NumberKeyframeTrack( "weight", keys ); - mpars.depthTest = m.depthTest; + return this; - } + }, - if (m.depthWrite !== undefined) { + fadeIn: function( action, duration ) { + + var keys = []; + + keys.push( { time: this.time, value: 0 } ); + keys.push( { time: this.time + duration, value: 1 } ); + + action.weight = new THREE.NumberKeyframeTrack( "weight", keys ); - mpars.depthWrite = m.depthWrite; + return this; - } + }, - if (m.visible !== undefined) { + warp: function( action, startTimeScale, endTimeScale, duration ) { - mpars.visible = m.visible; + var keys = []; + + keys.push( { time: this.time, value: startTimeScale } ); + keys.push( { time: this.time + duration, value: endTimeScale } ); + + action.timeScale = new THREE.NumberKeyframeTrack( "timeScale", keys ); - } + return this; - if (m.flipSided !== undefined) { + }, - mpars.side = THREE.BackSide; + crossFade: function( fadeOutAction, fadeInAction, duration, warp ) { - } + this.fadeOut( fadeOutAction, duration ); + this.fadeIn( fadeInAction, duration ); - if (m.doubleSided !== undefined) { + if( warp ) { + + var startEndRatio = fadeOutAction.clip.duration / fadeInAction.clip.duration; + var endStartRatio = 1.0 / startEndRatio; - mpars.side = THREE.DoubleSide; + this.warp( fadeOutAction, 1.0, startEndRatio, duration ); + this.warp( fadeInAction, endStartRatio, 1.0, duration ); - } + } - if (m.wireframe !== undefined) { + return this; + + }, - mpars.wireframe = m.wireframe; + update: function( deltaTime ) { - } + var mixerDeltaTime = deltaTime * this.timeScale; + this.time += mixerDeltaTime; - if (m.vertexColors !== undefined) { + for( var i = 0; i < this.actions.length; i ++ ) { - if (m.vertexColors === 'face') { + var action = this.actions[i]; - mpars.vertexColors = THREE.FaceColors; + var weight = action.getWeightAt( this.time ); - } else if (m.vertexColors) { + var actionTimeScale = action.getTimeScaleAt( this.time ); + var actionDeltaTime = mixerDeltaTime * actionTimeScale; + + var actionResults = action.update( actionDeltaTime ); - mpars.vertexColors = THREE.VertexColors; + if( action.weight <= 0 || ! action.enabled ) continue; - } + for( var j = 0; j < actionResults.length; j ++ ) { - } + var name = action.clip.tracks[j].name; - // colors + action.propertyBindings[ j ].accumulate( actionResults[j], weight ); - if (m.colorDiffuse) { + } - mpars.color = rgb2hex(m.colorDiffuse); + } + + // apply to nodes + for( var propertyBindingKey in this.propertyBindingMap ) { - } else if (m.DbgColor) { + this.propertyBindingMap[ propertyBindingKey ].apply(); - mpars.color = m.DbgColor; + } - } + return this; + + } - if (m.colorSpecular) { +}; - mpars.specular = rgb2hex(m.colorSpecular); +THREE.EventDispatcher.prototype.apply( THREE.AnimationMixer.prototype ); - } +// File:src/animation/AnimationUtils.js - if (m.colorEmissive) { +/** + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - mpars.emissive = rgb2hex(m.colorEmissive); + THREE.AnimationUtils = { - } + getEqualsFunc: function( exemplarValue ) { + + if( exemplarValue.equals ) { + return function equals_object( a, b ) { + return a.equals( b ); + } + } + + return function equals_primitive( a, b ) { + return ( a === b ); + }; - // modifiers + }, - if (m.transparency !== undefined) { + clone: function( exemplarValue ) { - THREE.warn('THREE.Loader: transparency has been renamed to opacity'); - m.opacity = m.transparency; + var typeName = typeof exemplarValue; + if( typeName === "object" ) { + if( exemplarValue.clone ) { + return exemplarValue.clone(); + } + console.error( "can not figure out how to copy exemplarValue", exemplarValue ); + } - } + return exemplarValue; - if (m.opacity !== undefined) { + }, - mpars.opacity = m.opacity; + lerp: function( a, b, alpha, interTrack ) { - } + var lerpFunc = THREE.AnimationUtils.getLerpFunc( a, interTrack ); - if (m.specularCoef) { + return lerpFunc( a, b, alpha ); - mpars.shininess = m.specularCoef; + }, - } + lerp_object: function( a, b, alpha ) { + return a.lerp( b, alpha ); + }, + + slerp_object: function( a, b, alpha ) { + return a.slerp( b, alpha ); + }, - // textures + lerp_number: function( a, b, alpha ) { + return a * ( 1 - alpha ) + b * alpha; + }, - if (m.mapDiffuse && texturePath) { + lerp_boolean: function( a, b, alpha ) { + return ( alpha < 0.5 ) ? a : b; + }, - create_texture(mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy); + lerp_boolean_immediate: function( a, b, alpha ) { + return a; + }, + + lerp_string: function( a, b, alpha ) { + return ( alpha < 0.5 ) ? a : b; + }, + + lerp_string_immediate: function( a, b, alpha ) { + return a; + }, - } + // NOTE: this is an accumulator function that modifies the first argument (e.g. a). This is to minimize memory alocations. + getLerpFunc: function( exemplarValue, interTrack ) { - if (m.mapLight && texturePath) { + if( exemplarValue === undefined || exemplarValue === null ) throw new Error( "examplarValue is null" ); - create_texture(mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy); + var typeName = typeof exemplarValue; + switch( typeName ) { + case "object": { - } + if( exemplarValue.lerp ) { - if (m.mapAO && texturePath) { + return THREE.AnimationUtils.lerp_object; - create_texture(mpars, 'aoMap', m.mapAO, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy); + } + if( exemplarValue.slerp ) { - } + return THREE.AnimationUtils.slerp_object; - if (m.mapBump && texturePath) { + } + break; + } + case "number": { + return THREE.AnimationUtils.lerp_number; + } + case "boolean": { + if( interTrack ) { + return THREE.AnimationUtils.lerp_boolean; + } + else { + return THREE.AnimationUtils.lerp_boolean_immediate; + } + } + case "string": { + if( interTrack ) { + return THREE.AnimationUtils.lerp_string; + } + else { + return THREE.AnimationUtils.lerp_string_immediate; + } + } + }; + + } + +}; +// File:src/animation/KeyframeTrack.js - create_texture(mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy); +/** + * + * A Track that returns a keyframe interpolated value, currently linearly interpolated + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - } +THREE.KeyframeTrack = function ( name, keys ) { - if (m.mapNormal && texturePath) { + if( name === undefined ) throw new Error( "track name is undefined" ); + if( keys === undefined || keys.length === 0 ) throw new Error( "no keys in track named " + name ); - create_texture(mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy); + this.name = name; + this.keys = keys; // time in seconds, value as value - } + // the index of the last result, used as a starting point for local search. + this.lastIndex = 0; - if (m.mapSpecular && texturePath) { + this.validate(); + this.optimize(); +}; - create_texture(mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy); +THREE.KeyframeTrack.prototype = { - } + constructor: THREE.KeyframeTrack, - if (m.mapAlpha && texturePath) { + getAt: function( time ) { - create_texture(mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy); - } + // this can not go higher than this.keys.length. + while( ( this.lastIndex < this.keys.length ) && ( time >= this.keys[this.lastIndex].time ) ) { + this.lastIndex ++; + }; - // + // this can not go lower than 0. + while( ( this.lastIndex > 0 ) && ( time < this.keys[this.lastIndex - 1].time ) ) { + this.lastIndex --; + } - if (m.mapBumpScale) { + if( this.lastIndex >= this.keys.length ) { - mpars.bumpScale = m.mapBumpScale; + this.setResult( this.keys[ this.keys.length - 1 ].value ); - } + return this.result; - if (m.mapNormalFactor) { + } - mpars.normalScale = new THREE.Vector2(m.mapNormalFactor, m.mapNormalFactor); + if( this.lastIndex === 0 ) { - } + this.setResult( this.keys[ 0 ].value ); - var material = new THREE[mtype](mpars); + return this.result; - if (m.DbgName !== undefined) material.name = m.DbgName; + } - return material; + var prevKey = this.keys[ this.lastIndex - 1 ]; + this.setResult( prevKey.value ); - } + // if true, means that prev/current keys are identical, thus no interpolation required. + if( prevKey.constantToNext ) { -}; + return this.result; -THREE.Loader.Handlers = { + } - handlers: [], + // linear interpolation to start with + var currentKey = this.keys[ this.lastIndex ]; + var alpha = ( time - prevKey.time ) / ( currentKey.time - prevKey.time ); + this.result = this.lerpValues( this.result, currentKey.value, alpha ); - add: function (regex, loader) { + return this.result; - this.handlers.push(regex, loader); + }, - }, + // move all keyframes either forwards or backwards in time + shift: function( timeOffset ) { - get: function (file) { + if( timeOffset !== 0.0 ) { - for (var i = 0, l = this.handlers.length; i < l; i += 2) { + for( var i = 0; i < this.keys.length; i ++ ) { + this.keys[i].time += timeOffset; + } - var regex = this.handlers[i]; - var loader = this.handlers[i + 1]; + } - if (regex.test(file)) { + return this; - return loader; + }, - } + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function( timeScale ) { - } + if( timeScale !== 1.0 ) { - return null; + for( var i = 0; i < this.keys.length; i ++ ) { + this.keys[i].time *= timeScale; + } - } + } -}; + return this; -// File:src/loaders/XHRLoader.js + }, -/** - * @author mrdoob / http://mrdoob.com/ - */ + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim: function( startTime, endTime ) { -THREE.XHRLoader = function (manager) { + var firstKeysToRemove = 0; + for( var i = 1; i < this.keys.length; i ++ ) { + if( this.keys[i] <= startTime ) { + firstKeysToRemove ++; + } + } - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + var lastKeysToRemove = 0; + for( var i = this.keys.length - 2; i > 0; i ++ ) { + if( this.keys[i] >= endTime ) { + lastKeysToRemove ++; + } + else { + break; + } + } -}; + // remove last keys first because it doesn't affect the position of the first keys (the otherway around doesn't work as easily) + if( ( firstKeysToRemove + lastKeysToRemove ) > 0 ) { + this.keys = this.keys.splice( firstKeysToRemove, this.keys.length - lastKeysToRemove - firstKeysToRemove );; + } -THREE.XHRLoader.prototype = { + return this; - constructor: THREE.XHRLoader, + }, - load: function (url, onLoad, onProgress, onError) { + /* NOTE: This is commented out because we really shouldn't have to handle unsorted key lists + Tracks with out of order keys should be considered to be invalid. - bhouston + sort: function() { - var scope = this; + this.keys.sort( THREE.KeyframeTrack.keyComparer ); - var cached = THREE.Cache.get(url); + return this; - if (cached !== undefined) { + },*/ - if (onLoad) onLoad(cached); - return; + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + // One could eventually ensure that all key.values in a track are all of the same type (otherwise interpolation makes no sense.) + validate: function() { - } + var prevKey = null; - var request = new XMLHttpRequest(); - request.open('GET', url, true); + if( this.keys.length === 0 ) { + console.error( " track is empty, no keys", this ); + return; + } - request.addEventListener('load', function (event) { + for( var i = 0; i < this.keys.length; i ++ ) { - THREE.Cache.add(url, this.response); + var currKey = this.keys[i]; - if (onLoad) onLoad(this.response); + if( ! currKey ) { + console.error( " key is null in track", this, i ); + return; + } - scope.manager.itemEnd(url); + if( ( typeof currKey.time ) !== 'number' || Number.isNaN( currKey.time ) ) { + console.error( " key.time is not a valid number", this, i, currKey ); + return; + } - }, false); + if( currKey.value === undefined || currKey.value === null) { + console.error( " key.value is null in track", this, i, currKey ); + return; + } - if (onProgress !== undefined) { + if( prevKey && prevKey.time > currKey.time ) { + console.error( " key.time is less than previous key time, out of order keys", this, i, currKey, prevKey ); + return; + } - request.addEventListener('progress', function (event) { + prevKey = currKey; - onProgress(event); + } - }, false); + return this; - } + }, - if (onError !== undefined) { + // currently only removes equivalent sequential keys (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0), which are common in morph target animations + optimize: function() { - request.addEventListener('error', function (event) { + var newKeys = []; + var prevKey = this.keys[0]; + newKeys.push( prevKey ); - onError(event); + var equalsFunc = THREE.AnimationUtils.getEqualsFunc( prevKey.value ); - }, false); + for( var i = 1; i < this.keys.length - 1; i ++ ) { + var currKey = this.keys[i]; + var nextKey = this.keys[i+1]; - } + // if prevKey & currKey are the same time, remove currKey. If you want immediate adjacent keys, use an epsilon offset + // it is not possible to have two keys at the same time as we sort them. The sort is not stable on keys with the same time. + if( ( prevKey.time === currKey.time ) ) { - if (this.crossOrigin !== undefined) request.crossOrigin = this.crossOrigin; - if (this.responseType !== undefined) request.responseType = this.responseType; + continue; - request.send(null); + } - scope.manager.itemStart(url); + // remove completely unnecessary keyframes that are the same as their prev and next keys + if( this.compareValues( prevKey.value, currKey.value ) && this.compareValues( currKey.value, nextKey.value ) ) { - }, + continue; - setResponseType: function (value) { + } - this.responseType = value; + // determine if interpolation is required + prevKey.constantToNext = this.compareValues( prevKey.value, currKey.value ); - }, + newKeys.push( currKey ); + prevKey = currKey; + } + newKeys.push( this.keys[ this.keys.length - 1 ] ); - setCrossOrigin: function (value) { + this.keys = newKeys; - this.crossOrigin = value; + return this; - } + } }; -// File:src/loaders/ImageLoader.js - -/** - * @author mrdoob / http://mrdoob.com/ - */ +THREE.KeyframeTrack.keyComparer = function keyComparator(key0, key1) { + return key0.time - key1.time; +}; -THREE.ImageLoader = function (manager) { +THREE.KeyframeTrack.parse = function( json ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + if( json.type === undefined ) throw new Error( "track type undefined, can not parse" ); -}; + var trackType = THREE.KeyframeTrack.GetTrackTypeForTypeName( json.type ); -THREE.ImageLoader.prototype = { + return trackType.parse( json ); - constructor: THREE.ImageLoader, +}; - load: function (url, onLoad, onProgress, onError) { +THREE.KeyframeTrack.GetTrackTypeForTypeName = function( typeName ) { + switch( typeName.toLowerCase() ) { + case "vector": + case "vector2": + case "vector3": + case "vector4": + return THREE.VectorKeyframeTrack; - var scope = this; + case "quaternion": + return THREE.QuaternionKeyframeTrack; - var cached = THREE.Cache.get(url); + case "integer": + case "scalar": + case "double": + case "float": + case "number": + return THREE.NumberKeyframeTrack; - if (cached !== undefined) { + case "bool": + case "boolean": + return THREE.BooleanKeyframeTrack; - onLoad(cached); - return; + case "string": + return THREE.StringKeyframeTrack; + }; - } + throw new Error( "Unsupported typeName: " + typeName ); +}; +// File:src/animation/PropertyBinding.js - var image = document.createElement('img'); +/** + * + * A track bound to a real value in the scene graph. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - image.addEventListener('load', function (event) { +THREE.PropertyBinding = function ( rootNode, trackName ) { - THREE.Cache.add(url, this); + this.rootNode = rootNode; + this.trackName = trackName; + this.referenceCount = 0; + this.originalValue = null; // the value of the property before it was controlled by this binding - if (onLoad) onLoad(this); + var parseResults = THREE.PropertyBinding.parseTrackName( trackName ); - scope.manager.itemEnd(url); + this.directoryName = parseResults.directoryName; + this.nodeName = parseResults.nodeName; + this.objectName = parseResults.objectName; + this.objectIndex = parseResults.objectIndex; + this.propertyName = parseResults.propertyName; + this.propertyIndex = parseResults.propertyIndex; - }, false); + this.node = THREE.PropertyBinding.findNode( rootNode, this.nodeName ) || rootNode; + + this.cumulativeValue = null; + this.cumulativeWeight = 0; +}; - if (onProgress !== undefined) { +THREE.PropertyBinding.prototype = { - image.addEventListener('progress', function (event) { + constructor: THREE.PropertyBinding, - onProgress(event); + reset: function() { - }, false); + this.cumulativeValue = null; + this.cumulativeWeight = 0; + + }, - } + accumulate: function( value, weight ) { + + if( ! this.isBound ) this.bind(); - if (onError !== undefined) { + if( this.cumulativeWeight === 0 ) { - image.addEventListener('error', function (event) { + if( weight > 0 ) { - onError(event); + if( this.cumulativeValue === null ) { + this.cumulativeValue = THREE.AnimationUtils.clone( value ); + } + this.cumulativeWeight = weight; - }, false); + } - } + } + else { + + var lerpAlpha = weight / ( this.cumulativeWeight + weight ); + this.cumulativeValue = this.lerpValue( this.cumulativeValue, value, lerpAlpha ); + this.cumulativeWeight += weight; + + } + + }, + + unbind: function() { + + if( ! this.isBound ) return; + + this.setValue( this.originalValue ); + + this.setValue = null; + this.getValue = null; + this.lerpValue = null; + this.equalsValue = null; + this.triggerDirty = null; + this.isBound = false; + + }, + + // bind to the real property in the scene graph, remember original value, memorize various accessors for speed/inefficiency + bind: function() { + + if( this.isBound ) return; + + var targetObject = this.node; + + // ensure there is a value node + if( ! targetObject ) { + console.error( " trying to update node for track: " + this.trackName + " but it wasn't found." ); + return; + } + + if( this.objectName ) { + // special case were we need to reach deeper into the hierarchy to get the face materials.... + if( this.objectName === "materials" ) { + if( ! targetObject.material ) { + console.error( ' can not bind to material as node does not have a material', this ); + return; + } + if( ! targetObject.material.materials ) { + console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); + return; + } + targetObject = targetObject.material.materials; + } + else if( this.objectName === "bones" ) { + if( ! targetObject.skeleton ) { + console.error( ' can not bind to bones as node does not have a skeleton', this ); + return; + } + // potential future optimization: skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + + targetObject = targetObject.skeleton.bones; + + // support resolving morphTarget names into indices. + for( var i = 0; i < targetObject.length; i ++ ) { + if( targetObject[i].name === this.objectIndex ) { + this.objectIndex = i; + break; + } + } + } + else { + + if( targetObject[ this.objectName ] === undefined ) { + console.error( ' can not bind to objectName of node, undefined', this ); + return; + } + targetObject = targetObject[ this.objectName ]; + } + + if( this.objectIndex !== undefined ) { + if( targetObject[ this.objectIndex ] === undefined ) { + console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); + return; + } + + targetObject = targetObject[ this.objectIndex ]; + } + + } + + // special case mappings + var nodeProperty = targetObject[ this.propertyName ]; + if( ! nodeProperty ) { + console.error( " trying to update property for track: " + this.nodeName + '.' + this.propertyName + " but it wasn't found.", targetObject ); + return; + } + + // access a sub element of the property array (only primitives are supported right now) + if( this.propertyIndex !== undefined ) { + + if( this.propertyName === "morphTargetInfluences" ) { + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + + // support resolving morphTarget names into indices. + if( ! targetObject.geometry ) { + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); + } + if( ! targetObject.geometry.morphTargets ) { + console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); + } + + for( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { + if( targetObject.geometry.morphTargets[i].name === this.propertyIndex ) { + this.propertyIndex = i; + break; + } + } + } + + this.setValue = function setValue_propertyIndexed( value ) { + if( ! this.equalsValue( nodeProperty[ this.propertyIndex ], value ) ) { + nodeProperty[ this.propertyIndex ] = value; + return true; + } + return false; + }; + + this.getValue = function getValue_propertyIndexed() { + return nodeProperty[ this.propertyIndex ]; + }; + + } + // must use copy for Object3D.Euler/Quaternion + else if( nodeProperty.copy ) { + + this.setValue = function setValue_propertyObject( value ) { + if( ! this.equalsValue( nodeProperty, value ) ) { + nodeProperty.copy( value ); + return true; + } + return false; + } + + this.getValue = function getValue_propertyObject() { + return nodeProperty; + }; + + } + // otherwise just set the property directly on the node (do not use nodeProperty as it may not be a reference object) + else { + + this.setValue = function setValue_property( value ) { + if( ! this.equalsValue( targetObject[ this.propertyName ], value ) ) { + targetObject[ this.propertyName ] = value; + return true; + } + return false; + } + + this.getValue = function getValue_property() { + return targetObject[ this.propertyName ]; + }; + + } + + // trigger node dirty + if( targetObject.needsUpdate !== undefined ) { // material + + this.triggerDirty = function triggerDirty_needsUpdate() { + this.node.needsUpdate = true; + } + + } + else if( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + + this.triggerDirty = function triggerDirty_matrixWorldNeedsUpdate() { + targetObject.matrixWorldNeedsUpdate = true; + } - if (this.crossOrigin !== undefined) image.crossOrigin = this.crossOrigin; + } - image.src = url; + this.originalValue = this.getValue(); - scope.manager.itemStart(url); + this.equalsValue = THREE.AnimationUtils.getEqualsFunc( this.originalValue ); + this.lerpValue = THREE.AnimationUtils.getLerpFunc( this.originalValue, true ); - return image; + this.isBound = true; - }, + }, - setCrossOrigin: function (value) { + apply: function() { - this.crossOrigin = value; + // for speed capture the setter pattern as a closure (sort of a memoization pattern: https://en.wikipedia.org/wiki/Memoization) + if( ! this.isBound ) this.bind(); - } + // early exit if there is nothing to apply. + if( this.cumulativeWeight > 0 ) { + + // blend with original value + if( this.cumulativeWeight < 1 ) { -}; + var remainingWeight = 1 - this.cumulativeWeight; + var lerpAlpha = remainingWeight / ( this.cumulativeWeight + remainingWeight ); + this.cumulativeValue = this.lerpValue( this.cumulativeValue, this.originalValue, lerpAlpha ); -// File:src/loaders/JSONLoader.js + } -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + var valueChanged = this.setValue( this.cumulativeValue ); -THREE.JSONLoader = function (showStatus) { + if( valueChanged && this.triggerDirty ) { + this.triggerDirty(); + } - THREE.Loader.call(this, showStatus); + // reset accumulator + this.cumulativeValue = null; + this.cumulativeWeight = 0; - this.withCredentials = false; + } + } }; -THREE.JSONLoader.prototype = Object.create(THREE.Loader.prototype); -THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; -THREE.JSONLoader.prototype.load = function (url, callback, texturePath) { +THREE.PropertyBinding.parseTrackName = function( trackName ) { - // todo: unify load API to for easier SceneLoader use + // matches strings in the form of: + // nodeName.property + // nodeName.property[accessor] + // nodeName.material.property[accessor] + // uuid.property[accessor] + // uuid.objectName[objectIndex].propertyName[propertyIndex] + // parentName/nodeName.property + // parentName/parentName/nodeName.property[index] + // .bone[Armature.DEF_cog].position + // created and tested via https://regex101.com/#javascript - texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase(url); + var re = /^(([\w]+\/)*)([\w-\d]+)?(\.([\w]+)(\[([\w\d\[\]\_. ]+)\])?)?(\.([\w.]+)(\[([\w\d\[\]\_. ]+)\])?)$/; + var matches = re.exec(trackName); - this.onLoadStart(); - this.loadAjaxJSON(this, url, callback, texturePath); + if( ! matches ) { + throw new Error( "cannot parse trackName at all: " + trackName ); + } -}; + if (matches.index === re.lastIndex) { + re.lastIndex++; + } -THREE.JSONLoader.prototype.loadAjaxJSON = function (context, url, callback, texturePath, callbackProgress) { + var results = { + directoryName: matches[1], + nodeName: matches[3], // allowed to be null, specified root node. + objectName: matches[5], + objectIndex: matches[7], + propertyName: matches[9], + propertyIndex: matches[11] // allowed to be null, specifies that the whole property is set. + }; - var xhr = new XMLHttpRequest(); + if( results.propertyName === null || results.propertyName.length === 0 ) { + throw new Error( "can not parse propertyName from trackName: " + trackName ); + } - var length = 0; + return results; - xhr.onreadystatechange = function () { +}; - if (xhr.readyState === xhr.DONE) { +THREE.PropertyBinding.findNode = function( root, nodeName ) { - if (xhr.status === 200 || xhr.status === 0) { + if( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { - if (xhr.responseText) { + return root; - var json = JSON.parse(xhr.responseText); - var metadata = json.metadata; + } - if (metadata !== undefined) { + // search into skeleton bones. + if( root.skeleton ) { - if (metadata.type === 'object') { + var searchSkeleton = function( skeleton ) { - THREE.error('THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.'); - return; + for( var i = 0; i < skeleton.bones.length; i ++ ) { - } + var bone = skeleton.bones[i]; - if (metadata.type === 'scene') { + if( bone.name === nodeName ) { - THREE.error('THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.'); - return; + return bone; - } + } + } - } + return null; - var result = context.parse(json, texturePath); - callback(result.geometry, result.materials); + }; - } else { + var bone = searchSkeleton( root.skeleton ); - THREE.error('THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.'); + if( bone ) { - } + return bone; - // in context of more complex asset initialization - // do not block on single failed file - // maybe should go even one more level up + } + } - context.onLoadComplete(); + // search into node subtree. + if( root.children ) { - } else { + var searchNodeSubtree = function( children ) { - THREE.error('THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')'); + for( var i = 0; i < children.length; i ++ ) { - } + var childNode = children[i]; - } else if (xhr.readyState === xhr.LOADING) { + if( childNode.name === nodeName || childNode.uuid === nodeName ) { - if (callbackProgress) { + return childNode; - if (length === 0) { + } - length = xhr.getResponseHeader('Content-Length'); + var result = searchNodeSubtree( childNode.children ); - } + if( result ) return result; - callbackProgress({total: length, loaded: xhr.responseText.length}); + } - } + return null; - } else if (xhr.readyState === xhr.HEADERS_RECEIVED) { + }; - if (callbackProgress !== undefined) { + var subTreeNode = searchNodeSubtree( root.children ); - length = xhr.getResponseHeader('Content-Length'); + if( subTreeNode ) { - } + return subTreeNode; - } + } - }; + } - xhr.open('GET', url, true); - xhr.withCredentials = this.withCredentials; - xhr.send(null); + return null; +} -}; +// File:src/animation/tracks/VectorKeyframeTrack.js -THREE.JSONLoader.prototype.parse = function (json, texturePath) { +/** + * + * A Track that interpolates Vectors + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ + +THREE.VectorKeyframeTrack = function ( name, keys ) { + + THREE.KeyframeTrack.call( this, name, keys ); + + // local cache of value type to avoid allocations during runtime. + this.result = this.keys[0].value.clone(); + +}; - var geometry = new THREE.Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; +THREE.VectorKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); - parseModel(scale); +THREE.VectorKeyframeTrack.prototype.constructor = THREE.VectorKeyframeTrack; - parseSkin(); - parseMorphing(scale); +THREE.VectorKeyframeTrack.prototype.setResult = function( value ) { - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + this.result.copy( value ); - function parseModel(scale) { +}; - function isBitSet(value, position) { +// memoization of the lerp function for speed. +// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. +THREE.VectorKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { - return value & ( 1 << position ); + return value0.lerp( value1, alpha ); - } +}; - var i, j, fi, +THREE.VectorKeyframeTrack.prototype.compareValues = function( value0, value1 ) { - offset, zLength, + return value0.equals( value1 ); - colorIndex, normalIndex, uvIndex, +}; - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, +THREE.VectorKeyframeTrack.prototype.clone = function() { - vertex, face, faceA, faceB, hex, normal, + var clonedKeys = []; - uvLayer, uv, u, v, + for( var i = 0; i < this.keys.length; i ++ ) { + + var key = this.keys[i]; + clonedKeys.push( { + time: key.time, + value: key.value.clone() + } ); + } - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + return new THREE.VectorKeyframeTrack( this.name, clonedKeys ); - nUvLayers = 0; +}; - if (json.uvs !== undefined) { +THREE.VectorKeyframeTrack.parse = function( json ) { - // disregard empty arrays + var elementCount = json.keys[0].value.length; + var valueType = THREE[ 'Vector' + elementCount ]; - for (i = 0; i < json.uvs.length; i++) { + var keys = []; - if (json.uvs[i].length) nUvLayers++; + for( var i = 0; i < json.keys.length; i ++ ) { + var jsonKey = json.keys[i]; + keys.push( { + value: new valueType().fromArray( jsonKey.value ), + time: jsonKey.time + } ); + } - } + return new THREE.VectorKeyframeTrack( json.name, keys ); - for (i = 0; i < nUvLayers; i++) { +}; + +// File:src/animation/tracks/QuaternionKeyframeTrack.js - geometry.faceVertexUvs[i] = []; +/** + * + * A Track that interpolates Quaternion + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - } +THREE.QuaternionKeyframeTrack = function ( name, keys ) { - } + THREE.KeyframeTrack.call( this, name, keys ); - offset = 0; - zLength = vertices.length; + // local cache of value type to avoid allocations during runtime. + this.result = this.keys[0].value.clone(); - while (offset < zLength) { +}; + +THREE.QuaternionKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); - vertex = new THREE.Vector3(); +THREE.QuaternionKeyframeTrack.prototype.constructor = THREE.QuaternionKeyframeTrack; - vertex.x = vertices[offset++] * scale; - vertex.y = vertices[offset++] * scale; - vertex.z = vertices[offset++] * scale; +THREE.QuaternionKeyframeTrack.prototype.setResult = function( value ) { - geometry.vertices.push(vertex); + this.result.copy( value ); - } +}; - offset = 0; - zLength = faces.length; +// memoization of the lerp function for speed. +// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. +THREE.QuaternionKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { - while (offset < zLength) { + return value0.slerp( value1, alpha ); - type = faces[offset++]; +}; +THREE.QuaternionKeyframeTrack.prototype.compareValues = function( value0, value1 ) { - 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); + return value0.equals( value1 ); - // THREE.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); +}; - if (isQuad) { +THREE.QuaternionKeyframeTrack.prototype.multiply = function( quat ) { - faceA = new THREE.Face3(); - faceA.a = faces[offset]; - faceA.b = faces[offset + 1]; - faceA.c = faces[offset + 3]; + for( var i = 0; i < this.keys.length; i ++ ) { - faceB = new THREE.Face3(); - faceB.a = faces[offset + 1]; - faceB.b = faces[offset + 2]; - faceB.c = faces[offset + 3]; + this.keys[i].value.multiply( quat ); + + } - offset += 4; + return this; - if (hasMaterial) { +}; - offset++; +THREE.QuaternionKeyframeTrack.prototype.clone = function() { - } + var clonedKeys = []; - // to get face <=> uv index correspondence + for( var i = 0; i < this.keys.length; i ++ ) { + + var key = this.keys[i]; + clonedKeys.push( { + time: key.time, + value: key.value.clone() + } ); + } - fi = geometry.faces.length; + return new THREE.QuaternionKeyframeTrack( this.name, clonedKeys ); - if (hasFaceVertexUv) { +}; - for (i = 0; i < nUvLayers; i++) { +THREE.QuaternionKeyframeTrack.parse = function( json ) { - uvLayer = json.uvs[i]; + var keys = []; - geometry.faceVertexUvs[i][fi] = []; - geometry.faceVertexUvs[i][fi + 1] = []; + for( var i = 0; i < json.keys.length; i ++ ) { + var jsonKey = json.keys[i]; + keys.push( { + value: new THREE.Quaternion().fromArray( jsonKey.value ), + time: jsonKey.time + } ); + } - for (j = 0; j < 4; j++) { + return new THREE.QuaternionKeyframeTrack( json.name, keys ); - uvIndex = faces[offset++]; +}; + +// File:src/animation/tracks/StringKeyframeTrack.js - u = uvLayer[uvIndex * 2]; - v = uvLayer[uvIndex * 2 + 1]; +/** + * + * A Track that interpolates Strings + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - uv = new THREE.Vector2(u, v); +THREE.StringKeyframeTrack = function ( name, keys ) { - if (j !== 2) geometry.faceVertexUvs[i][fi].push(uv); - if (j !== 0) geometry.faceVertexUvs[i][fi + 1].push(uv); + THREE.KeyframeTrack.call( this, name, keys ); - } + // local cache of value type to avoid allocations during runtime. + this.result = this.keys[0].value; - } +}; - } +THREE.StringKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); - if (hasFaceNormal) { +THREE.StringKeyframeTrack.prototype.constructor = THREE.StringKeyframeTrack; - normalIndex = faces[offset++] * 3; +THREE.StringKeyframeTrack.prototype.setResult = function( value ) { - faceA.normal.set( - normals[normalIndex++], - normals[normalIndex++], - normals[normalIndex] - ); + this.result = value; - faceB.normal.copy(faceA.normal); +}; - } +// memoization of the lerp function for speed. +// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. +THREE.StringKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { - if (hasFaceVertexNormal) { + return ( alpha < 1.0 ) ? value0 : value1; - for (i = 0; i < 4; i++) { +}; - normalIndex = faces[offset++] * 3; +THREE.StringKeyframeTrack.prototype.compareValues = function( value0, value1 ) { - normal = new THREE.Vector3( - normals[normalIndex++], - normals[normalIndex++], - normals[normalIndex] - ); + return ( value0 === value1 ); +}; - if (i !== 2) faceA.vertexNormals.push(normal); - if (i !== 0) faceB.vertexNormals.push(normal); +THREE.StringKeyframeTrack.prototype.clone = function() { - } + var clonedKeys = []; - } + for( var i = 0; i < this.keys.length; i ++ ) { + + var key = this.keys[i]; + clonedKeys.push( { + time: key.time, + value: key.value + } ); + } + return new THREE.StringKeyframeTrack( this.name, clonedKeys ); - if (hasFaceColor) { +}; - colorIndex = faces[offset++]; - hex = colors[colorIndex]; +THREE.StringKeyframeTrack.parse = function( json ) { - faceA.color.setHex(hex); - faceB.color.setHex(hex); + return new THREE.StringKeyframeTrack( json.name, json.keys ); - } +}; + +// File:src/animation/tracks/BooleanKeyframeTrack.js +/** + * + * A Track that interpolates Boolean + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - if (hasFaceVertexColor) { +THREE.BooleanKeyframeTrack = function ( name, keys ) { - for (i = 0; i < 4; i++) { + THREE.KeyframeTrack.call( this, name, keys ); - colorIndex = faces[offset++]; - hex = colors[colorIndex]; + // local cache of value type to avoid allocations during runtime. + this.result = this.keys[0].value; - if (i !== 2) faceA.vertexColors.push(new THREE.Color(hex)); - if (i !== 0) faceB.vertexColors.push(new THREE.Color(hex)); +}; - } +THREE.BooleanKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); - } +THREE.BooleanKeyframeTrack.prototype.constructor = THREE.BooleanKeyframeTrack; - geometry.faces.push(faceA); - geometry.faces.push(faceB); +THREE.BooleanKeyframeTrack.prototype.setResult = function( value ) { - } else { + this.result = value; - face = new THREE.Face3(); - face.a = faces[offset++]; - face.b = faces[offset++]; - face.c = faces[offset++]; +}; - if (hasMaterial) { +// memoization of the lerp function for speed. +// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. +THREE.BooleanKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { - offset++; + return ( alpha < 1.0 ) ? value0 : value1; - } +}; - // to get face <=> uv index correspondence +THREE.BooleanKeyframeTrack.prototype.compareValues = function( value0, value1 ) { - fi = geometry.faces.length; + return ( value0 === value1 ); - if (hasFaceVertexUv) { +}; - for (i = 0; i < nUvLayers; i++) { +THREE.BooleanKeyframeTrack.prototype.clone = function() { - uvLayer = json.uvs[i]; + var clonedKeys = []; - geometry.faceVertexUvs[i][fi] = []; + for( var i = 0; i < this.keys.length; i ++ ) { + + var key = this.keys[i]; + clonedKeys.push( { + time: key.time, + value: key.value + } ); + } - for (j = 0; j < 3; j++) { + return new THREE.BooleanKeyframeTrack( this.name, clonedKeys ); - uvIndex = faces[offset++]; +}; - u = uvLayer[uvIndex * 2]; - v = uvLayer[uvIndex * 2 + 1]; +THREE.BooleanKeyframeTrack.parse = function( json ) { - uv = new THREE.Vector2(u, v); + return new THREE.BooleanKeyframeTrack( json.name, json.keys ); - geometry.faceVertexUvs[i][fi].push(uv); +}; + +// File:src/animation/tracks/NumberKeyframeTrack.js - } +/** + * + * A Track that interpolates Numbers + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - } +THREE.NumberKeyframeTrack = function ( name, keys ) { - } + THREE.KeyframeTrack.call( this, name, keys ); - if (hasFaceNormal) { + // local cache of value type to avoid allocations during runtime. + this.result = this.keys[0].value; - normalIndex = faces[offset++] * 3; +}; - face.normal.set( - normals[normalIndex++], - normals[normalIndex++], - normals[normalIndex] - ); +THREE.NumberKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); - } +THREE.NumberKeyframeTrack.prototype.constructor = THREE.NumberKeyframeTrack; - if (hasFaceVertexNormal) { +THREE.NumberKeyframeTrack.prototype.setResult = function( value ) { - for (i = 0; i < 3; i++) { + this.result = value; - normalIndex = faces[offset++] * 3; +}; - normal = new THREE.Vector3( - normals[normalIndex++], - normals[normalIndex++], - normals[normalIndex] - ); +// memoization of the lerp function for speed. +// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. +THREE.NumberKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { - face.vertexNormals.push(normal); + return value0 * ( 1 - alpha ) + value1 * alpha; - } +}; - } +THREE.NumberKeyframeTrack.prototype.compareValues = function( value0, value1 ) { + return ( value0 === value1 ); - if (hasFaceColor) { +}; - colorIndex = faces[offset++]; - face.color.setHex(colors[colorIndex]); +THREE.NumberKeyframeTrack.prototype.clone = function() { - } + var clonedKeys = []; + for( var i = 0; i < this.keys.length; i ++ ) { + + var key = this.keys[i]; + clonedKeys.push( { + time: key.time, + value: key.value + } ); + } - if (hasFaceVertexColor) { + return new THREE.NumberKeyframeTrack( this.name, clonedKeys ); - for (i = 0; i < 3; i++) { +}; - colorIndex = faces[offset++]; - face.vertexColors.push(new THREE.Color(colors[colorIndex])); +THREE.NumberKeyframeTrack.parse = function( json ) { - } + return new THREE.NumberKeyframeTrack( json.name, json.keys ); - } +}; + +// File:src/cameras/Camera.js - geometry.faces.push(face); +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ - } +THREE.Camera = function () { - } + THREE.Object3D.call( this ); - } + this.type = 'Camera'; - function parseSkin() { - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + this.matrixWorldInverse = new THREE.Matrix4(); + this.projectionMatrix = new THREE.Matrix4(); - if (json.skinWeights) { +}; - for (var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex) { +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Camera.prototype.constructor = THREE.Camera; - 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; +THREE.Camera.prototype.getWorldDirection = function () { - geometry.skinWeights.push(new THREE.Vector4(x, y, z, w)); + var quaternion = new THREE.Quaternion(); - } + return function ( optionalTarget ) { - } + var result = optionalTarget || new THREE.Vector3(); - if (json.skinIndices) { + this.getWorldQuaternion( quaternion ); - for (var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex) { + return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - 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; + }; - geometry.skinIndices.push(new THREE.Vector4(a, b, c, d)); +}(); - } +THREE.Camera.prototype.lookAt = function () { - } + // This routine does not support cameras with rotated and/or translated parent(s) - geometry.bones = json.bones; + var m1 = new THREE.Matrix4(); - if (geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length )) { + return function ( vector ) { - THREE.warn('THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.'); + m1.lookAt( this.position, vector, this.up ); - } + this.quaternion.setFromRotationMatrix( m1 ); + }; - // could change this to json.animations[0] or remove completely +}(); - geometry.animation = json.animation; - geometry.animations = json.animations; +THREE.Camera.prototype.clone = function () { - } + return new this.constructor().copy( this ); - function parseMorphing(scale) { +}; - if (json.morphTargets !== undefined) { +THREE.Camera.prototype.copy = function ( source ) { - var i, l, v, vl, dstVertices, srcVertices; + THREE.Object3D.prototype.copy.call( this, source ); - for (i = 0, l = json.morphTargets.length; i < l; i++) { + this.matrixWorldInverse.copy( source.matrixWorldInverse ); + this.projectionMatrix.copy( source.projectionMatrix ); - geometry.morphTargets[i] = {}; - geometry.morphTargets[i].name = json.morphTargets[i].name; - geometry.morphTargets[i].vertices = []; + return this; - dstVertices = geometry.morphTargets[i].vertices; - srcVertices = json.morphTargets [i].vertices; +}; - for (v = 0, vl = srcVertices.length; v < vl; v += 3) { +// File:src/cameras/CubeCamera.js - var vertex = new THREE.Vector3(); - vertex.x = srcVertices[v] * scale; - vertex.y = srcVertices[v + 1] * scale; - vertex.z = srcVertices[v + 2] * scale; +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ - dstVertices.push(vertex); +THREE.CubeCamera = function ( near, far, cubeResolution ) { - } + THREE.Object3D.call( this ); - } + this.type = 'CubeCamera'; - } + var fov = 90, aspect = 1; - if (json.morphColors !== undefined) { + 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 i, l, c, cl, dstColors, srcColors, color; + 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 ); - for (i = 0, l = json.morphColors.length; i < l; i++) { + 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 ); - geometry.morphColors[i] = {}; - geometry.morphColors[i].name = json.morphColors[i].name; - geometry.morphColors[i].colors = []; + 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 ); - dstColors = geometry.morphColors[i].colors; - srcColors = json.morphColors [i].colors; + 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 ); - for (c = 0, cl = srcColors.length; c < cl; c += 3) { + 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 ); - color = new THREE.Color(0xffaa00); - color.setRGB(srcColors[c], srcColors[c + 1], srcColors[c + 2]); - dstColors.push(color); + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); - } + this.updateCubeMap = function ( renderer, scene ) { - } + if ( this.parent === null ) this.updateMatrixWorld(); - } + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; - } + renderTarget.generateMipmaps = false; - if (json.materials === undefined || json.materials.length === 0) { + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); - return {geometry: geometry}; + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); - } else { + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); - var materials = this.initMaterials(json.materials, texturePath); + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); - if (this.needsTangents(materials)) { + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); - geometry.computeTangents(); + renderTarget.generateMipmaps = generateMipmaps; - } + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); - return {geometry: geometry, materials: materials}; + renderer.setRenderTarget( null ); - } + }; }; -// File:src/loaders/LoadingManager.js +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); +THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; + +// File:src/cameras/OrthographicCamera.js /** - * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ */ -THREE.LoadingManager = function (onLoad, onProgress, onError) { +THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { - var scope = this; + THREE.Camera.call( this ); - var loaded = 0, total = 0; + this.type = 'OrthographicCamera'; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + this.zoom = 1; - this.itemStart = function (url) { + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; - total++; + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; - }; + this.updateProjectionMatrix(); - this.itemEnd = function (url) { +}; - loaded++; +THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; - if (scope.onProgress !== undefined) { +THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { - scope.onProgress(url, loaded, total); + 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; - } + this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far ); - if (loaded === total && scope.onLoad !== undefined) { +}; - scope.onLoad(); +THREE.OrthographicCamera.prototype.copy = function ( source ) { + + THREE.Camera.prototype.copy.call( this, source ); + + this.left = source.left; + this.right = source.right; + this.top = source.top; + this.bottom = source.bottom; + this.near = source.near; + this.far = source.far; + + this.zoom = source.zoom; + + return this; + +}; - } +THREE.OrthographicCamera.prototype.toJSON = function ( meta ) { - }; + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); -}; + data.object.zoom = this.zoom; + data.object.left = this.left; + data.object.right = this.right; + data.object.top = this.top; + data.object.bottom = this.bottom; + data.object.near = this.near; + data.object.far = this.far; -THREE.DefaultLoadingManager = new THREE.LoadingManager(); + return data; -// File:src/loaders/BufferGeometryLoader.js +}; + +// File:src/cameras/PerspectiveCamera.js /** * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog */ -THREE.BufferGeometryLoader = function (manager) { +THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + THREE.Camera.call( this ); -}; + this.type = 'PerspectiveCamera'; -THREE.BufferGeometryLoader.prototype = { + this.zoom = 1; - constructor: THREE.BufferGeometryLoader, + 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; - load: function (url, onLoad, onProgress, onError) { + this.updateProjectionMatrix(); - var scope = this; +}; - var loader = new THREE.XHRLoader(scope.manager); - loader.setCrossOrigin(this.crossOrigin); - loader.load(url, function (text) { +THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); +THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; - onLoad(scope.parse(JSON.parse(text))); - }, onProgress, onError); +/** + * Uses Focal Length (in mm) to estimate and set FOV + * 35mm (full-frame) 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 ) { - setCrossOrigin: function (value) { + if ( frameHeight === undefined ) frameHeight = 24; - this.crossOrigin = value; + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); - }, +}; - parse: function (json) { - var geometry = new THREE.BufferGeometry(); +/** + * 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. + */ - var attributes = json.data.attributes; +THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { - for (var key in attributes) { + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; - var attribute = attributes[key]; - var typedArray = new self[attribute.type](attribute.array); + this.updateProjectionMatrix(); - geometry.addAttribute(key, new THREE.BufferAttribute(typedArray, attribute.itemSize)); +}; - } - var offsets = json.data.offsets; +THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { - if (offsets !== undefined) { + var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) ); - geometry.offsets = JSON.parse(JSON.stringify(offsets)); + if ( this.fullWidth ) { - } + 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 ); - var boundingSphere = json.data.boundingSphere; + 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 (boundingSphere !== undefined) { + } else { - var center = new THREE.Vector3(); + this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far ); - if (boundingSphere.center !== undefined) { + } - center.fromArray(boundingSphere.center); +}; - } +THREE.PerspectiveCamera.prototype.copy = function ( source ) { + + THREE.Camera.prototype.copy.call( this, source ); + + this.fov = source.fov; + this.aspect = source.aspect; + this.near = source.near; + this.far = source.far; + + this.zoom = source.zoom; + + return this; + +}; - geometry.boundingSphere = new THREE.Sphere(center, boundingSphere.radius); +THREE.PerspectiveCamera.prototype.toJSON = function ( meta ) { - } + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - return geometry; + data.object.zoom = this.zoom; + data.object.fov = this.fov; + data.object.aspect = this.aspect; + data.object.near = this.near; + data.object.far = this.far; - } + return data; }; -// File:src/loaders/MaterialLoader.js +// File:src/lights/Light.js /** * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ */ -THREE.MaterialLoader = function (manager) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.MaterialLoader.prototype = { - - constructor: THREE.MaterialLoader, - - load: function (url, onLoad, onProgress, onError) { +THREE.Light = function ( color ) { - var scope = this; + THREE.Object3D.call( this ); - var loader = new THREE.XHRLoader(scope.manager); - loader.setCrossOrigin(this.crossOrigin); - loader.load(url, function (text) { + this.type = 'Light'; - onLoad(scope.parse(JSON.parse(text))); + this.color = new THREE.Color( color ); - }, onProgress, onError); - - }, - - setCrossOrigin: function (value) { +}; - this.crossOrigin = value; +THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Light.prototype.constructor = THREE.Light; - }, +THREE.Light.prototype.copy = function ( source ) { + + THREE.Object3D.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + + return this; - parse: function (json) { +}; +// File:src/lights/AmbientLight.js - var material = new THREE[json.type]; +/** + * @author mrdoob / http://mrdoob.com/ + */ - 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; - if (json.alphaTest !== undefined) material.alphaTest = json.alphaTest; +THREE.AmbientLight = function ( color ) { - // for PointCloudMaterial - if (json.size !== undefined) material.size = json.size; - if (json.sizeAttenuation !== undefined) material.sizeAttenuation = json.sizeAttenuation; + THREE.Light.call( this, color ); - if (json.materials !== undefined) { + this.type = 'AmbientLight'; - for (var i = 0, l = json.materials.length; i < l; i++) { +}; - material.materials.push(this.parse(json.materials[i])); +THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; - } +THREE.AmbientLight.prototype.toJSON = function ( meta ) { - } + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - return material; + data.object.color = this.color.getHex(); - } + return data; }; -// File:src/loaders/ObjectLoader.js +// File:src/lights/DirectionalLight.js /** * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ */ -THREE.ObjectLoader = function (manager) { +THREE.DirectionalLight = function ( color, intensity ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - this.texturePath = ''; + THREE.Light.call( this, color ); -}; + this.type = 'DirectionalLight'; -THREE.ObjectLoader.prototype = { + this.position.set( 0, 1, 0 ); + this.updateMatrix(); + + this.target = new THREE.Object3D(); - constructor: THREE.ObjectLoader, + this.intensity = ( intensity !== undefined ) ? intensity : 1; - load: function (url, onLoad, onProgress, onError) { + this.castShadow = false; + this.onlyShadow = false; - if (this.texturePath === '') { + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; - this.texturePath = url.substring(0, url.lastIndexOf('/') + 1); + this.shadowCameraLeft = - 500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = - 500; - } + this.shadowCameraVisible = false; - var scope = this; + this.shadowBias = 0; + this.shadowDarkness = 0.5; - var loader = new THREE.XHRLoader(scope.manager); - loader.setCrossOrigin(this.crossOrigin); - loader.load(url, function (text) { + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - scope.parse(JSON.parse(text), onLoad); + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; - }, onProgress, onError); +}; - }, +THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); +THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; - setTexturePath: function (value) { +THREE.DirectionalLight.prototype.copy = function ( source ) { - this.texturePath = value; + THREE.Light.prototype.copy.call( this, source ); - }, + this.intensity = source.intensity; + this.target = source.target.clone(); - setCrossOrigin: function (value) { + this.castShadow = source.castShadow; + this.onlyShadow = source.onlyShadow; - this.crossOrigin = value; + this.shadowCameraNear = source.shadowCameraNear; + this.shadowCameraFar = source.shadowCameraFar; - }, + this.shadowCameraLeft = source.shadowCameraLeft; + this.shadowCameraRight = source.shadowCameraRight; + this.shadowCameraTop = source.shadowCameraTop; + this.shadowCameraBottom = source.shadowCameraBottom; - parse: function (json, onLoad) { + this.shadowCameraVisible = source.shadowCameraVisible; - var geometries = this.parseGeometries(json.geometries); + this.shadowBias = source.shadowBias; + this.shadowDarkness = source.shadowDarkness; - var images = this.parseImages(json.images, function () { + this.shadowMapWidth = source.shadowMapWidth; + this.shadowMapHeight = source.shadowMapHeight; - if (onLoad !== undefined) onLoad(object); + return this; - }); - var textures = this.parseTextures(json.textures, images); - var materials = this.parseMaterials(json.materials, textures); - var object = this.parseObject(json.object, geometries, materials); +}; - if (json.images === undefined || json.images.length === 0) { +THREE.DirectionalLight.prototype.toJSON = function ( meta ) { - if (onLoad !== undefined) onLoad(object); + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - } + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - return object; + return data; - }, +}; - parseGeometries: function (json) { +// File:src/lights/HemisphereLight.js - var geometries = {}; +/** + * @author alteredq / http://alteredqualia.com/ + */ - if (json !== undefined) { +THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { - var geometryLoader = new THREE.JSONLoader(); - var bufferGeometryLoader = new THREE.BufferGeometryLoader(); + THREE.Light.call( this, skyColor ); - for (var i = 0, l = json.length; i < l; i++) { + this.type = 'HemisphereLight'; - var geometry; - var data = json[i]; + this.position.set( 0, 1, 0 ); + this.updateMatrix(); - switch (data.type) { + this.groundColor = new THREE.Color( groundColor ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; - case 'PlaneGeometry': - case 'PlaneBufferGeometry': +}; - geometry = new THREE[data.type]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); +THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); +THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; - break; +THREE.HemisphereLight.prototype.copy = function ( source ) { - case 'BoxGeometry': - case 'CubeGeometry': // backwards compatible + THREE.Light.prototype.copy.call( this, source ); - geometry = new THREE.BoxGeometry( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + this.groundColor.copy( source.groundColor ); + this.intensity = source.intensity; - break; + return this; - case 'CircleGeometry': +}; - geometry = new THREE.CircleGeometry( - data.radius, - data.segments - ); +THREE.HemisphereLight.prototype.toJSON = function ( meta ) { - break; + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - case 'CylinderGeometry': + data.object.color = this.color.getHex(); + data.object.groundColor = this.groundColor.getHex(); + data.object.intensity = this.intensity; - geometry = new THREE.CylinderGeometry( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded - ); + return data; - break; +}; - case 'SphereGeometry': +// File:src/lights/PointLight.js - geometry = new THREE.SphereGeometry( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - break; - case 'IcosahedronGeometry': +THREE.PointLight = function ( color, intensity, distance, decay ) { - geometry = new THREE.IcosahedronGeometry( - data.radius, - data.detail - ); + THREE.Light.call( this, color ); - break; + this.type = 'PointLight'; - case 'TorusGeometry': + 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. - geometry = new THREE.TorusGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); + this.castShadow = false; + this.onlyShadow = false; - break; + // - case 'TorusKnotGeometry': + this.shadowCameraNear = 1; + this.shadowCameraFar = 500; + this.shadowCameraFov = 90; - geometry = new THREE.TorusKnotGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.p, - data.q, - data.heightScale - ); + this.shadowCameraVisible = false; - break; + this.shadowBias = 0; + this.shadowDarkness = 0.5; - case 'BufferGeometry': + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - geometry = bufferGeometryLoader.parse(data); + // - break; + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; - case 'Geometry': +}; - geometry = geometryLoader.parse(data.data).geometry; +THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); +THREE.PointLight.prototype.constructor = THREE.PointLight; - break; +THREE.PointLight.prototype.copy = function ( source ) { - case 'TextGeometry': + THREE.Light.prototype.copy.call( this, source ); - geometry = new THREE.TextGeometry( - data.text, - data.data - ); + this.intensity = source.intensity; + this.distance = source.distance; + this.decay = source.decay; - break; + this.castShadow = source.castShadow; + this.onlyShadow = source.onlyShadow; - } + this.shadowCameraNear = source.shadowCameraNear; + this.shadowCameraFar = source.shadowCameraFar; + this.shadowCameraFov = source.shadowCameraFov; - geometry.uuid = data.uuid; + this.shadowCameraVisible = source.shadowCameraVisible; - if (data.name !== undefined) geometry.name = data.name; + this.shadowBias = source.shadowBias; + this.shadowDarkness = source.shadowDarkness; - geometries[data.uuid] = geometry; + this.shadowMapWidth = source.shadowMapWidth; + this.shadowMapHeight = source.shadowMapHeight; - } + return this; - } +}; - return geometries; +THREE.PointLight.prototype.toJSON = function ( meta ) { - }, + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - parseMaterials: function (json, textures) { + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; + data.object.distance = this.distance; + data.object.decay = this.decay; - var materials = {}; + return data; - if (json !== undefined) { +}; - var getTexture = function (name) { +// File:src/lights/SpotLight.js - if (textures[name] === undefined) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - THREE.warn('THREE.ObjectLoader: Undefined texture', name); +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { - } + THREE.Light.call( this, color ); - return textures[name]; + this.type = 'SpotLight'; - }; + this.position.set( 0, 1, 0 ); + this.updateMatrix(); - var loader = new THREE.MaterialLoader(); + this.target = new THREE.Object3D(); - for (var i = 0, l = json.length; i < l; i++) { + 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. - var data = json[i]; - var material = loader.parse(data); + this.castShadow = false; + this.onlyShadow = false; - material.uuid = data.uuid; + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; - if (data.name !== undefined) material.name = data.name; + this.shadowCameraVisible = false; - if (data.map !== undefined) { + this.shadowBias = 0; + this.shadowDarkness = 0.5; - material.map = getTexture(data.map); + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; - } + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; - if (data.bumpMap !== undefined) { +}; - material.bumpMap = getTexture(data.bumpMap); - if (data.bumpScale !== undefined) { - material.bumpScale = data.bumpScale; - } +THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); +THREE.SpotLight.prototype.constructor = THREE.SpotLight; - } +THREE.SpotLight.prototype.copy = function ( source ) { - if (data.alphaMap !== undefined) { + THREE.Light.prototype.copy.call( this, source ); - material.alphaMap = getTexture(data.alphaMap); + this.intensity = source.intensity; + this.distance = source.distance; + this.angle = source.angle; + this.exponent = source.exponent; + this.decay = source.decay; - } + this.target = source.target.clone(); - if (data.envMap !== undefined) { + this.castShadow = source.castShadow; + this.onlyShadow = source.onlyShadow; - material.envMap = getTexture(data.envMap); + this.shadowCameraNear = source.shadowCameraNear; + this.shadowCameraFar = source.shadowCameraFar; + this.shadowCameraFov = source.shadowCameraFov; - } + this.shadowCameraVisible = source.shadowCameraVisible; - if (data.normalMap !== undefined) { + this.shadowBias = source.shadowBias; + this.shadowDarkness = source.shadowDarkness; - material.normalMap = getTexture(data.normalMap); - if (data.normalScale !== undefined) { - material.normalScale = new THREE.Vector2(data.normalScale, data.normalScale); - } + this.shadowMapWidth = source.shadowMapWidth; + this.shadowMapHeight = source.shadowMapHeight; - } + return this; +} - if (data.lightMap !== undefined) { +THREE.SpotLight.prototype.toJSON = function ( meta ) { - material.lightMap = getTexture(data.lightMap); + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - if (data.lightMapIntensity !== undefined) { - material.lightMapIntensity = data.lightMapIntensity; - } + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; + data.object.distance = this.distance; + data.object.angle = this.angle; + data.object.exponent = this.exponent; + data.object.decay = this.decay; - } + return data; - if (data.aoMap !== undefined) { +}; - material.aoMap = getTexture(data.aoMap); - if (data.aoMapIntensity !== undefined) { - material.aoMapIntensity = data.aoMapIntensity; - } - } +// File:src/loaders/Cache.js - if (data.specularMap !== undefined) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - material.specularMap = getTexture(data.specularMap); +THREE.Cache = { - } + enabled: false, - materials[data.uuid] = material; + files: {}, - } + add: function ( key, file ) { - } + if ( this.enabled === false ) return; - return materials; + // console.log( 'THREE.Cache', 'Adding key:', key ); - }, + this.files[ key ] = file; - parseImages: function (json, onLoad) { + }, - var scope = this; - var images = {}; + get: function ( key ) { - if (json !== undefined && json.length > 0) { + if ( this.enabled === false ) return; - var manager = new THREE.LoadingManager(onLoad); + // console.log( 'THREE.Cache', 'Checking key:', key ); - var loader = new THREE.ImageLoader(manager); - loader.setCrossOrigin(this.crossOrigin); + return this.files[ key ]; - var loadImage = function (url) { + }, - scope.manager.itemStart(url); + remove: function ( key ) { - return loader.load(url, function () { + delete this.files[ key ]; - scope.manager.itemEnd(url); + }, - }); + clear: function () { - }; + this.files = {}; - for (var i = 0, l = json.length; i < l; i++) { + } - var image = json[i]; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(image.url) ? image.url : scope.texturePath + image.url; +}; - images[image.uuid] = loadImage(path); +// File:src/loaders/Loader.js - } +/** + * @author alteredq / http://alteredqualia.com/ + */ - } +THREE.Loader = function () { - return images; + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; - }, +}; - parseTextures: function (json, images) { +THREE.Loader.prototype = { - var textures = {}; + constructor: THREE.Loader, - if (json !== undefined) { + crossOrigin: undefined, - for (var i = 0, l = json.length; i < l; i++) { + extractUrlBase: function ( url ) { - var data = json[i]; + var parts = url.split( '/' ); - if (data.image === undefined) { + if ( parts.length === 1 ) return './'; - THREE.warn('THREE.ObjectLoader: No "image" speficied for', data.uuid); + parts.pop(); - } + return parts.join( '/' ) + '/'; - if (images[data.image] === undefined) { + }, - THREE.warn('THREE.ObjectLoader: Undefined image', data.image); + initMaterials: function ( materials, texturePath, crossOrigin ) { - } + var array = []; - var texture = new THREE.Texture(images[data.image]); - texture.needsUpdate = true; + for ( var i = 0; i < materials.length; ++ i ) { - texture.uuid = data.uuid; + array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); - 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]]; + return array; - } + }, - textures[data.uuid] = texture; + createMaterial: ( function () { - } + var imageLoader; - } + return function createMaterial( m, texturePath, crossOrigin ) { - return textures; + var scope = this; - }, + if ( crossOrigin === undefined && scope.crossOrigin !== undefined ) crossOrigin = scope.crossOrigin; - parseObject: function () { + if ( imageLoader === undefined ) imageLoader = new THREE.ImageLoader(); - var matrix = new THREE.Matrix4(); + function nearest_pow2( n ) { - return function (data, geometries, materials) { + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); - var object; + } - var getGeometry = function (name) { + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - if (geometries[name] === undefined) { + var fullPath = texturePath + sourceFile; - THREE.warn('THREE.ObjectLoader: Undefined geometry', name); + var texture; - } + var loader = THREE.Loader.Handlers.get( fullPath ); - return geometries[name]; + if ( loader !== null ) { - }; + texture = loader.load( fullPath ); - var getMaterial = function (name) { + } else { - if (materials[name] === undefined) { + texture = new THREE.Texture(); - THREE.warn('THREE.ObjectLoader: Undefined material', name); + loader = imageLoader; + loader.setCrossOrigin( crossOrigin ); + loader.load( fullPath, function ( image ) { - } + if ( THREE.Math.isPowerOfTwo( image.width ) === false || + THREE.Math.isPowerOfTwo( image.height ) === false ) { - return materials[name]; + var width = nearest_pow2( image.width ); + var height = nearest_pow2( image.height ); - }; + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - switch (data.type) { + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, width, height ); - case 'Scene': + texture.image = canvas; - object = new THREE.Scene(); + } else { - break; + texture.image = image; - case 'PerspectiveCamera': + } - object = new THREE.PerspectiveCamera(data.fov, data.aspect, data.near, data.far); + texture.needsUpdate = true; - break; + } ); - case 'OrthographicCamera': + } - object = new THREE.OrthographicCamera(data.left, data.right, data.top, data.bottom, data.near, data.far); + texture.sourceFile = sourceFile; - break; + if ( repeat ) { - case 'AmbientLight': + texture.repeat.set( repeat[ 0 ], repeat[ 1 ] ); - object = new THREE.AmbientLight(data.color); + if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - break; + } - case 'DirectionalLight': + if ( offset ) { - object = new THREE.DirectionalLight(data.color, data.intensity); + texture.offset.set( offset[ 0 ], offset[ 1 ] ); - break; + } - case 'PointLight': + if ( wrap ) { - object = new THREE.PointLight(data.color, data.intensity, data.distance, data.decay); + var wrapMap = { + 'repeat': THREE.RepeatWrapping, + 'mirror': THREE.MirroredRepeatWrapping + }; - break; + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ]; - case 'SpotLight': + } - object = new THREE.SpotLight(data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay); + if ( anisotropy ) { - break; + texture.anisotropy = anisotropy; - case 'HemisphereLight': + } - object = new THREE.HemisphereLight(data.color, data.groundColor, data.intensity); + where[ name ] = texture; - break; + } - case 'Mesh': + function rgb2hex( rgb ) { - object = new THREE.Mesh(getGeometry(data.geometry), getMaterial(data.material)); + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; - break; + } - case 'Line': + // defaults - object = new THREE.Line(getGeometry(data.geometry), getMaterial(data.material), data.mode); + var mtype = 'MeshLambertMaterial'; + var mpars = {}; - break; + // parameters from model file - case 'PointCloud': + if ( m.shading ) { - object = new THREE.PointCloud(getGeometry(data.geometry), getMaterial(data.material)); + var shading = m.shading.toLowerCase(); - break; + if ( shading === 'phong' ) mtype = 'MeshPhongMaterial'; + else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial'; - case 'Sprite': + } - object = new THREE.Sprite(getMaterial(data.material)); + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { - break; + mpars.blending = THREE[ m.blending ]; - case 'Group': + } - object = new THREE.Group(); + if ( m.transparent !== undefined ) { - break; + mpars.transparent = m.transparent; - default: + } - object = new THREE.Object3D(); + if ( m.opacity !== undefined && m.opacity < 1.0 ) { - } + mpars.transparent = true; - object.uuid = data.uuid; + } - if (data.name !== undefined) object.name = data.name; - if (data.matrix !== undefined) { + if ( m.depthTest !== undefined ) { - matrix.fromArray(data.matrix); - matrix.decompose(object.position, object.quaternion, object.scale); + mpars.depthTest = m.depthTest; - } 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 ( m.depthWrite !== undefined ) { - } + mpars.depthWrite = m.depthWrite; - if (data.castShadow !== undefined) object.castShadow = data.castShadow; - if (data.receiveShadow !== undefined) object.receiveShadow = data.receiveShadow; + } - if (data.visible !== undefined) object.visible = data.visible; - if (data.userData !== undefined) object.userData = data.userData; + if ( m.visible !== undefined ) { - if (data.children !== undefined) { + mpars.visible = m.visible; - for (var child in data.children) { + } - object.add(this.parseObject(data.children[child], geometries, materials)); + if ( m.flipSided !== undefined ) { - } + mpars.side = THREE.BackSide; - } + } - return object; + if ( m.doubleSided !== undefined ) { - } + mpars.side = THREE.DoubleSide; - }() + } -}; + if ( m.wireframe !== undefined ) { -// File:src/loaders/TextureLoader.js + mpars.wireframe = m.wireframe; -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -THREE.TextureLoader = function (manager) { + if ( m.vertexColors !== undefined ) { - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + if ( m.vertexColors === 'face' ) { -}; + mpars.vertexColors = THREE.FaceColors; -THREE.TextureLoader.prototype = { + } else if ( m.vertexColors ) { - constructor: THREE.TextureLoader, + mpars.vertexColors = THREE.VertexColors; - 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) { + // colors - var texture = new THREE.Texture(image); - texture.needsUpdate = true; + if ( m.colorDiffuse ) { - if (onLoad !== undefined) { + mpars.color = rgb2hex( m.colorDiffuse ); - onLoad(texture); + } else if ( m.DbgColor ) { - } + mpars.color = m.DbgColor; - }, onProgress, onError); + } - }, + if ( m.colorEmissive ) { - setCrossOrigin: function (value) { + mpars.emissive = rgb2hex( m.colorEmissive ); - this.crossOrigin = value; + } - } + if ( mtype === 'MeshPhongMaterial' ) { -}; + if ( m.colorSpecular ) { -// File:src/loaders/BinaryTextureLoader.js + mpars.specular = rgb2hex( m.colorSpecular ); -/** - * @author Nikos M. / https://github.com/foo123/ - * - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - */ + } -THREE.DataTextureLoader = THREE.BinaryTextureLoader = function () { + if ( m.specularCoef ) { - // override in sub classes - this._parser = null; + mpars.shininess = m.specularCoef; -}; + } -THREE.BinaryTextureLoader.prototype = { + } - constructor: THREE.BinaryTextureLoader, + // modifiers - load: function (url, onLoad, onProgress, onError) { + if ( m.transparency !== undefined ) { - var scope = this; + console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); + m.opacity = m.transparency; - var texture = new THREE.DataTexture(); + } - var loader = new THREE.XHRLoader(); - loader.setResponseType('arraybuffer'); + if ( m.opacity !== undefined ) { - loader.load(url, function (buffer) { + mpars.opacity = m.opacity; - var texData = scope._parser(buffer); + } - if (!texData) return; + // textures - if (undefined !== texData.image) { + if ( texturePath ) { - texture.image = texData.image; + if ( m.mapDiffuse ) { - } else if (undefined !== texData.data) { + create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; + } - } + if ( m.mapLight ) { - texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping; - texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; + create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; - texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter; + } - texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; + if ( m.mapAO ) { - if (undefined !== texData.format) { + create_texture( mpars, 'aoMap', m.mapAO, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - texture.format = texData.format; + } - } - if (undefined !== texData.type) { + if ( m.mapBump ) { - texture.type = texData.type; + create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - } + } - if (undefined !== texData.mipmaps) { + if ( m.mapNormal ) { - texture.mipmaps = texData.mipmaps; + create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - } + } - if (1 === texData.mipmapCount) { + if ( m.mapSpecular ) { - texture.minFilter = THREE.LinearFilter; + create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - } + } - texture.needsUpdate = true; + if ( m.mapAlpha ) { - if (onLoad) onLoad(texture, texData); + create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - }, onProgress, onError); + } + } - return texture; + // - } + if ( m.mapBumpScale ) { -}; + mpars.bumpScale = m.mapBumpScale; -// File:src/loaders/CompressedTextureLoader.js + } -/** - * @author mrdoob / http://mrdoob.com/ - * - * Abstract Base class to block based textures loader (dds, pvr, ...) - */ + if ( m.mapNormalFactor ) { -THREE.CompressedTextureLoader = function () { + mpars.normalScale = new THREE.Vector2( m.mapNormalFactor, m.mapNormalFactor ); - // override in sub classes - this._parser = null; + } -}; + var material = new THREE[ mtype ]( mpars ); + if ( m.DbgName !== undefined ) material.name = m.DbgName; -THREE.CompressedTextureLoader.prototype = { + return material; - constructor: THREE.CompressedTextureLoader, + }; - load: function (url, onLoad, onError) { + } )() - var scope = this; +}; - var images = []; +THREE.Loader.Handlers = { - var texture = new THREE.CompressedTexture(); - texture.image = images; + handlers: [], - var loader = new THREE.XHRLoader(); - loader.setResponseType('arraybuffer'); + add: function ( regex, loader ) { - if (url instanceof Array) { + this.handlers.push( regex, loader ); - var loaded = 0; + }, - var loadTexture = function (i) { + get: function ( file ) { - loader.load(url[i], function (buffer) { + for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) { - var texDatas = scope._parser(buffer, true); + var regex = this.handlers[ i ]; + var loader = this.handlers[ i + 1 ]; - images[i] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; + if ( regex.test( file ) ) { - loaded += 1; + return loader; - if (loaded === 6) { + } - if (texDatas.mipmapCount == 1) - texture.minFilter = THREE.LinearFilter; + } - texture.format = texDatas.format; - texture.needsUpdate = true; + return null; - if (onLoad) onLoad(texture); + } - } +}; - }); +// File:src/loaders/XHRLoader.js - }; +/** + * @author mrdoob / http://mrdoob.com/ + */ - for (var i = 0, il = url.length; i < il; ++i) { +THREE.XHRLoader = function ( manager ) { - loadTexture(i); + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - } +}; - } else { +THREE.XHRLoader.prototype = { - // compressed cubemap texture stored in a single DDS file + constructor: THREE.XHRLoader, - loader.load(url, function (buffer) { + load: function ( url, onLoad, onProgress, onError ) { - var texDatas = scope._parser(buffer, true); + var scope = this; - if (texDatas.isCubemap) { + var cached = THREE.Cache.get( url ); - var faces = texDatas.mipmaps.length / texDatas.mipmapCount; + if ( cached !== undefined ) { - for (var f = 0; f < faces; f++) { + if ( onLoad ) { - images[f] = {mipmaps: []}; + setTimeout( function () { - for (var i = 0; i < texDatas.mipmapCount; i++) { + onLoad( cached ); - 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; + }, 0 ); - } + } - } + return cached; - } else { + } - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; + var request = new XMLHttpRequest(); + request.open( 'GET', url, true ); - } + request.addEventListener( 'load', function ( event ) { - if (texDatas.mipmapCount === 1) { + THREE.Cache.add( url, this.response ); - texture.minFilter = THREE.LinearFilter; + if ( onLoad ) onLoad( this.response ); - } + scope.manager.itemEnd( url ); - texture.format = texDatas.format; - texture.needsUpdate = true; + }, false ); - if (onLoad) onLoad(texture); + if ( onProgress !== undefined ) { - }); + request.addEventListener( 'progress', function ( event ) { - } + onProgress( event ); - return texture; + }, false ); - } + } -}; + request.addEventListener( 'error', function ( event ) { -// File:src/materials/Material.js + if ( onError ) onError( event ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + scope.manager.itemError( url ); -THREE.Material = function () { + }, false ); - Object.defineProperty(this, 'id', {value: THREE.MaterialIdCount++}); + if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + if ( this.responseType !== undefined ) request.responseType = this.responseType; + if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; - this.uuid = THREE.Math.generateUUID(); + request.send( null ); - this.name = ''; - this.type = 'Material'; + scope.manager.itemStart( url ); - this.side = THREE.FrontSide; + return request; - this.opacity = 1; - this.transparent = false; + }, - this.blending = THREE.NormalBlending; + setResponseType: function ( value ) { - this.blendSrc = THREE.SrcAlphaFactor; - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; + this.responseType = value; - this.depthFunc = THREE.LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; + }, - this.colorWrite = true; + setCrossOrigin: function ( value ) { - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; + this.crossOrigin = value; - this.alphaTest = 0; + }, - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer + setWithCredentials: function ( value ) { - this.visible = true; + this.withCredentials = value; - this._needsUpdate = true; + } }; -THREE.Material.prototype = { +// File:src/loaders/ImageLoader.js - constructor: THREE.Material, +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ImageLoader.prototype = { + + constructor: THREE.ImageLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var cached = THREE.Cache.get( url ); + + if ( cached !== undefined ) { + + if ( onLoad ) { + + setTimeout( function () { + + onLoad( cached ); + + }, 0 ); + + } + + return cached; + + } + + var image = document.createElement( 'img' ); + + image.addEventListener( 'load', function ( event ) { + + THREE.Cache.add( url, this ); + + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); + + }, false ); + + if ( onProgress !== undefined ) { + + image.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + image.addEventListener( 'error', function ( event ) { + + if ( onError ) onError( event ); + + scope.manager.itemError( url ); + + }, false ); + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + scope.manager.itemStart( url ); + + image.src = url; + + return image; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +// File:src/loaders/JSONLoader.js + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.JSONLoader = function ( manager ) { + + if ( typeof manager === 'boolean' ) { + + console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); + manager = undefined; + + } + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + + this.withCredentials = false; + +}; + +THREE.JSONLoader.prototype = { + + constructor: THREE.JSONLoader, + + // Deprecated + + get statusDomElement () { + + if ( this._statusDomElement === undefined ) { + + this._statusDomElement = document.createElement( 'div' ); + + } + + console.warn( 'THREE.JSONLoader: .statusDomElement has been removed.' ); + return this._statusDomElement; + + }, + + load: function( url, onLoad, onProgress, onError ) { + + var scope = this; + + var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : THREE.Loader.prototype.extractUrlBase( url ); + + var loader = new THREE.XHRLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { + + var json = JSON.parse( text ); + var metadata = json.metadata; + + if ( metadata !== undefined ) { + + if ( metadata.type === 'object' ) { + + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; + + } + + if ( metadata.type === 'scene' ) { + + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); + return; + + } + + } + + var object = scope.parse( json, texturePath ); + onLoad( object.geometry, object.materials ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + + parse: function ( json, texturePath ) { + + var geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); + + parseSkin(); + parseMorphing( scale ); + parseAnimations(); + + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); + + function parseModel( scale ) { + + function isBitSet( value, position ) { + + return value & ( 1 << position ); + + } + + var i, j, fi, + + offset, zLength, + + colorIndex, normalIndex, uvIndex, materialIndex, + + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, + + vertex, face, faceA, faceB, hex, normal, + + uvLayer, uv, u, v, + + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, + + nUvLayers = 0; + + if ( json.uvs !== undefined ) { + + // disregard empty arrays + + for ( i = 0; i < json.uvs.length; i ++ ) { + + if ( json.uvs[ i ].length ) nUvLayers ++; + + } + + for ( i = 0; i < nUvLayers; i ++ ) { + + geometry.faceVertexUvs[ i ] = []; + + } + + } + + offset = 0; + zLength = vertices.length; + + while ( offset < zLength ) { + + vertex = new THREE.Vector3(); + + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; + + geometry.vertices.push( vertex ); + + } + + offset = 0; + zLength = faces.length; + + while ( offset < zLength ) { + + type = faces[ offset ++ ]; + + + 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); + + if ( isQuad ) { + + faceA = new THREE.Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; + + faceB = new THREE.Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; + + offset += 4; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i ++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + + for ( j = 0; j < 4; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + 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 ); + + } + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + faceB.normal.copy( faceA.normal ); + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < 4; i ++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < 4; i ++ ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); + + } + + } + + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); + + } else { + + face = new THREE.Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i ++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + + 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 ] ) ); + + } + + } + + geometry.faces.push( face ); + + } + + } + + }; + + function parseSkin() { + + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + + if ( json.skinWeights ) { + + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { + + 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; + + geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); + + } + + } + + if ( json.skinIndices ) { + + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + + 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; + + geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); + + } + + } + + geometry.bones = json.bones; + + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + + console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + + } + + }; + + function parseMorphing( scale ) { + + if ( json.morphTargets !== undefined ) { + + var i, l, v, vl, dstVertices, srcVertices; + + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + + 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; + + for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + + var vertex = new THREE.Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; + + dstVertices.push( vertex ); + + } + + } + + } + + if ( json.morphColors !== undefined ) { + + var i, l, c, cl, dstColors, srcColors, color; + + 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 = []; + + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors[ i ].colors; + + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); + + } + + } + + } + } + + function parseAnimations() { + + var outputAnimations = []; + + // parse old style Bone/Hierarchy animations + var animations = []; + if( json.animation !== undefined ) { + animations.push( json.animation ); + } + if( json.animations !== undefined ) { + if( json.animations.length ) { + animations = animations.concat( json.animations ); + } + else { + animations.push( json.animations ); + } + } + + for( var i = 0; i < animations.length; i ++ ) { + + var clip = THREE.AnimationClip.parseAnimation( animations[i], geometry.bones ); + if( clip ) outputAnimations.push( clip ); + + } + + // parse implicit morph animations + if( geometry.morphTargets ) { + + // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. + var morphAnimationClips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); + outputAnimations = outputAnimations.concat( morphAnimationClips ); + + } + + if( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + + }; + + if ( json.materials === undefined || json.materials.length === 0 ) { + + return { geometry: geometry }; + + } else { + + var materials = THREE.Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + + return { geometry: geometry, materials: materials }; + + } + + } + +}; + +// File:src/loaders/LoadingManager.js + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LoadingManager = function ( onLoad, onProgress, onError ) { + + var scope = this; + + var isLoading = false, itemsLoaded = 0, itemsTotal = 0; + + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; + + this.itemStart = function ( url ) { + + itemsTotal ++; + + if ( isLoading === false ) { + + if ( scope.onStart !== undefined ) { + + scope.onStart( url, itemsLoaded, itemsTotal ); + + } + + } + + isLoading = true; + + }; + + this.itemEnd = function ( url ) { + + itemsLoaded ++; + + if ( scope.onProgress !== undefined ) { + + scope.onProgress( url, itemsLoaded, itemsTotal ); + + } + + if ( itemsLoaded === itemsTotal ) { + + isLoading = false; + + if ( scope.onLoad !== undefined ) { + + scope.onLoad(); + + } + + } + + }; + + this.itemError = function ( url ) { + + if ( scope.onError !== undefined ) { + + scope.onError( url ); + + } + + }; + +}; + +THREE.DefaultLoadingManager = new THREE.LoadingManager(); + +// File:src/loaders/BufferGeometryLoader.js + +/** + * @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( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + }, onProgress, onError ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometry = new THREE.BufferGeometry(); + + var index = json.data.index; + + if ( index !== undefined ) { + + var typedArray = new self[ index.type ]( index.array ); + geometry.setIndex( new THREE.BufferAttribute( typedArray, 1 ) ); + + } + + var attributes = json.data.attributes; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + var typedArray = new self[ attribute.type ]( attribute.array ); + + geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) ); + + } + + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; + + if ( groups !== undefined ) { + + for ( var i = 0, n = groups.length; i !== n; ++ i ) { + + var group = groups[ i ]; + + geometry.addGroup( group.start, group.count ); + + } + + } + + var boundingSphere = json.data.boundingSphere; + + if ( boundingSphere !== undefined ) { + + var center = new THREE.Vector3(); + + if ( boundingSphere.center !== undefined ) { + + center.fromArray( boundingSphere.center ); + + } + + geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius ); + + } + + return geometry; + + } + +}; + +// File:src/loaders/MaterialLoader.js + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MaterialLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.textures = {}; + +}; + +THREE.MaterialLoader.prototype = { + + constructor: THREE.MaterialLoader, + + 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 ) ) ); + + }, onProgress, onError ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + setTextures: function ( value ) { + + this.textures = value; + + }, + + getTexture: function ( name ) { + + var textures = this.textures; + + if ( textures[ name ] === undefined ) { + + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + + } + + return textures[ name ]; + + }, + + parse: function ( json ) { + + var material = new THREE[ json.type ]; + material.uuid = json.uuid; + + if ( json.name !== undefined ) material.name = json.name; + 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.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + + // for PointsMaterial + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + + // maps + + if ( json.map !== undefined ) material.map = this.getTexture( json.map ); + + if ( json.alphaMap !== undefined ) { + + material.alphaMap = this.getTexture( json.alphaMap ); + material.transparent = true; + + } + + if ( json.bumpMap !== undefined ) material.bumpMap = this.getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + + if ( json.normalMap !== undefined ) material.normalMap = this.getTexture( json.normalMap ); + if ( json.normalScale ) material.normalScale = new THREE.Vector2( json.normalScale, json.normalScale ); + + if ( json.displacementMap !== undefined ) material.displacementMap = this.getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + + if ( json.specularMap !== undefined ) material.specularMap = this.getTexture( json.specularMap ); + + if ( json.envMap !== undefined ) { + + material.envMap = this.getTexture( json.envMap ); + material.combine = THREE.MultiplyOperation; + + } + + if ( json.reflectivity ) material.reflectivity = json.reflectivity; + + if ( json.lightMap !== undefined ) material.lightMap = this.getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + + if ( json.aoMap !== undefined ) material.aoMap = this.getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + + // MeshFaceMaterial + + 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; + + } + +}; + +// File:src/loaders/ObjectLoader.js + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ObjectLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.texturePath = ''; + +}; + +THREE.ObjectLoader.prototype = { + + constructor: THREE.ObjectLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + if ( this.texturePath === '' ) { + + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + + } + + 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 ); + + }, onProgress, onError ); + + }, + + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json, onLoad ) { + + var geometries = this.parseGeometries( json.geometries ); + + var images = this.parseImages( json.images, function () { + + if ( onLoad !== undefined ) onLoad( object ); + + } ); + + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); + + var object = this.parseObject( json.object, geometries, materials ); + + if( json.animations ) { + + object.animations = this.parseAnimations( json.animations ); + + } + + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); + + } + + 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': + case 'PlaneBufferGeometry': + + geometry = new THREE[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); + + break; + + case 'BoxGeometry': + case 'CubeGeometry': // backwards compatible + + geometry = new THREE.BoxGeometry( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); + + break; + + case 'CircleBufferGeometry': + + geometry = new THREE.CircleBufferGeometry( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'CircleGeometry': + + geometry = new THREE.CircleGeometry( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'CylinderGeometry': + + geometry = new THREE.CylinderGeometry( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'SphereGeometry': + + geometry = new THREE.SphereGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'SphereBufferGeometry': + + geometry = new THREE.SphereBufferGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'DodecahedronGeometry': + + geometry = new THREE.DodecahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'IcosahedronGeometry': + + geometry = new THREE.IcosahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'OctahedronGeometry': + + geometry = new THREE.OctahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'TetrahedronGeometry': + + geometry = new THREE.TetrahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'RingGeometry': + + geometry = new THREE.RingGeometry( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); + + 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 'TextGeometry': + + geometry = new THREE.TextGeometry( + data.text, + data.data + ); + + break; + + case 'BufferGeometry': + + geometry = bufferGeometryLoader.parse( data ); + + break; + + case 'Geometry': + + geometry = geometryLoader.parse( data.data, this.texturePath ).geometry; + + break; + + default: + + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); + + continue; + + } + + geometry.uuid = data.uuid; + + if ( data.name !== undefined ) geometry.name = data.name; + + geometries[ data.uuid ] = geometry; + + } + + } + + return geometries; + + }, + + parseMaterials: function ( json, textures ) { + + var materials = {}; + + if ( json !== undefined ) { + + var loader = new THREE.MaterialLoader(); + loader.setTextures( textures ); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var material = loader.parse( json[ i ] ); + materials[ material.uuid ] = material; + + } + + } + + return materials; + + }, + + parseAnimations: function ( json ) { + + var animations = []; + + for( var i = 0; i < json.length; i ++ ) { + + var clip = THREE.AnimationClip.parse( json[i] ); + + animations.push( clip ); + + } + + return animations; + + }, + + parseImages: function ( json, onLoad ) { + + var scope = this; + var images = {}; + + function loadImage( url ) { + + scope.manager.itemStart( url ); + + return loader.load( url, function () { + + scope.manager.itemEnd( url ); + + } ); + + } + + if ( json !== undefined && json.length > 0 ) { + + var manager = new THREE.LoadingManager( onLoad ); + + var loader = new THREE.ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + + images[ image.uuid ] = loadImage( path ); + + } + + } + + return images; + + }, + + parseTextures: function ( json, images ) { + + function parseConstant( value ) { + + if ( typeof( value ) === 'number' ) return value; + + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + + return THREE[ value ]; + + } + + var textures = {}; + + if ( json !== undefined ) { + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + + if ( data.image === undefined ) { + + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + + } + + if ( images[ data.image ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } + + var texture = new THREE.Texture( images[ data.image ] ); + texture.needsUpdate = true; + + texture.uuid = data.uuid; + + if ( data.name !== undefined ) texture.name = data.name; + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping ); + if ( data.offset !== undefined ) texture.offset = new THREE.Vector2( data.offset[ 0 ], data.offset[ 1 ] ); + if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + if ( Array.isArray( data.wrap ) ) { + + texture.wrapS = parseConstant( data.wrap[ 0 ] ); + texture.wrapT = parseConstant( data.wrap[ 1 ] ); + + } + + textures[ data.uuid ] = texture; + + } + + } + + return textures; + + }, + + parseObject: function () { + + var matrix = new THREE.Matrix4(); + + return function ( data, geometries, materials ) { + + var object; + + var getGeometry = function ( name ) { + + if ( geometries[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + + } + + return geometries[ name ]; + + }; + + var getMaterial = function ( name ) { + + if ( materials[ name ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', name ); + + } + + return materials[ name ]; + + }; + + 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, data.decay ); + + break; + + case 'SpotLight': + + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay ); + + break; + + case 'HemisphereLight': + + object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); + + break; + + case 'Mesh': + + object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'LOD': + + object = new THREE.LOD(); + + break; + + case 'Line': + + object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); + + break; + + case 'PointCloud': + case 'Points': + + object = new THREE.Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + + break; + + case 'Sprite': + + object = new THREE.Sprite( getMaterial( data.material ) ); + + break; + + case 'Group': + + object = new THREE.Group(); + + 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.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + + 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 ) ); + + } + + } + + if ( data.type === 'LOD' ) { + + var levels = data.levels; + + for ( var l = 0; l < levels.length; l ++ ) { + + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); + + if ( child !== undefined ) { + + object.addLevel( child, level.distance ); + + } + + } + + } + + return object; + + } + + }() + +}; + +// File:src/loaders/TextureLoader.js + +/** + * @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 ); + + } + + }, onProgress, onError ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +// File:src/loaders/BinaryTextureLoader.js + +/** + * @author Nikos M. / https://github.com/foo123/ + * + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + */ + +THREE.DataTextureLoader = THREE.BinaryTextureLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + + // override in sub classes + this._parser = null; + +}; + +THREE.BinaryTextureLoader.prototype = { + + constructor: THREE.BinaryTextureLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var texture = new THREE.DataTexture(); + + var loader = new THREE.XHRLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setResponseType( 'arraybuffer' ); + + loader.load( url, function ( buffer ) { + + var texData = scope._parser( buffer ); + + if ( ! texData ) return; + + if ( undefined !== texData.image ) { + + texture.image = texData.image; + + } else if ( undefined !== texData.data ) { + + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; + + } + + texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping; + texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; + + texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; + texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter; + + texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; + + if ( undefined !== texData.format ) { + + texture.format = texData.format; + + } + if ( undefined !== texData.type ) { + + texture.type = texData.type; + + } + + if ( undefined !== texData.mipmaps ) { + + texture.mipmaps = texData.mipmaps; + + } + + if ( 1 === texData.mipmapCount ) { + + texture.minFilter = THREE.LinearFilter; + + } + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture, texData ); + + }, onProgress, onError ); + + + return texture; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +// File:src/loaders/CompressedTextureLoader.js + +/** + * @author mrdoob / http://mrdoob.com/ + * + * Abstract Base class to block based textures loader (dds, pvr, ...) + */ + +THREE.CompressedTextureLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + + // override in sub classes + this._parser = null; + +}; + + +THREE.CompressedTextureLoader.prototype = { + + constructor: THREE.CompressedTextureLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var images = []; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + + var loader = new THREE.XHRLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setResponseType( 'arraybuffer' ); + + if ( Array.isArray( url ) ) { + + var loaded = 0; + + var loadTexture = function ( i ) { + + loader.load( url[ i ], function ( buffer ) { + + var texDatas = scope._parser( buffer, true ); + + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; + + loaded += 1; + + if ( loaded === 6 ) { + + if ( texDatas.mipmapCount === 1 ) + texture.minFilter = THREE.LinearFilter; + + texture.format = texDatas.format; + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } - get needsUpdate() { + }, onProgress, onError ); - return this._needsUpdate; + }; - }, + for ( var i = 0, il = url.length; i < il; ++ i ) { - set needsUpdate(value) { + loadTexture( i ); - if (value === true) this.update(); + } - this._needsUpdate = value; + } else { - }, + // compressed cubemap texture stored in a single DDS file - setValues: function (values) { + loader.load( url, function ( buffer ) { - if (values === undefined) return; + var texDatas = scope._parser( buffer, true ); - for (var key in values) { + if ( texDatas.isCubemap ) { - var newValue = values[key]; + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - if (newValue === undefined) { + for ( var f = 0; f < faces; f ++ ) { - THREE.warn("THREE.Material: '" + key + "' parameter is undefined."); - continue; + images[ f ] = { mipmaps : [] }; - } + for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { - if (key in this) { + 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; - var currentValue = this[key]; + } - if (currentValue instanceof THREE.Color) { + } - currentValue.set(newValue); + } else { - } else if (currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3) { + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - currentValue.copy(newValue); + } - } else if (key == 'overdraw') { + if ( texDatas.mipmapCount === 1 ) { - // ensure overdraw is backwards-compatable with legacy boolean type - this[key] = Number(newValue); + texture.minFilter = THREE.LinearFilter; - } else { + } - this[key] = newValue; + texture.format = texDatas.format; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); - } + }, onProgress, onError ); - } + } - }, + return texture; - toJSON: function () { + }, - // we will store all serialization data on 'data' - var data = {}; + setCrossOrigin: function ( value ) { - // add metadata - data.metadata = { - version: 4.4, - type: 'Material', - generator: 'Material.toJSON' - }; + this.crossOrigin = value; - // standard Material serialization - data.type = this.type; - data.uuid = this.uuid; - if (this.name !== '') data.name = this.name; + } - if (this.opacity < 1) data.opacity = this.opacity; - if (this.transparent !== false) data.transparent = this.transparent; - if (this.wireframe !== false) data.wireframe = this.wireframe; +}; + +// File:src/materials/Material.js + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - return data; +THREE.Material = function () { - }, + Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } ); - clone: function (material) { + this.uuid = THREE.Math.generateUUID(); - if (material === undefined) material = new THREE.Material(); + this.name = ''; + this.type = 'Material'; - material.name = this.name; + this.side = THREE.FrontSide; - material.side = this.side; + this.opacity = 1; + this.transparent = false; - material.opacity = this.opacity; - material.transparent = this.transparent; + this.blending = THREE.NormalBlending; - material.blending = this.blending; + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - material.blendSrc = this.blendSrc; - material.blendDst = this.blendDst; - material.blendEquation = this.blendEquation; - material.blendSrcAlpha = this.blendSrcAlpha; - material.blendDstAlpha = this.blendDstAlpha; - material.blendEquationAlpha = this.blendEquationAlpha; + this.depthFunc = THREE.LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; - material.depthFunc = this.depthFunc; - material.depthTest = this.depthTest; - material.depthWrite = this.depthWrite; + this.colorWrite = true; - material.polygonOffset = this.polygonOffset; - material.polygonOffsetFactor = this.polygonOffsetFactor; - material.polygonOffsetUnits = this.polygonOffsetUnits; + this.precision = null; // override the renderer's default precision for this material - material.alphaTest = this.alphaTest; + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - material.overdraw = this.overdraw; + this.alphaTest = 0; - material.visible = this.visible; + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - return material; + this.visible = true; - }, + this._needsUpdate = true; - update: function () { +}; - this.dispatchEvent({type: 'update'}); +THREE.Material.prototype = { - }, + constructor: THREE.Material, - dispose: function () { + get needsUpdate () { - this.dispatchEvent({type: 'dispose'}); + return this._needsUpdate; - } + }, + + set needsUpdate ( value ) { + + if ( value === true ) this.update(); + + this._needsUpdate = value; + + }, + + 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; + + } + + var currentValue = this[ key ]; + + if ( currentValue === undefined ) { + + console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); + continue; + + } + + 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-compatible with legacy boolean type + this[ key ] = Number( newValue ); + + } else { + + this[ key ] = newValue; + + } + + } + + }, + + toJSON: function ( meta ) { + + var data = { + metadata: { + version: 4.4, + type: 'Material', + generator: 'Material.toJSON' + } + }; + + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; + + if ( this.color instanceof THREE.Color ) data.color = this.color.getHex(); + if ( this.emissive instanceof THREE.Color ) data.emissive = this.emissive.getHex(); + if ( this.specular instanceof THREE.Color ) data.specular = this.specular.getHex(); + if ( this.shininess !== undefined ) data.shininess = this.shininess; + + if ( this.map instanceof THREE.Texture ) data.map = this.map.toJSON( meta ).uuid; + if ( this.alphaMap instanceof THREE.Texture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; + if ( this.lightMap instanceof THREE.Texture ) data.lightMap = this.lightMap.toJSON( meta ).uuid; + if ( this.bumpMap instanceof THREE.Texture ) { + + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; + + } + if ( this.normalMap instanceof THREE.Texture ) { + + data.normalMap = this.normalMap.toJSON( meta ).uuid; + data.normalScale = this.normalScale; // Removed for now, causes issue in editor ui.js + + } + if ( this.displacementMap instanceof THREE.Texture ) { + + data.displacementMap = this.displacementMap.toJSON( meta ).uuid; + data.displacementScale = this.displacementScale; + data.displacementBias = this.displacementBias; + + } + if ( this.specularMap instanceof THREE.Texture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; + if ( this.envMap instanceof THREE.Texture ) { + + data.envMap = this.envMap.toJSON( meta ).uuid; + data.reflectivity = this.reflectivity; // Scale behind envMap + + } + + if ( this.size !== undefined ) data.size = this.size; + if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + + if ( this.vertexColors !== undefined && this.vertexColors !== THREE.NoColors ) data.vertexColors = this.vertexColors; + if ( this.shading !== undefined && this.shading !== THREE.SmoothShading ) data.shading = this.shading; + if ( this.blending !== undefined && this.blending !== THREE.NormalBlending ) data.blending = this.blending; + if ( this.side !== undefined && this.side !== THREE.FrontSide ) data.side = this.side; + + if ( this.opacity < 1 ) data.opacity = this.opacity; + if ( this.transparent === true ) data.transparent = this.transparent; + if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; + if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; + + return data; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.name = source.name; + + this.side = source.side; + + this.opacity = source.opacity; + this.transparent = source.transparent; + + this.blending = source.blending; + + this.blendSrc = source.blendSrc; + this.blendDst = source.blendDst; + this.blendEquation = source.blendEquation; + this.blendSrcAlpha = source.blendSrcAlpha; + this.blendDstAlpha = source.blendDstAlpha; + this.blendEquationAlpha = source.blendEquationAlpha; + + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; + + this.precision = source.precision; + + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; + + this.alphaTest = source.alphaTest; + + this.overdraw = source.overdraw; + + this.visible = source.visible; + + return this; + + }, + + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + }, + + // Deprecated + + get wrapAround () { + + console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + + }, + + set wrapAround ( boolean ) { + + console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); + + }, + + get wrapRGB () { + + console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' ); + return new THREE.Color(); + + } }; -THREE.EventDispatcher.prototype.apply(THREE.Material.prototype); +THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); THREE.MaterialIdCount = 0; @@ -14798,46 +17089,44 @@ THREE.MaterialIdCount = 0; * } */ -THREE.LineBasicMaterial = function (parameters) { +THREE.LineBasicMaterial = function ( parameters ) { - THREE.Material.call(this); + THREE.Material.call( this ); - this.type = 'LineBasicMaterial'; + this.type = 'LineBasicMaterial'; - this.color = new THREE.Color(0xffffff); + this.color = new THREE.Color( 0xffffff ); - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - this.vertexColors = THREE.NoColors; + this.vertexColors = THREE.NoColors; - this.fog = true; + this.fog = true; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.LineBasicMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; -THREE.LineBasicMaterial.prototype.clone = function () { - - var material = new THREE.LineBasicMaterial(); +THREE.LineBasicMaterial.prototype.copy = function ( source ) { - THREE.Material.prototype.clone.call(this, material); + THREE.Material.prototype.copy.call( this, source ); - material.color.copy(this.color); + this.color.copy( source.color ); - material.linewidth = this.linewidth; - material.linecap = this.linecap; - material.linejoin = this.linejoin; + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; - material.vertexColors = this.vertexColors; + this.vertexColors = source.vertexColors; - material.fog = this.fog; + this.fog = source.fog; - return material; + return this; }; @@ -14866,50 +17155,48 @@ THREE.LineBasicMaterial.prototype.clone = function () { * } */ -THREE.LineDashedMaterial = function (parameters) { +THREE.LineDashedMaterial = function ( parameters ) { - THREE.Material.call(this); + THREE.Material.call( this ); - this.type = 'LineDashedMaterial'; + this.type = 'LineDashedMaterial'; - this.color = new THREE.Color(0xffffff); + this.color = new THREE.Color( 0xffffff ); - this.linewidth = 1; + this.linewidth = 1; - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; - this.vertexColors = false; + this.vertexColors = false; - this.fog = true; + this.fog = true; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.LineDashedMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial; -THREE.LineDashedMaterial.prototype.clone = function () { - - var material = new THREE.LineDashedMaterial(); - - THREE.Material.prototype.clone.call(this, material); +THREE.LineDashedMaterial.prototype.copy = function ( source ) { - material.color.copy(this.color); + THREE.Material.prototype.copy.call( this, source ); - material.linewidth = this.linewidth; + this.color.copy( source.color ); + + this.linewidth = source.linewidth; - material.scale = this.scale; - material.dashSize = this.dashSize; - material.gapSize = this.gapSize; + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; - material.vertexColors = this.vertexColors; + this.vertexColors = source.vertexColors; - material.fog = this.fog; + this.fog = source.fog; - return material; + return this; }; @@ -14924,6 +17211,9 @@ THREE.LineDashedMaterial.prototype.clone = function () { * opacity: , * map: new THREE.Texture( ), * + * aoMap: new THREE.Texture( ), + * aoMapIntensity: + * * specularMap: new THREE.Texture( ), * * alphaMap: new THREE.Texture( ), @@ -14950,93 +17240,84 @@ THREE.LineDashedMaterial.prototype.clone = function () { * } */ -THREE.MeshBasicMaterial = function (parameters) { +THREE.MeshBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); - THREE.Material.call(this); + this.type = 'MeshBasicMaterial'; - this.type = 'MeshBasicMaterial'; + this.color = new THREE.Color( 0xffffff ); // emissive - this.color = new THREE.Color(0xffffff); // emissive + this.map = null; - this.map = null; + this.aoMap = null; + this.aoMapIntensity = 1.0; - this.specularMap = null; + this.specularMap = null; - this.alphaMap = null; + this.alphaMap = null; - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - this.fog = true; + this.fog = true; - this.shading = THREE.SmoothShading; + this.shading = THREE.SmoothShading; - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - this.vertexColors = THREE.NoColors; + this.vertexColors = THREE.NoColors; - this.skinning = false; - this.morphTargets = false; + this.skinning = false; + this.morphTargets = false; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.MeshBasicMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; -THREE.MeshBasicMaterial.prototype.clone = function () { +THREE.MeshBasicMaterial.prototype.copy = function ( source ) { + + THREE.Material.prototype.copy.call( this, source ); - var material = new THREE.MeshBasicMaterial(); + this.color.copy( source.color ); - THREE.Material.prototype.clone.call(this, material); + this.map = source.map; - material.color.copy(this.color); + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - material.map = this.map; + this.specularMap = source.specularMap; - material.specularMap = this.specularMap; + this.alphaMap = source.alphaMap; - material.alphaMap = this.alphaMap; + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; + this.fog = source.fog; - material.fog = this.fog; + this.shading = source.shading; - material.shading = this.shading; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; + this.vertexColors = source.vertexColors; - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - - return material; - -}; - -THREE.MeshBasicMaterial.prototype.toJSON = function () { - - var data = THREE.Material.prototype.toJSON.call(this); - - data.color = this.color.getHex(); - if (this.vertexColors !== THREE.NoColors) data.vertexColors = this.vertexColors; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; - if (this.side !== THREE.FrontSide) data.side = this.side; - - return data; + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + + return this; }; @@ -15062,7 +17343,6 @@ THREE.MeshBasicMaterial.prototype.toJSON = function () { * reflectivity: , * refractionRatio: , * - * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , @@ -15080,99 +17360,78 @@ THREE.MeshBasicMaterial.prototype.toJSON = function () { * } */ -THREE.MeshLambertMaterial = function (parameters) { - - THREE.Material.call(this); +THREE.MeshLambertMaterial = function ( parameters ) { - this.type = 'MeshLambertMaterial'; + THREE.Material.call( this ); - this.color = new THREE.Color(0xffffff); // diffuse - this.emissive = new THREE.Color(0x000000); + this.type = 'MeshLambertMaterial'; - this.map = null; + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); - this.specularMap = null; + this.map = null; - this.alphaMap = null; + this.specularMap = null; - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + this.alphaMap = null; - this.fog = true; + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - this.shading = THREE.SmoothShading; + this.fog = true; - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - this.vertexColors = THREE.NoColors; + this.vertexColors = THREE.NoColors; - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.MeshLambertMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial; -THREE.MeshLambertMaterial.prototype.clone = function () { - - var material = new THREE.MeshLambertMaterial(); - - THREE.Material.prototype.clone.call(this, material); - - material.color.copy(this.color); - material.emissive.copy(this.emissive); - - material.map = this.map; - - material.specularMap = this.specularMap; - - material.alphaMap = this.alphaMap; +THREE.MeshLambertMaterial.prototype.copy = function ( source ) { - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; + THREE.Material.prototype.copy.call( this, source ); - material.fog = this.fog; + this.color.copy( source.color ); + this.emissive.copy( source.emissive ); - material.shading = this.shading; + this.map = source.map; - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; + this.specularMap = source.specularMap; - material.vertexColors = this.vertexColors; + this.alphaMap = source.alphaMap; - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - return material; + this.fog = source.fog; -}; - -THREE.MeshLambertMaterial.prototype.toJSON = function () { + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - var data = THREE.Material.prototype.toJSON.call(this); + this.vertexColors = source.vertexColors; - data.color = this.color.getHex(); - data.emissive = this.emissive.getHex(); - if (this.vertexColors !== THREE.NoColors) data.vertexColors = this.vertexColors; - if (this.shading !== THREE.SmoothShading) data.shading = this.shading; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; - if (this.side !== THREE.FrontSide) data.side = this.side; + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - return data; + return this; }; @@ -15197,12 +17456,18 @@ THREE.MeshLambertMaterial.prototype.toJSON = function () { * aoMap: new THREE.Texture( ), * aoMapIntensity: * + * emissiveMap: new THREE.Texture( ), + * * bumpMap: new THREE.Texture( ), * bumpScale: , * * normalMap: new THREE.Texture( ), * normalScale: , * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * * specularMap: new THREE.Texture( ), * * alphaMap: new THREE.Texture( ), @@ -15230,134 +17495,126 @@ THREE.MeshLambertMaterial.prototype.toJSON = function () { * } */ -THREE.MeshPhongMaterial = function (parameters) { +THREE.MeshPhongMaterial = function ( parameters ) { - THREE.Material.call(this); + THREE.Material.call( this ); - this.type = 'MeshPhongMaterial'; + this.type = 'MeshPhongMaterial'; - this.color = new THREE.Color(0xffffff); // diffuse - this.emissive = new THREE.Color(0x000000); - this.specular = new THREE.Color(0x111111); - this.shininess = 30; + this.color = new THREE.Color( 0xffffff ); // diffuse + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0x111111 ); + this.shininess = 30; - this.metal = false; + this.metal = false; - this.map = null; + this.map = null; - this.lightMap = null; - this.lightMapIntensity = 1.0; + this.lightMap = null; + this.lightMapIntensity = 1.0; - this.aoMap = null; - this.aoMapIntensity = 1.0; + this.aoMap = null; + this.aoMapIntensity = 1.0; - this.bumpMap = null; - this.bumpScale = 1; + this.emissiveMap = null; - this.normalMap = null; - this.normalScale = new THREE.Vector2(1, 1); + this.bumpMap = null; + this.bumpScale = 1; - this.specularMap = null; + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); - this.alphaMap = null; + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + this.specularMap = null; - this.fog = true; + this.alphaMap = null; - this.shading = THREE.SmoothShading; + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + this.fog = true; - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues(parameters); - -}; + this.shading = THREE.SmoothShading; -THREE.MeshPhongMaterial.prototype = Object.create(THREE.Material.prototype); -THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; -THREE.MeshPhongMaterial.prototype.clone = function () { + this.vertexColors = THREE.NoColors; - var material = new THREE.MeshPhongMaterial(); + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - THREE.Material.prototype.clone.call(this, material); + this.setValues( parameters ); - material.color.copy(this.color); - material.emissive.copy(this.emissive); - material.specular.copy(this.specular); - material.shininess = this.shininess; +}; - material.metal = this.metal; +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; - material.map = this.map; +THREE.MeshPhongMaterial.prototype.copy = function ( source ) { - material.lightMap = this.lightMap; - material.lightMapIntensity = this.lightMapIntensity; + THREE.Material.prototype.copy.call( this, source ); - material.aoMap = this.aoMap; - material.aoMapIntensity = this.aoMapIntensity; + this.color.copy( source.color ); + this.emissive.copy( source.emissive ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; + this.metal = source.metal; - material.normalMap = this.normalMap; - material.normalScale.copy(this.normalScale); + this.map = source.map; - material.specularMap = this.specularMap; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - material.alphaMap = this.alphaMap; + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; + this.emissiveMap = source.emissiveMap; - material.fog = this.fog; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - material.shading = this.shading; + this.normalMap = source.normalMap; + this.normalScale.copy( source.normalScale ); - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - material.vertexColors = this.vertexColors; + this.specularMap = source.specularMap; - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + this.alphaMap = source.alphaMap; - return material; + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; -}; + this.fog = source.fog; -THREE.MeshPhongMaterial.prototype.toJSON = function () { + this.shading = source.shading; - var data = THREE.Material.prototype.toJSON.call(this); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - data.color = this.color.getHex(); - data.emissive = this.emissive.getHex(); - data.specular = this.specular.getHex(); - data.shininess = this.shininess; + this.vertexColors = source.vertexColors; - if (this.vertexColors !== THREE.NoColors) data.vertexColors = this.vertexColors; - if (this.shading !== THREE.SmoothShading) data.shading = this.shading; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; - if (this.side !== THREE.FrontSide) data.side = this.side; + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - return data; + return this; }; @@ -15379,44 +17636,31 @@ THREE.MeshPhongMaterial.prototype.toJSON = function () { * } */ -THREE.MeshDepthMaterial = function (parameters) { +THREE.MeshDepthMaterial = function ( parameters ) { - THREE.Material.call(this); + THREE.Material.call( this ); - this.type = 'MeshDepthMaterial'; + this.type = 'MeshDepthMaterial'; - this.morphTargets = false; - this.wireframe = false; - this.wireframeLinewidth = 1; + this.morphTargets = false; + this.wireframe = false; + this.wireframeLinewidth = 1; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.MeshDepthMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial; -THREE.MeshDepthMaterial.prototype.clone = function () { - - var material = new THREE.MeshDepthMaterial(); - - THREE.Material.prototype.clone.call(this, material); - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; +THREE.MeshDepthMaterial.prototype.copy = function ( source ) { -}; - -THREE.MeshDepthMaterial.prototype.toJSON = function () { + THREE.Material.prototype.copy.call( this, source ); - var data = THREE.Material.prototype.toJSON.call(this); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; - if (this.side !== THREE.FrontSide) data.side = this.side; - - return data; + return this; }; @@ -15438,66 +17682,105 @@ THREE.MeshDepthMaterial.prototype.toJSON = function () { * } */ -THREE.MeshNormalMaterial = function (parameters) { +THREE.MeshNormalMaterial = function ( parameters ) { - THREE.Material.call(this, parameters); + THREE.Material.call( this, parameters ); - this.type = 'MeshNormalMaterial'; + this.type = 'MeshNormalMaterial'; - this.wireframe = false; - this.wireframeLinewidth = 1; + this.wireframe = false; + this.wireframeLinewidth = 1; - this.morphTargets = false; + this.morphTargets = false; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.MeshNormalMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial; -THREE.MeshNormalMaterial.prototype.clone = function () { - - var material = new THREE.MeshNormalMaterial(); +THREE.MeshNormalMaterial.prototype.copy = function ( source ) { - THREE.Material.prototype.clone.call(this, material); + THREE.Material.prototype.copy.call( this, source ); - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - return material; + return this; }; -THREE.MeshNormalMaterial.prototype.toJSON = function () { +// File:src/materials/MultiMaterial.js + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MultiMaterial = function ( materials ) { + + this.uuid = THREE.Math.generateUUID(); - var data = THREE.Material.prototype.toJSON.call(this); + this.type = 'MultiMaterial'; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; - if (this.side !== THREE.FrontSide) data.side = this.side; + this.materials = materials instanceof Array ? materials : []; - return data; + this.visible = true; }; -// File:src/materials/MeshFaceMaterial.js +THREE.MultiMaterial.prototype = { -/** - * @author mrdoob / http://mrdoob.com/ - */ + constructor: THREE.MultiMaterial, + + toJSON: function () { + + var output = { + metadata: { + version: 4.2, + type: 'material', + generator: 'MaterialExporter' + }, + uuid: this.uuid, + type: this.type, + materials: [] + }; + + for ( var i = 0, l = this.materials.length; i < l; i ++ ) { -THREE.MeshFaceMaterial = function (materials) { + output.materials.push( this.materials[ i ].toJSON() ); - THREE.error('THREE.MeshFaceMaterial has been removed.'); + } - var material = materials !== undefined ? materials[0] : new THREE.MeshBasicMaterial(); - material.materials = []; // temporal workaround + output.visible = this.visible; - return material; + return output; + + }, + + clone: function () { + + var material = new this.constructor(); + + for ( var i = 0; i < this.materials.length; i ++ ) { + + material.materials.push( this.materials[ i ].clone() ); + + } + + material.visible = this.visible; + + return material; + + } }; -// File:src/materials/PointCloudMaterial.js +// backwards compatibility + +THREE.MeshFaceMaterial = THREE.MultiMaterial; + +// File:src/materials/PointsMaterial.js /** * @author mrdoob / http://mrdoob.com/ @@ -15521,79 +17804,69 @@ THREE.MeshFaceMaterial = function (materials) { * } */ -THREE.PointCloudMaterial = function (parameters) { +THREE.PointsMaterial = function ( parameters ) { - THREE.Material.call(this); + THREE.Material.call( this ); - this.type = 'PointCloudMaterial'; + this.type = 'PointsMaterial'; - this.color = new THREE.Color(0xffffff); + this.color = new THREE.Color( 0xffffff ); - this.map = null; + this.map = null; - this.size = 1; - this.sizeAttenuation = true; + this.size = 1; + this.sizeAttenuation = true; - this.vertexColors = THREE.NoColors; + this.vertexColors = THREE.NoColors; - this.fog = true; + this.fog = true; - this.setValues(parameters); + this.setValues( parameters ); }; -THREE.PointCloudMaterial.prototype = Object.create(THREE.Material.prototype); -THREE.PointCloudMaterial.prototype.constructor = THREE.PointCloudMaterial; +THREE.PointsMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.PointsMaterial.prototype.constructor = THREE.PointsMaterial; -THREE.PointCloudMaterial.prototype.clone = function () { +THREE.PointsMaterial.prototype.copy = function ( source ) { - var material = new THREE.PointCloudMaterial(); + THREE.Material.prototype.copy.call( this, source ); - THREE.Material.prototype.clone.call(this, material); + this.color.copy( source.color ); - material.color.copy(this.color); + this.map = source.map; - material.map = this.map; + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; - material.size = this.size; - material.sizeAttenuation = this.sizeAttenuation; + this.vertexColors = source.vertexColors; - material.vertexColors = this.vertexColors; + this.fog = source.fog; - material.fog = this.fog; - - return material; + return this; }; -THREE.PointCloudMaterial.prototype.toJSON = function () { - - var data = THREE.Material.prototype.toJSON.call(this); - - data.size = this.size; - data.sizeAttenuation = this.sizeAttenuation; - data.color = this.color.getHex(); +// backwards compatibility - if (this.vertexColors !== THREE.NoColors) data.vertexColors = this.vertexColors; - if (this.blending !== THREE.NormalBlending) data.blending = this.blending; +THREE.PointCloudMaterial = function ( parameters ) { - return data; + console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); + return new THREE.PointsMaterial( parameters ); }; -// backwards compatibility - -THREE.ParticleBasicMaterial = function (parameters) { +THREE.ParticleBasicMaterial = function ( parameters ) { - THREE.warn('THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.'); - return new THREE.PointCloudMaterial(parameters); + console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); + return new THREE.PointsMaterial( parameters ); }; -THREE.ParticleSystemMaterial = function (parameters) { +THREE.ParticleSystemMaterial = function ( parameters ) { - THREE.warn('THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.'); - return new THREE.PointCloudMaterial(parameters); + console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); + return new THREE.PointsMaterial( parameters ); }; @@ -15629,97 +17902,109 @@ THREE.ParticleSystemMaterial = function (parameters) { * } */ -THREE.ShaderMaterial = function (parameters) { +THREE.ShaderMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.type = 'ShaderMaterial'; + + this.defines = {}; + this.uniforms = {}; + + 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; - THREE.Material.call(this); + this.wireframe = false; + this.wireframeLinewidth = 1; - this.type = 'ShaderMaterial'; + this.fog = false; // set to use scene fog - this.defines = {}; - this.uniforms = {}; - this.attributes = null; + this.lights = false; // set to use scene lights - 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.vertexColors = THREE.NoColors; // set to use "color" attribute stream - this.shading = THREE.SmoothShading; + this.skinning = false; // set to use skinning attribute streams - this.linewidth = 1; + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals - this.wireframe = false; - this.wireframeLinewidth = 1; + this.derivatives = false; // set to use derivatives - this.fog = false; // set to use scene fog + // 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 ] + }; - this.lights = false; // set to use scene lights + this.index0AttributeName = undefined; - this.vertexColors = THREE.NoColors; // set to use "color" attribute stream + if ( parameters !== undefined ) { - this.skinning = false; // set to use skinning attribute streams + if ( parameters.attributes !== undefined ) { - this.morphTargets = false; // set to use morph targets - this.morphNormals = false; // set to use morph normals + console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); - // 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] - }; + } - this.index0AttributeName = undefined; + this.setValues( parameters ); - this.setValues(parameters); + } }; -THREE.ShaderMaterial.prototype = Object.create(THREE.Material.prototype); +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial; -THREE.ShaderMaterial.prototype.clone = function (material) { +THREE.ShaderMaterial.prototype.copy = function ( source ) { - if (material === undefined) material = new THREE.ShaderMaterial(); + THREE.Material.prototype.copy.call( this, source ); - THREE.Material.prototype.clone.call(this, material); + this.fragmentShader = source.fragmentShader; + this.vertexShader = source.vertexShader; - material.fragmentShader = this.fragmentShader; - material.vertexShader = this.vertexShader; + this.uniforms = THREE.UniformsUtils.clone( source.uniforms ); - material.uniforms = THREE.UniformsUtils.clone(this.uniforms); + this.attributes = source.attributes; + this.defines = source.defines; - material.attributes = this.attributes; - material.defines = this.defines; + this.shading = source.shading; - material.shading = this.shading; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; + this.fog = source.fog; - material.fog = this.fog; + this.lights = source.lights; - material.lights = this.lights; + this.vertexColors = source.vertexColors; - material.vertexColors = this.vertexColors; + this.skinning = source.skinning; - material.skinning = this.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; + this.derivatives = source.derivatives; - return material; + return this; }; -THREE.ShaderMaterial.prototype.toJSON = function () { +THREE.ShaderMaterial.prototype.toJSON = function ( meta ) { - var data = THREE.Material.prototype.toJSON.call(this); + var data = THREE.Material.prototype.toJSON.call( this, meta ); - data.uniforms = this.uniforms; - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; + data.uniforms = this.uniforms; + data.attributes = this.attributes; + data.vertexShader = this.vertexShader; + data.fragmentShader = this.fragmentShader; - return data; + return data; }; @@ -15729,341 +18014,476 @@ THREE.ShaderMaterial.prototype.toJSON = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.RawShaderMaterial = function (parameters) { +THREE.RawShaderMaterial = function ( parameters ) { + + THREE.ShaderMaterial.call( this, parameters ); + + this.type = 'RawShaderMaterial'; + +}; + +THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); +THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial; +// File:src/materials/SpriteMaterial.js + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: + * } + */ + +THREE.SpriteMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.type = 'SpriteMaterial'; + + this.color = new THREE.Color( 0xffffff ); + this.map = null; + + this.rotation = 0; + + this.fog = false; + + // set parameters + + this.setValues( parameters ); + +}; + +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); +THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; + +THREE.SpriteMaterial.prototype.copy = function ( source ) { + + THREE.Material.prototype.copy.call( this, source ); + + this.color.copy( source.color ); + this.map = source.map; + + this.rotation = source.rotation; + + this.fog = source.fog; + + return this; + +}; + +// File:src/textures/Texture.js + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } ); + + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + this.sourceFile = ''; + + this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; + this.mipmaps = []; + + this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; + + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + + 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 ); + + 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.version = 0; + this.onUpdate = null; + +}; + +THREE.Texture.DEFAULT_IMAGE = undefined; +THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; + +THREE.Texture.prototype = { + + constructor: THREE.Texture, + + set needsUpdate ( value ) { + + if ( value === true ) this.version ++; + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + }, + + copy: function ( source ) { + + this.image = source.image; + this.mipmaps = source.mipmaps.slice( 0 ); + + this.mapping = source.mapping; + + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; + + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; + + this.anisotropy = source.anisotropy; + + this.format = source.format; + this.type = source.type; - THREE.ShaderMaterial.call(this, parameters); + this.offset.copy( source.offset ); + this.repeat.copy( source.repeat ); - this.type = 'RawShaderMaterial'; + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; -}; + return this; -THREE.RawShaderMaterial.prototype = Object.create(THREE.ShaderMaterial.prototype); -THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial; + }, -THREE.RawShaderMaterial.prototype.clone = function () { + toJSON: function ( meta ) { - var material = new THREE.RawShaderMaterial(); + if ( meta.textures[ this.uuid ] !== undefined ) { - THREE.ShaderMaterial.prototype.clone.call(this, material); + return meta.textures[ this.uuid ]; - return material; + } -}; + function getDataURL( image ) { -// File:src/materials/SpriteMaterial.js + var canvas; -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2(), - * - * fog: - * } - */ + if ( image.toDataURL !== undefined ) { -THREE.SpriteMaterial = function (parameters) { + canvas = image; - THREE.Material.call(this); + } else { - this.type = 'SpriteMaterial'; + canvas = document.createElement( 'canvas' ); + canvas.width = image.width; + canvas.height = image.height; - this.color = new THREE.Color(0xffffff); - this.map = null; + canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height ); - this.rotation = 0; + } - this.fog = false; + if ( canvas.width > 2048 || canvas.height > 2048 ) { - // set parameters + return canvas.toDataURL( 'image/jpeg', 0.6 ); - this.setValues(parameters); + } else { -}; + return canvas.toDataURL( 'image/png' ); -THREE.SpriteMaterial.prototype = Object.create(THREE.Material.prototype); -THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; + } -THREE.SpriteMaterial.prototype.clone = function () { + } - var material = new THREE.SpriteMaterial(); + var output = { + metadata: { + version: 4.4, + type: 'Texture', + generator: 'Texture.toJSON' + }, - THREE.Material.prototype.clone.call(this, material); + uuid: this.uuid, + name: this.name, - material.color.copy(this.color); - material.map = this.map; + mapping: this.mapping, - material.rotation = this.rotation; + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + wrap: [ this.wrapS, this.wrapT ], - material.fog = this.fog; + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy + }; - return material; + if ( this.image !== undefined ) { -}; + // TODO: Move to THREE.Image -THREE.SpriteMaterial.prototype.toJSON = function () { + var image = this.image; - var data = THREE.Material.prototype.toJSON.call(this); + if ( image.uuid === undefined ) { - data.color = this.color.getHex(); + image.uuid = THREE.Math.generateUUID(); // UGH - return data; + } -}; + if ( meta.images[ image.uuid ] === undefined ) { -// File:src/textures/Texture.js + meta.images[ image.uuid ] = { + uuid: image.uuid, + url: getDataURL( image ) + }; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ + } -THREE.Texture = function (image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) { + output.image = image.uuid; - Object.defineProperty(this, 'id', {value: THREE.TextureIdCount++}); + } - this.uuid = THREE.Math.generateUUID(); + meta.textures[ this.uuid ] = output; - this.name = ''; - this.sourceFile = ''; + return output; - this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; - this.mipmaps = []; + }, - this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; + dispose: function () { - this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + this.dispatchEvent( { type: 'dispose' } ); - this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + }, - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + transformUv: function ( uv ) { - this.format = format !== undefined ? format : THREE.RGBAFormat; - this.type = type !== undefined ? type : THREE.UnsignedByteType; + if ( this.mapping !== THREE.UVMapping ) return; - this.offset = new THREE.Vector2(0, 0); - this.repeat = new THREE.Vector2(1, 1); + uv.multiply( this.repeat ); + uv.add( this.offset ); - 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) + if ( uv.x < 0 || uv.x > 1 ) { - this._needsUpdate = false; - this.onUpdate = null; + switch ( this.wrapS ) { -}; + case THREE.RepeatWrapping: -THREE.Texture.DEFAULT_IMAGE = undefined; -THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; + uv.x = uv.x - Math.floor( uv.x ); + break; -THREE.Texture.prototype = { + case THREE.ClampToEdgeWrapping: - constructor: THREE.Texture, + uv.x = uv.x < 0 ? 0 : 1; + break; - get needsUpdate() { + case THREE.MirroredRepeatWrapping: - return this._needsUpdate; + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - }, + uv.x = Math.ceil( uv.x ) - uv.x; - set needsUpdate(value) { + } else { - if (value === true) this.update(); + uv.x = uv.x - Math.floor( uv.x ); - this._needsUpdate = value; + } + break; - }, + } - clone: function (texture) { + } - if (texture === undefined) texture = new THREE.Texture(); + if ( uv.y < 0 || uv.y > 1 ) { - texture.image = this.image; - texture.mipmaps = this.mipmaps.slice(0); + switch ( this.wrapT ) { - texture.mapping = this.mapping; + case THREE.RepeatWrapping: - texture.wrapS = this.wrapS; - texture.wrapT = this.wrapT; + uv.y = uv.y - Math.floor( uv.y ); + break; - texture.magFilter = this.magFilter; - texture.minFilter = this.minFilter; + case THREE.ClampToEdgeWrapping: - texture.anisotropy = this.anisotropy; + uv.y = uv.y < 0 ? 0 : 1; + break; - texture.format = this.format; - texture.type = this.type; + case THREE.MirroredRepeatWrapping: - texture.offset.copy(this.offset); - texture.repeat.copy(this.repeat); + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - texture.generateMipmaps = this.generateMipmaps; - texture.premultiplyAlpha = this.premultiplyAlpha; - texture.flipY = this.flipY; - texture.unpackAlignment = this.unpackAlignment; + uv.y = Math.ceil( uv.y ) - uv.y; - return texture; + } else { - }, + uv.y = uv.y - Math.floor( uv.y ); - update: function () { + } + break; - this.dispatchEvent({type: 'update'}); + } - }, + } - dispose: function () { + if ( this.flipY ) { - this.dispatchEvent({type: 'dispose'}); + uv.y = 1 - uv.y; - } + } + + } }; -THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype); +THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); THREE.TextureIdCount = 0; -// File:src/textures/CubeTexture.js +// File:src/textures/CanvasTexture.js /** * @author mrdoob / http://mrdoob.com/ */ -THREE.CubeTexture = function (images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) { - - mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; +THREE.CanvasTexture = function ( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - THREE.Texture.call(this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); + THREE.Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - this.images = images; + this.needsUpdate = true; }; -THREE.CubeTexture.prototype = Object.create(THREE.Texture.prototype); -THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; +THREE.CanvasTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CanvasTexture.prototype.constructor = THREE.CanvasTexture; + +// File:src/textures/CubeTexture.js -THREE.CubeTexture.clone = function (texture) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - if (texture === undefined) texture = new THREE.CubeTexture(); +THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - THREE.Texture.prototype.clone.call(this, texture); + mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; - texture.images = this.images; + THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - return texture; + this.images = images; + this.flipY = false; }; +THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype ); +THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; + +THREE.CubeTexture.prototype.copy = function ( source ) { + + THREE.Texture.prototype.copy.call( this, source ); + + this.images = source.images; + + return this; + +}; // File:src/textures/CompressedTexture.js /** * @author alteredq / http://alteredqualia.com/ */ -THREE.CompressedTexture = function (mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy) { +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - THREE.Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - this.image = {width: width, height: height}; - this.mipmaps = mipmaps; + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) - this.flipY = false; + this.flipY = false; - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files - this.generateMipmaps = false; + this.generateMipmaps = false; }; -THREE.CompressedTexture.prototype = Object.create(THREE.Texture.prototype); +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture; -THREE.CompressedTexture.prototype.clone = function () { - - var texture = new THREE.CompressedTexture(); - - THREE.Texture.prototype.clone.call(this, texture); - - return texture; - -}; - // File:src/textures/DataTexture.js /** * @author alteredq / http://alteredqualia.com/ */ -THREE.DataTexture = function (data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy) { +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - THREE.Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); + this.image = { data: data, width: width, height: height }; - this.image = {data: data, width: width, height: height}; + this.magFilter = magFilter !== undefined ? magFilter : THREE.NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; }; -THREE.DataTexture.prototype = Object.create(THREE.Texture.prototype); +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.DataTexture.prototype.constructor = THREE.DataTexture; -THREE.DataTexture.prototype.clone = function () { - - var texture = new THREE.DataTexture(); - - THREE.Texture.prototype.clone.call(this, texture); - - return texture; - -}; - // File:src/textures/VideoTexture.js /** * @author mrdoob / http://mrdoob.com/ */ -THREE.VideoTexture = function (video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) { +THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - THREE.Texture.call(this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); + THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - this.generateMipmaps = false; + this.generateMipmaps = false; - var scope = this; + var scope = this; - var update = function () { + var update = function () { - requestAnimationFrame(update); + requestAnimationFrame( update ); - if (video.readyState === video.HAVE_ENOUGH_DATA) { + if ( video.readyState === video.HAVE_ENOUGH_DATA ) { - scope.needsUpdate = true; + scope.needsUpdate = true; - } + } - }; + }; - update(); + update(); }; -THREE.VideoTexture.prototype = Object.create(THREE.Texture.prototype); +THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; // File:src/textures/DepthTexture.js @@ -16072,30 +18492,30 @@ THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; * @author Marius Kintel / https://github.com/kintel */ -THREE.DepthTexture = function (width, height, hasStencil) { +THREE.DepthTexture = function ( width, height, hasStencil ) { - var format = hasStencil ? THREE.DepthStencilFormat : THREE.DepthFormat; - var type = hasStencil ? THREE.UnsignedInt24_8Type : THREE.UnsignedIntType; + var format = hasStencil ? THREE.DepthStencilFormat : THREE.DepthFormat; + var type = hasStencil ? THREE.UnsignedInt24_8Type : THREE.UnsignedIntType; - THREE.Texture.call(this, null, THREE.Texture.DEFAULT_MAPPING, THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.NearestFilter, format, type); + THREE.Texture.call( this, null, THREE.Texture.DEFAULT_MAPPING, THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.NearestFilter, format, type ); - this.width = width; - this.height = height; + this.width = width; + this.height = height; }; -THREE.DepthTexture.prototype = Object.create(THREE.Texture.prototype); +THREE.DepthTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.DepthTexture.prototype.clone = function () { - var texture = new THREE.DepthTexture(); + var texture = new THREE.DepthTexture(); - THREE.Texture.prototype.clone.call(this, texture); + THREE.Texture.prototype.clone.call( this, texture ); - texture.width = this.width; - texture.height = this.height; + texture.width = this.width; + texture.height = this.height; - return texture; + return texture; }; @@ -16107,199 +18527,182 @@ THREE.DepthTexture.prototype.clone = function () { THREE.Group = function () { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Group'; + this.type = 'Group'; }; -THREE.Group.prototype = Object.create(THREE.Object3D.prototype); +THREE.Group.prototype = Object.create( THREE.Object3D.prototype ); THREE.Group.prototype.constructor = THREE.Group; - -// File:src/objects/PointCloud.js +// File:src/objects/Points.js /** * @author alteredq / http://alteredqualia.com/ */ -THREE.PointCloud = function (geometry, material) { +THREE.Points = function ( geometry, material ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'PointCloud'; + this.type = 'Points'; - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.PointCloudMaterial({color: Math.random() * 0xffffff}); + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.PointsMaterial( { color: Math.random() * 0xffffff } ); }; -THREE.PointCloud.prototype = Object.create(THREE.Object3D.prototype); -THREE.PointCloud.prototype.constructor = THREE.PointCloud; - -THREE.PointCloud.prototype.raycast = ( function () { +THREE.Points.prototype = Object.create( THREE.Object3D.prototype ); +THREE.Points.prototype.constructor = THREE.Points; - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); +THREE.Points.prototype.raycast = ( function () { - return function (raycaster, intersects) { + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); - var object = this; - var geometry = object.geometry; - var threshold = raycaster.params.PointCloud.threshold; + return function raycast( raycaster, intersects ) { - inverseMatrix.getInverse(this.matrixWorld); - ray.copy(raycaster.ray).applyMatrix4(inverseMatrix); + var object = this; + var geometry = object.geometry; + var threshold = raycaster.params.Points.threshold; - if (geometry.boundingBox !== null) { + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - if (ray.isIntersectionBox(geometry.boundingBox) === false) { + if ( geometry.boundingBox !== null ) { - return; + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - } + return; - } + } - var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var position = new THREE.Vector3(); + } - var testPoint = function (point, index) { + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var localThresholdSq = localThreshold * localThreshold; + var position = new THREE.Vector3(); - var rayPointDistance = ray.distanceToPoint(point); + function testPoint( point, index ) { - if (rayPointDistance < localThreshold) { + var rayPointDistanceSq = ray.distanceSqToPoint( point ); - var intersectPoint = ray.closestPointToPoint(point); - intersectPoint.applyMatrix4(object.matrixWorld); + if ( rayPointDistanceSq < localThresholdSq ) { - var distance = raycaster.ray.origin.distanceTo(intersectPoint); + var intersectPoint = ray.closestPointToPoint( point ); + intersectPoint.applyMatrix4( object.matrixWorld ); - intersects.push({ + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - distance: distance, - distanceToRay: rayPointDistance, - point: intersectPoint.clone(), - index: index, - face: null, - object: object + if ( distance < raycaster.near || distance > raycaster.far ) return; - }); + intersects.push( { - } + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint.clone(), + index: index, + face: null, + object: object - }; + } ); - if (geometry instanceof THREE.BufferGeometry) { + } - var attributes = geometry.attributes; - var positions = attributes.position.array; + } - if (attributes.index !== undefined) { + if ( geometry instanceof THREE.BufferGeometry ) { - var indices = attributes.index.array; - var offsets = geometry.offsets; + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; - if (offsets.length === 0) { + if ( index !== null ) { - var offset = { - start: 0, - count: indices.length, - index: 0 - }; + var indices = index.array; - offsets = [offset]; + for ( var i = 0, il = indices.length; i < il; i ++ ) { - } + var a = indices[ i ]; - for (var oi = 0, ol = offsets.length; oi < ol; ++oi) { + position.fromArray( positions, a * 3 ); - var start = offsets[oi].start; - var count = offsets[oi].count; - var index = offsets[oi].index; + testPoint( position, a ); - for (var i = start, il = start + count; i < il; i++) { + } - var a = index + indices[i]; + } else { - position.fromArray(positions, a * 3); + for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { - testPoint(position, a); + position.fromArray( positions, i * 3 ); - } + testPoint( position, i ); - } + } - } else { + } - var pointCount = positions.length / 3; + } else { - for (var i = 0; i < pointCount; i++) { + var vertices = geometry.vertices; - position.set( - positions[3 * i], - positions[3 * i + 1], - positions[3 * i + 2] - ); + for ( var i = 0, l = vertices.length; i < l; i ++ ) { - testPoint(position, i); + testPoint( vertices[ i ], i ); - } + } - } + } - } else { + }; - var vertices = this.geometry.vertices; +}() ); - for (var i = 0; i < vertices.length; i++) { +THREE.Points.prototype.clone = function () { - testPoint(vertices[i], i); + return new this.constructor( this.geometry, this.material ).copy( this ); - } +}; - } +THREE.Points.prototype.toJSON = function ( meta ) { - }; + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); -}() ); + // only serialize if not in meta geometries cache + if ( meta.geometries[ this.geometry.uuid ] === undefined ) { -THREE.PointCloud.prototype.clone = function (object) { + meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON(); - if (object === undefined) object = new THREE.PointCloud(this.geometry, this.material); + } - THREE.Object3D.prototype.clone.call(this, object); + // only serialize if not in meta materials cache + if ( meta.materials[ this.material.uuid ] === undefined ) { - return object; + meta.materials[ this.material.uuid ] = this.material.toJSON(); -}; + } -THREE.PointCloud.prototype.toJSON = function (meta) { + data.object.geometry = this.geometry.uuid; + data.object.material = this.material.uuid; - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + return data; - // only serialize if not in meta geometries cache - if (meta.geometries[this.geometry.uuid] === undefined) { - meta.geometries[this.geometry.uuid] = this.geometry.toJSON(); - } +}; - // only serialize if not in meta materials cache - if (meta.materials[this.material.uuid] === undefined) { - meta.materials[this.material.uuid] = this.material.toJSON(); - } +// Backwards compatibility - data.object.geometry = this.geometry.uuid; - data.object.material = this.material.uuid; +THREE.PointCloud = function ( geometry, material ) { - return data; + console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); + return new THREE.Points( geometry, material ); }; -// Backwards compatibility - -THREE.ParticleSystem = function (geometry, material) { +THREE.ParticleSystem = function ( geometry, material ) { - THREE.warn('THREE.ParticleSystem has been renamed to THREE.PointCloud.'); - return new THREE.PointCloud(geometry, material); + console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); + return new THREE.Points( geometry, material ); }; @@ -16309,219 +18712,232 @@ THREE.ParticleSystem = function (geometry, material) { * @author mrdoob / http://mrdoob.com/ */ -THREE.Line = function (geometry, material, mode) { +THREE.Line = function ( geometry, material, mode ) { - THREE.Object3D.call(this); + if ( mode === 1 ) { - this.type = 'Line'; + console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); + return new THREE.LineSegments( geometry, material ); - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.LineBasicMaterial({color: Math.random() * 0xffffff}); + } - this.mode = mode !== undefined ? mode : THREE.LineStrip; + THREE.Object3D.call( this ); -}; + this.type = 'Line'; -THREE.LineStrip = 0; -THREE.LinePieces = 1; + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); + +}; -THREE.Line.prototype = Object.create(THREE.Object3D.prototype); +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); THREE.Line.prototype.constructor = THREE.Line; THREE.Line.prototype.raycast = ( function () { - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); - var sphere = new THREE.Sphere(); + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - return function (raycaster, intersects) { + return function raycast( raycaster, intersects ) { - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; - var geometry = this.geometry; + var geometry = this.geometry; - if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - // Checking boundingSphere distance to ray + // Checking boundingSphere distance to ray - sphere.copy(geometry.boundingSphere); - sphere.applyMatrix4(this.matrixWorld); + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - if (raycaster.ray.isIntersectionSphere(sphere) === false) { + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - return; + return; - } + } - inverseMatrix.getInverse(this.matrixWorld); - ray.copy(raycaster.ray).applyMatrix4(inverseMatrix); + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - 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; + var vStart = new THREE.Vector3(); + var vEnd = new THREE.Vector3(); + var interSegment = new THREE.Vector3(); + var interRay = new THREE.Vector3(); + var step = this instanceof THREE.LineSegments ? 2 : 1; - if (geometry instanceof THREE.BufferGeometry) { + if ( geometry instanceof THREE.BufferGeometry ) { - var attributes = geometry.attributes; + var index = geometry.index; + var attributes = geometry.attributes; - if (attributes.index !== undefined) { + if ( index !== null ) { - var indices = attributes.index.array; - var positions = attributes.position.array; - var offsets = geometry.offsets; + var indices = index.array; + var positions = attributes.position.array; - if (offsets.length === 0) { + for ( var i = 0, l = indices.length - 1; i < l; i += step ) { - offsets = [{start: 0, count: indices.length, index: 0}]; + var a = indices[ i ]; + var b = indices[ i + 1 ]; - } + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); - for (var oi = 0; oi < offsets.length; oi++) { + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - var start = offsets[oi].start; - var count = offsets[oi].count; - var index = offsets[oi].index; + if ( distSq > precisionSq ) continue; - for (var i = start; i < start + count - 1; i += step) { + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - var a = index + indices[i]; - var b = index + indices[i + 1]; + var distance = raycaster.ray.origin.distanceTo( interRay ); - vStart.fromArray(positions, a * 3); - vEnd.fromArray(positions, b * 3); + if ( distance < raycaster.near || distance > raycaster.far ) continue; - var distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment); + intersects.push( { - if (distSq > precisionSq) continue; + 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 - var distance = ray.origin.distanceTo(interRay); + } ); - if (distance < raycaster.near || distance > raycaster.far) continue; + } - intersects.push({ + } else { - 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 + var positions = attributes.position.array; - }); + for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { - } + vStart.fromArray( positions, 3 * i ); + vEnd.fromArray( positions, 3 * i + 3 ); - } + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - } else { + if ( distSq > precisionSq ) continue; - var positions = attributes.position.array; + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - for (var i = 0; i < positions.length / 3 - 1; i += step) { + var distance = raycaster.ray.origin.distanceTo( interRay ); - vStart.fromArray(positions, 3 * i); - vEnd.fromArray(positions, 3 * i + 3); + if ( distance < raycaster.near || distance > raycaster.far ) continue; - var distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment); + intersects.push( { - if (distSq > precisionSq) continue; + 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 - var distance = ray.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(this.matrixWorld), - index: i, - face: null, - faceIndex: null, - object: this + } else if ( geometry instanceof THREE.Geometry ) { - }); + var vertices = geometry.vertices; + var nbVertices = vertices.length; - } + for ( var i = 0; i < nbVertices - 1; i += step ) { - } + var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - } else if (geometry instanceof THREE.Geometry) { + if ( distSq > precisionSq ) continue; - var vertices = geometry.vertices; - var nbVertices = vertices.length; + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - for (var i = 0; i < nbVertices - 1; i += step) { + var distance = raycaster.ray.origin.distanceTo( interRay ); - var distSq = ray.distanceSqToSegment(vertices[i], vertices[i + 1], interRay, interSegment); + if ( distance < raycaster.near || distance > raycaster.far ) continue; - if (distSq > precisionSq) continue; + intersects.push( { - var distance = ray.origin.distanceTo(interRay); + 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 - 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, - face: null, - faceIndex: null, - object: this + } - }); + }; - } +}() ); - } +THREE.Line.prototype.clone = function () { - }; + return new this.constructor( this.geometry, this.material ).copy( this ); -}() ); +}; + +THREE.Line.prototype.toJSON = function ( meta ) { + + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); + + // only serialize if not in meta geometries cache + if ( meta.geometries[ this.geometry.uuid ] === undefined ) { + + meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON(); -THREE.Line.prototype.clone = function (object) { + } - if (object === undefined) object = new THREE.Line(this.geometry, this.material, this.mode); + // only serialize if not in meta materials cache + if ( meta.materials[ this.material.uuid ] === undefined ) { - THREE.Object3D.prototype.clone.call(this, object); + meta.materials[ this.material.uuid ] = this.material.toJSON(); - return object; + } + + data.object.geometry = this.geometry.uuid; + data.object.material = this.material.uuid; + + return data; }; -THREE.Line.prototype.toJSON = function (meta) { +// DEPRECATED - var data = THREE.Object3D.prototype.toJSON.call(this, meta); +THREE.LineStrip = 0; +THREE.LinePieces = 1; - data.object.mode = this.mode; +// File:src/objects/LineSegments.js - // only serialize if not in meta geometries cache - if (meta.geometries[this.geometry.uuid] === undefined) { - meta.geometries[this.geometry.uuid] = this.geometry.toJSON(); - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - // only serialize if not in meta materials cache - if (meta.materials[this.material.uuid] === undefined) { - meta.materials[this.material.uuid] = this.material.toJSON(); - } +THREE.LineSegments = function ( geometry, material ) { - data.object.geometry = this.geometry.uuid; - data.object.material = this.material.uuid; + THREE.Line.call( this, geometry, material ); - return data; + this.type = 'LineSegments'; }; +THREE.LineSegments.prototype = Object.create( THREE.Line.prototype ); +THREE.LineSegments.prototype.constructor = THREE.LineSegments; + // File:src/objects/Mesh.js /** @@ -16531,343 +18947,378 @@ THREE.Line.prototype.toJSON = function (meta) { * @author jonobr1 / http://jonobr1.com/ */ -THREE.Mesh = function (geometry, material) { +THREE.Mesh = function ( geometry, material ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Mesh'; + this.type = 'Mesh'; - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.MeshBasicMaterial({color: Math.random() * 0xffffff}); + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - this.updateMorphTargets(); + this.updateMorphTargets(); }; -THREE.Mesh.prototype = Object.create(THREE.Object3D.prototype); +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); THREE.Mesh.prototype.constructor = THREE.Mesh; THREE.Mesh.prototype.updateMorphTargets = function () { - if (this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0) { + if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - this.morphTargetBase = -1; - this.morphTargetForcedOrder = []; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + this.morphTargetBase = - 1; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - for (var m = 0, ml = this.geometry.morphTargets.length; m < ml; m++) { + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - this.morphTargetInfluences.push(0); - this.morphTargetDictionary[this.geometry.morphTargets[m].name] = m; + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - } + } - } + } }; -THREE.Mesh.prototype.getMorphTargetIndexByName = function (name) { +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - if (this.morphTargetDictionary[name] !== undefined) { + if ( this.morphTargetDictionary[ name ] !== undefined ) { - return this.morphTargetDictionary[name]; + return this.morphTargetDictionary[ name ]; - } + } - THREE.warn('THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.'); + console.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); - return 0; + return 0; }; THREE.Mesh.prototype.raycast = ( function () { - var inverseMatrix = new THREE.Matrix4(); - var ray = new THREE.Ray(); - var sphere = new THREE.Sphere(); + var inverseMatrix = new THREE.Matrix4(); + var ray = new THREE.Ray(); + var sphere = new THREE.Sphere(); - var vA = new THREE.Vector3(); - var vB = new THREE.Vector3(); - var vC = new THREE.Vector3(); + var vA = new THREE.Vector3(); + var vB = new THREE.Vector3(); + var vC = new THREE.Vector3(); - return function (raycaster, intersects) { + var tempA = new THREE.Vector3(); + var tempB = new THREE.Vector3(); + var tempC = new THREE.Vector3(); - var geometry = this.geometry; + var uvA = new THREE.Vector2(); + var uvB = new THREE.Vector2(); + var uvC = new THREE.Vector2(); - // Checking boundingSphere distance to ray + var barycoord = new THREE.Vector3(); - if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); + var intersectionPoint = new THREE.Vector3(); + var intersectionPointWorld = new THREE.Vector3(); - sphere.copy(geometry.boundingSphere); - sphere.applyMatrix4(this.matrixWorld); + function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { - if (raycaster.ray.isIntersectionSphere(sphere) === false) { + THREE.Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); - return; + uv1.multiplyScalar( barycoord.x ); + uv2.multiplyScalar( barycoord.y ); + uv3.multiplyScalar( barycoord.z ); - } + uv1.add( uv2 ).add( uv3 ); - // Check boundingBox before continuing + return uv1.clone(); - inverseMatrix.getInverse(this.matrixWorld); - ray.copy(raycaster.ray).applyMatrix4(inverseMatrix); + } - if (geometry.boundingBox !== null) { + return function raycast( raycaster, intersects ) { - if (ray.isIntersectionBox(geometry.boundingBox) === false) { + var geometry = this.geometry; + var material = this.material; - return; + if ( material === undefined ) return; - } + // Checking boundingSphere distance to ray - } + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - if (geometry instanceof THREE.BufferGeometry) { + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( this.matrixWorld ); - var material = this.material; + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - if (material === undefined) return; + return; - var attributes = geometry.attributes; + } - var a, b, c; - var precision = raycaster.precision; + // Check boundingBox before continuing - if (attributes.index !== undefined) { + inverseMatrix.getInverse( this.matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - var indices = attributes.index.array; - var positions = attributes.position.array; - var offsets = geometry.offsets; + if ( geometry.boundingBox !== null ) { - if (offsets.length === 0) { + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { - offsets = [{start: 0, count: indices.length, index: 0}]; + return; - } + } - for (var oi = 0, ol = offsets.length; oi < ol; ++oi) { + } - var start = offsets[oi].start; - var count = offsets[oi].count; - var index = offsets[oi].index; + var a, b, c; - for (var i = start, il = start + count; i < il; i += 3) { + if ( geometry instanceof THREE.BufferGeometry ) { - a = index + indices[i]; - b = index + indices[i + 1]; - c = index + indices[i + 2]; + var index = geometry.index; + var attributes = geometry.attributes; - vA.fromArray(positions, a * 3); - vB.fromArray(positions, b * 3); - vC.fromArray(positions, c * 3); + if ( index !== null ) { - if (material.side === THREE.BackSide) { + var indices = index.array; + var positions = attributes.position.array; - var intersectionPoint = ray.intersectTriangle(vC, vB, vA, true); + for ( var i = 0, l = indices.length; i < l; i += 3 ) { - } else { + a = indices[ i ]; + b = indices[ i + 1 ]; + c = indices[ i + 2 ]; - var intersectionPoint = ray.intersectTriangle(vA, vB, vC, material.side !== THREE.DoubleSide); + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - } + if ( material.side === THREE.BackSide ) { - if (intersectionPoint === null) continue; + if ( ray.intersectTriangle( vC, vB, vA, true, intersectionPoint ) === null ) continue; - intersectionPoint.applyMatrix4(this.matrixWorld); + } else { - var distance = raycaster.ray.origin.distanceTo(intersectionPoint); + if ( ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide, intersectionPoint ) === null ) continue; - if (distance < precision || distance < raycaster.near || distance > raycaster.far) continue; + } - intersects.push({ + intersectionPointWorld.copy( intersectionPoint ); + intersectionPointWorld.applyMatrix4( this.matrixWorld ); - distance: distance, - point: intersectionPoint, - face: new THREE.Face3(a, b, c, THREE.Triangle.normal(vA, vB, vC)), - faceIndex: null, - object: this + var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - }); + if ( distance < raycaster.near || distance > raycaster.far ) continue; - } + var uv; - } + if ( attributes.uv !== undefined ) { - } else { + var uvs = attributes.uv.array; + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); + uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); - var positions = attributes.position.array; + } - for (var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9) { + intersects.push( { - a = i; - b = i + 1; - c = i + 2; + distance: distance, + point: intersectionPointWorld.clone(), + uv: uv, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + faceIndex: Math.floor( i / 3 ), // triangle number in indices buffer semantics + object: this - vA.fromArray(positions, j); - vB.fromArray(positions, j + 3); - vC.fromArray(positions, j + 6); + } ); - if (material.side === THREE.BackSide) { + } - var intersectionPoint = ray.intersectTriangle(vC, vB, vA, true); + } else { - } else { + var positions = attributes.position.array; - var intersectionPoint = ray.intersectTriangle(vA, vB, vC, material.side !== THREE.DoubleSide); + for ( var i = 0, l = positions.length; i < l; i += 9 ) { - } + vA.fromArray( positions, i ); + vB.fromArray( positions, i + 3 ); + vC.fromArray( positions, i + 6 ); - if (intersectionPoint === null) continue; + if ( material.side === THREE.BackSide ) { - intersectionPoint.applyMatrix4(this.matrixWorld); + if ( ray.intersectTriangle( vC, vB, vA, true, intersectionPoint ) === null ) continue; - var distance = raycaster.ray.origin.distanceTo(intersectionPoint); + } else { - if (distance < precision || distance < raycaster.near || distance > raycaster.far) continue; + if ( ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide, intersectionPoint ) === null ) continue; - intersects.push({ + } - distance: distance, - point: intersectionPoint, - face: new THREE.Face3(a, b, c, THREE.Triangle.normal(vA, vB, vC)), - faceIndex: null, - object: this + intersectionPointWorld.copy( intersectionPoint ); + intersectionPointWorld.applyMatrix4( this.matrixWorld ); - }); + var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - } + if ( distance < raycaster.near || distance > raycaster.far ) continue; - } + var uv; - } else if (geometry instanceof THREE.Geometry) { + if ( attributes.uv !== undefined ) { - var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; - var objectMaterials = isFaceMaterial === true ? this.material.materials : null; + var uvs = attributes.uv.array; + uvA.fromArray( uvs, i ); + uvB.fromArray( uvs, i + 2 ); + uvC.fromArray( uvs, i + 4 ); + uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); - var a, b, c; - var precision = raycaster.precision; + } - var vertices = geometry.vertices; + a = i / 3; + b = a + 1; + c = a + 2; - for (var f = 0, fl = geometry.faces.length; f < fl; f++) { + intersects.push( { - var face = geometry.faces[f]; + distance: distance, + point: intersectionPointWorld.clone(), + uv: uv, + face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ), + index: a, // triangle number in positions buffer semantics + object: this - var material = isFaceMaterial === true ? objectMaterials[face.materialIndex] : this.material; + } ); - if (material === undefined) continue; + } - a = vertices[face.a]; - b = vertices[face.b]; - c = vertices[face.c]; + } - if (material.morphTargets === true) { + } else if ( geometry instanceof THREE.Geometry ) { - var morphTargets = geometry.morphTargets; - var morphInfluences = this.morphTargetInfluences; + var isFaceMaterial = material instanceof THREE.MeshFaceMaterial; + var materials = isFaceMaterial === true ? material.materials : null; - vA.set(0, 0, 0); - vB.set(0, 0, 0); - vC.set(0, 0, 0); + var vertices = geometry.vertices; + var faces = geometry.faces; - for (var t = 0, tl = morphTargets.length; t < tl; t++) { + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { - var influence = morphInfluences[t]; + var face = faces[ f ]; + var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material; - if (influence === 0) continue; + if ( faceMaterial === undefined ) continue; - var targets = morphTargets[t].vertices; + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; - 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; + if ( faceMaterial.morphTargets === true ) { - 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; + var morphTargets = geometry.morphTargets; + var morphInfluences = this.morphTargetInfluences; - 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; + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); - } + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - vA.add(a); - vB.add(b); - vC.add(c); + var influence = morphInfluences[ t ]; - a = vA; - b = vB; - c = vC; + if ( influence === 0 ) continue; - } + var targets = morphTargets[ t ].vertices; - if (material.side === THREE.BackSide) { + vA.addScaledVector( tempA.subVectors( targets[ face.a ], a ), influence ); + vB.addScaledVector( tempB.subVectors( targets[ face.b ], b ), influence ); + vC.addScaledVector( tempC.subVectors( targets[ face.c ], c ), influence ); - var intersectionPoint = ray.intersectTriangle(c, b, a, true); + } - } else { + vA.add( a ); + vB.add( b ); + vC.add( c ); - var intersectionPoint = ray.intersectTriangle(a, b, c, material.side !== THREE.DoubleSide); + a = vA; + b = vB; + c = vC; - } + } - if (intersectionPoint === null) continue; + if ( faceMaterial.side === THREE.BackSide ) { - intersectionPoint.applyMatrix4(this.matrixWorld); + if ( ray.intersectTriangle( c, b, a, true, intersectionPoint ) === null ) continue; - var distance = raycaster.ray.origin.distanceTo(intersectionPoint); + } else { - if (distance < precision || distance < raycaster.near || distance > raycaster.far) continue; + if ( ray.intersectTriangle( a, b, c, faceMaterial.side !== THREE.DoubleSide, intersectionPoint ) === null ) continue; - intersects.push({ + } - distance: distance, - point: intersectionPoint, - face: face, - faceIndex: f, - object: this + intersectionPointWorld.copy( intersectionPoint ); + intersectionPointWorld.applyMatrix4( this.matrixWorld ); - }); + var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - } + if ( distance < raycaster.near || distance > raycaster.far ) continue; - } + var uv; - }; + if ( geometry.faceVertexUvs[ 0 ].length > 0 ) { -}() ); + var uvs = geometry.faceVertexUvs[ 0 ][ f ]; + uvA.copy( uvs[ 0 ] ); + uvB.copy( uvs[ 1 ] ); + uvC.copy( uvs[ 2 ] ); + uv = uvIntersection( intersectionPoint, a, b, c, uvA, uvB, uvC ); + + } + + intersects.push( { -THREE.Mesh.prototype.clone = function (object, recursive) { + distance: distance, + point: intersectionPointWorld.clone(), + uv: uv, + face: face, + faceIndex: f, + object: this - if (object === undefined) object = new THREE.Mesh(this.geometry, this.material); + } ); - THREE.Object3D.prototype.clone.call(this, object, recursive); + } - return object; + } + + }; + +}() ); + +THREE.Mesh.prototype.clone = function () { + + return new this.constructor( this.geometry, this.material ).copy( this ); }; -THREE.Mesh.prototype.toJSON = function (meta) { +THREE.Mesh.prototype.toJSON = function ( meta ) { - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); - // only serialize if not in meta geometries cache - if (meta.geometries[this.geometry.uuid] === undefined) { - meta.geometries[this.geometry.uuid] = this.geometry.toJSON(); - } + // only serialize if not in meta geometries cache + if ( meta.geometries[ this.geometry.uuid ] === undefined ) { - // only serialize if not in meta materials cache - if (meta.materials[this.material.uuid] === undefined) { - meta.materials[this.material.uuid] = this.material.toJSON(); - } + meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta ); + + } - data.object.geometry = this.geometry.uuid; - data.object.material = this.material.uuid; + // only serialize if not in meta materials cache + if ( meta.materials[ this.material.uuid ] === undefined ) { - return data; + meta.materials[ this.material.uuid ] = this.material.toJSON( meta ); + + } + + data.object.geometry = this.geometry.uuid; + data.object.material = this.material.uuid; + + return data; }; @@ -16879,19 +19330,29 @@ THREE.Mesh.prototype.toJSON = function (meta) { * @author ikerr / http://verold.com */ -THREE.Bone = function (skin) { +THREE.Bone = function ( skin ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Bone'; + this.type = 'Bone'; - this.skin = skin; + this.skin = skin; }; -THREE.Bone.prototype = Object.create(THREE.Object3D.prototype); +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); THREE.Bone.prototype.constructor = THREE.Bone; +THREE.Bone.prototype.copy = function ( source ) { + + THREE.Object3D.prototype.copy.call( this, source ); + + this.skin = source.skin; + + return this; + +}; + // File:src/objects/Skeleton.js /** @@ -16901,180 +19362,175 @@ THREE.Bone.prototype.constructor = THREE.Bone; * @author ikerr / http://verold.com */ -THREE.Skeleton = function (bones, boneInverses, useVertexTexture) { +THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - this.identityMatrix = new THREE.Matrix4(); + this.identityMatrix = new THREE.Matrix4(); - // copy the bone array + // copy the bone array - bones = bones || []; + bones = bones || []; - this.bones = bones.slice(0); + this.bones = bones.slice( 0 ); - // create a bone texture or an array of floats + // create a bone texture or an array of floats - if (this.useVertexTexture) { + if ( this.useVertexTexture ) { - // 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) + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - var size; + + var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix + size = THREE.Math.nextPowerOfTwo( Math.ceil( size ) ); + size = Math.max( size, 4 ); - 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; + this.boneTextureWidth = size; + this.boneTextureHeight = size; - 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.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; + } else { - } else { + this.boneMatrices = new Float32Array( 16 * this.bones.length ); - this.boneMatrices = new Float32Array(16 * this.bones.length); - - } + } - // use the supplied bone inverses or calculate the inverses + // use the supplied bone inverses or calculate the inverses - if (boneInverses === undefined) { + if ( boneInverses === undefined ) { - this.calculateInverses(); + this.calculateInverses(); - } else { + } else { - if (this.bones.length === boneInverses.length) { + if ( this.bones.length === boneInverses.length ) { - this.boneInverses = boneInverses.slice(0); + this.boneInverses = boneInverses.slice( 0 ); - } else { + } else { - THREE.warn('THREE.Skeleton bonInverses is the wrong length.'); + console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); - this.boneInverses = []; + this.boneInverses = []; - for (var b = 0, bl = this.bones.length; b < bl; b++) { + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - this.boneInverses.push(new THREE.Matrix4()); + this.boneInverses.push( new THREE.Matrix4() ); - } + } - } + } - } + } }; THREE.Skeleton.prototype.calculateInverses = function () { - this.boneInverses = []; + this.boneInverses = []; - for (var b = 0, bl = this.bones.length; b < bl; b++) { + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - var inverse = new THREE.Matrix4(); + var inverse = new THREE.Matrix4(); - if (this.bones[b]) { + if ( this.bones[ b ] ) { - inverse.getInverse(this.bones[b].matrixWorld); + inverse.getInverse( this.bones[ b ].matrixWorld ); - } + } - this.boneInverses.push(inverse); + this.boneInverses.push( inverse ); - } + } }; THREE.Skeleton.prototype.pose = function () { - var bone; + var bone; - // recover the bind-time world matrices + // recover the bind-time world matrices - for (var b = 0, bl = this.bones.length; b < bl; b++) { + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - bone = this.bones[b]; + bone = this.bones[ b ]; - if (bone) { + if ( bone ) { - bone.matrixWorld.getInverse(this.boneInverses[b]); + bone.matrixWorld.getInverse( this.boneInverses[ b ] ); - } + } - } + } - // compute the local matrices, positions, rotations and scales + // compute the local matrices, positions, rotations and scales - for (var b = 0, bl = this.bones.length; b < bl; b++) { + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - bone = this.bones[b]; + bone = this.bones[ b ]; - if (bone) { + if ( bone ) { - if (bone.parent) { + if ( bone.parent ) { - bone.matrix.getInverse(bone.parent.matrixWorld); - bone.matrix.multiply(bone.matrixWorld); + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( bone.matrixWorld ); - } else { + } else { - bone.matrix.copy(bone.matrixWorld); + bone.matrix.copy( bone.matrixWorld ); - } + } - bone.matrix.decompose(bone.position, bone.quaternion, bone.scale); + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - } + } - } + } }; -THREE.Skeleton.prototype.update = (function () { +THREE.Skeleton.prototype.update = ( function () { - var offsetMatrix = new THREE.Matrix4(); + var offsetMatrix = new THREE.Matrix4(); - return function () { + return function update() { - // flatten bone matrices to array + // flatten bone matrices to array - for (var b = 0, bl = this.bones.length; b < bl; b++) { + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - // compute the offset between the current and the original transform + // compute the offset between the current and the original transform - var matrix = this.bones[b] ? this.bones[b].matrixWorld : this.identityMatrix; + var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; - offsetMatrix.multiplyMatrices(matrix, this.boneInverses[b]); - offsetMatrix.flattenToArrayOffset(this.boneMatrices, b * 16); + offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); + offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); - } + } - if (this.useVertexTexture) { + if ( this.useVertexTexture ) { - this.boneTexture.needsUpdate = true; + this.boneTexture.needsUpdate = true; - } + } - }; + }; -})(); +} )(); +THREE.Skeleton.prototype.clone = function () { + + return new THREE.Skeleton( this.bones, this.boneInverses, this.useVertexTexture ); + +}; // File:src/objects/SkinnedMesh.js @@ -17084,384 +19540,148 @@ THREE.Skeleton.prototype.update = (function () { * @author ikerr / http://verold.com */ -THREE.SkinnedMesh = function (geometry, material, useVertexTexture) { - - THREE.Mesh.call(this, geometry, material); +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - this.type = 'SkinnedMesh'; + THREE.Mesh.call( this, geometry, material ); - this.bindMode = "attached"; - this.bindMatrix = new THREE.Matrix4(); - this.bindMatrixInverse = new THREE.Matrix4(); + this.type = 'SkinnedMesh'; - // init bones + this.bindMode = "attached"; + this.bindMatrix = new THREE.Matrix4(); + this.bindMatrixInverse = new THREE.Matrix4(); - // TODO: remove bone creation as there is no reason (other than - // convenience) for THREE.SkinnedMesh to do this. + // init bones - var bones = []; + // TODO: remove bone creation as there is no reason (other than + // convenience) for THREE.SkinnedMesh to do this. - if (this.geometry && this.geometry.bones !== undefined) { + var bones = []; - var bone, gbone, p, q, s; + if ( this.geometry && this.geometry.bones !== undefined ) { - for (var b = 0, bl = this.geometry.bones.length; b < bl; ++b) { + var bone, gbone; - gbone = this.geometry.bones[b]; + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - p = gbone.pos; - q = gbone.rotq; - s = gbone.scl; + gbone = this.geometry.bones[ b ]; - bone = new THREE.Bone(this); - bones.push(bone); + bone = new THREE.Bone( this ); + bones.push( bone ); - bone.name = gbone.name; - bone.position.set(p[0], p[1], p[2]); - bone.quaternion.set(q[0], q[1], q[2], q[3]); + bone.name = gbone.name; + bone.position.fromArray( gbone.pos ); + bone.quaternion.fromArray( gbone.rotq ); + if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); - if (s !== undefined) { + } - bone.scale.set(s[0], s[1], s[2]); + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { - } else { + gbone = this.geometry.bones[ b ]; - bone.scale.set(1, 1, 1); + if ( gbone.parent !== - 1 ) { - } + bones[ gbone.parent ].add( bones[ b ] ); - } + } else { - for (var b = 0, bl = this.geometry.bones.length; b < bl; ++b) { + this.add( bones[ b ] ); - gbone = this.geometry.bones[b]; + } - if (gbone.parent !== -1) { + } - bones[gbone.parent].add(bones[b]); + } - } else { + this.normalizeSkinWeights(); - this.add(bones[b]); - - } - - } - - } - - this.normalizeSkinWeights(); - - this.updateMatrixWorld(true); - this.bind(new THREE.Skeleton(bones, undefined, useVertexTexture)); + this.updateMatrixWorld( true ); + this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld ); }; -THREE.SkinnedMesh.prototype = Object.create(THREE.Mesh.prototype); +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; -THREE.SkinnedMesh.prototype.bind = function (skeleton, bindMatrix) { +THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { - this.skeleton = skeleton; + this.skeleton = skeleton; - if (bindMatrix === undefined) { + if ( bindMatrix === undefined ) { - this.updateMatrixWorld(true); + this.updateMatrixWorld( true ); + + this.skeleton.calculateInverses(); - bindMatrix = this.matrixWorld; + bindMatrix = this.matrixWorld; - } + } - this.bindMatrix.copy(bindMatrix); - this.bindMatrixInverse.getInverse(bindMatrix); + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); }; THREE.SkinnedMesh.prototype.pose = function () { - this.skeleton.pose(); + this.skeleton.pose(); }; 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]; - - var scale = 1.0 / sw.lengthManhattan(); - - if (scale !== Infinity) { - - sw.multiplyScalar(scale); - - } else { - - sw.set(1); // this will be normalized by the shader anyway - - } - - } - - } else { - - // skinning weights assumed to be normalized for THREE.BufferGeometry - - } - -}; - -THREE.SkinnedMesh.prototype.updateMatrixWorld = function (force) { - - THREE.Mesh.prototype.updateMatrixWorld.call(this, true); - - if (this.bindMode === "attached") { - - this.bindMatrixInverse.getInverse(this.matrixWorld); - - } else if (this.bindMode === "detached") { - - this.bindMatrixInverse.getInverse(this.bindMatrix); - - } else { - - THREE.warn('THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode); - - } - -}; - -THREE.SkinnedMesh.prototype.clone = function (object) { - - if (object === undefined) { - - object = new THREE.SkinnedMesh(this.geometry, this.material, this.useVertexTexture); - - } - - THREE.Mesh.prototype.clone.call(this, object); - - return object; - -}; - - -// File:src/objects/MorphAnimMesh.js - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphAnimMesh = function (geometry, material) { - - THREE.Mesh.call(this, geometry, material); - - this.type = 'MorphAnimMesh'; - - // API - - this.duration = 1000; // milliseconds - this.mirroredLoop = false; - this.time = 0; - - // internals - - this.lastKeyframe = 0; - this.currentKeyframe = 0; - - this.direction = 1; - this.directionBackwards = false; - - 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 (start, end) { - - this.startKeyframe = start; - this.endKeyframe = end; - - this.length = this.endKeyframe - this.startKeyframe + 1; + if ( this.geometry instanceof THREE.Geometry ) { -}; - -THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - - this.direction = 1; - this.directionBackwards = false; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - - this.direction = -1; - this.directionBackwards = true; - -}; - -THREE.MorphAnimMesh.prototype.parseAnimations = function () { - - var geometry = this.geometry; - - if (!geometry.animations) geometry.animations = {}; - - var firstAnimation, animations = geometry.animations; - - var pattern = /([a-z]+)_?(\d+)/; - - for (var i = 0, il = geometry.morphTargets.length; i < il; i++) { - - var morph = geometry.morphTargets[i]; - var parts = morph.name.match(pattern); - - if (parts && parts.length > 1) { - - var label = parts[1]; - - if (!animations[label]) animations[label] = {start: Infinity, end: -Infinity}; - - var animation = animations[label]; - - if (i < animation.start) animation.start = i; - if (i > animation.end) animation.end = i; - - if (!firstAnimation) firstAnimation = label; - - } - - } - - geometry.firstAnimation = firstAnimation; - -}; - -THREE.MorphAnimMesh.prototype.setAnimationLabel = function (label, start, end) { - - if (!this.geometry.animations) this.geometry.animations = {}; - - this.geometry.animations[label] = {start: start, end: end}; - -}; - -THREE.MorphAnimMesh.prototype.playAnimation = function (label, fps) { - - var animation = this.geometry.animations[label]; - - if (animation) { - - this.setFrameRange(animation.start, animation.end); - this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); - this.time = 0; - - } else { - - THREE.warn('THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()'); - - } - -}; - -THREE.MorphAnimMesh.prototype.updateAnimation = function (delta) { - - var frameTime = this.duration / this.length; - - this.time += this.direction * delta; - - if (this.mirroredLoop) { - - if (this.time > this.duration || this.time < 0) { + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - this.direction *= -1; + var sw = this.geometry.skinWeights[ i ]; - if (this.time > this.duration) { + var scale = 1.0 / sw.lengthManhattan(); - this.time = this.duration; - this.directionBackwards = true; + if ( scale !== Infinity ) { - } - - if (this.time < 0) { - - this.time = 0; - this.directionBackwards = false; - - } - - } - - } else { - - this.time = this.time % this.duration; - - if (this.time < 0) this.time += this.duration; - - } - - var keyframe = this.startKeyframe + THREE.Math.clamp(Math.floor(this.time / frameTime), 0, this.length - 1); - - if (keyframe !== this.currentKeyframe) { - - this.morphTargetInfluences[this.lastKeyframe] = 0; - this.morphTargetInfluences[this.currentKeyframe] = 1; - - this.morphTargetInfluences[keyframe] = 0; - - this.lastKeyframe = this.currentKeyframe; - this.currentKeyframe = keyframe; - - } + sw.multiplyScalar( scale ); - var mix = ( this.time % frameTime ) / frameTime; + } else { - if (this.directionBackwards) { + sw.set( 1 ); // this will be normalized by the shader anyway - mix = 1 - mix; + } - } + } - this.morphTargetInfluences[this.currentKeyframe] = mix; - this.morphTargetInfluences[this.lastKeyframe] = 1 - mix; + } else { -}; + // skinning weights assumed to be normalized for THREE.BufferGeometry -THREE.MorphAnimMesh.prototype.interpolateTargets = function (a, b, t) { + } - var influences = this.morphTargetInfluences; +}; - for (var i = 0, l = influences.length; i < l; i++) { +THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { - influences[i] = 0; + THREE.Mesh.prototype.updateMatrixWorld.call( this, true ); - } + if ( this.bindMode === "attached" ) { - if (a > -1) influences[a] = 1 - t; - if (b > -1) influences[b] = t; + this.bindMatrixInverse.getInverse( this.matrixWorld ); -}; + } else if ( this.bindMode === "detached" ) { -THREE.MorphAnimMesh.prototype.clone = function (object) { + this.bindMatrixInverse.getInverse( this.bindMatrix ); - if (object === undefined) object = new THREE.MorphAnimMesh(this.geometry, this.material); + } else { - object.duration = this.duration; - object.mirroredLoop = this.mirroredLoop; - object.time = this.time; + console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode ); - object.lastKeyframe = this.lastKeyframe; - object.currentKeyframe = this.currentKeyframe; + } - object.direction = this.direction; - object.directionBackwards = this.directionBackwards; +}; - THREE.Mesh.prototype.clone.call(this, object); +THREE.SkinnedMesh.prototype.clone = function() { - return object; + return new this.constructor( this.geometry, this.material, this.useVertexTexture ).copy( this ); }; @@ -17475,125 +19695,172 @@ THREE.MorphAnimMesh.prototype.clone = function (object) { THREE.LOD = function () { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); + + this.type = 'LOD'; + + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + }, + objects: { + get: function () { - this.objects = []; + console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); + return this.levels; + + } + } + } ); }; -THREE.LOD.prototype = Object.create(THREE.Object3D.prototype); +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); THREE.LOD.prototype.constructor = THREE.LOD; -THREE.LOD.prototype.addLevel = function (object, distance) { +THREE.LOD.prototype.addLevel = function ( object, distance ) { - if (distance === undefined) distance = 0; + if ( distance === undefined ) distance = 0; - distance = Math.abs(distance); + distance = Math.abs( distance ); - for (var l = 0; l < this.objects.length; l++) { + var levels = this.levels; - if (distance < this.objects[l].distance) { + for ( var l = 0; l < levels.length; l ++ ) { - break; + if ( distance < levels[ l ].distance ) { - } + break; - } + } + + } + + levels.splice( l, 0, { distance: distance, object: object } ); - this.objects.splice(l, 0, {distance: distance, object: object}); - this.add(object); + this.add( object ); }; -THREE.LOD.prototype.getObjectForDistance = function (distance) { +THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - for (var i = 1, l = this.objects.length; i < l; i++) { + var levels = this.levels; - if (distance < this.objects[i].distance) { + for ( var i = 1, l = levels.length; i < l; i ++ ) { - break; + if ( distance < levels[ i ].distance ) { - } + break; - } + } + + } - return this.objects[i - 1].object; + return levels[ i - 1 ].object; }; THREE.LOD.prototype.raycast = ( function () { - var matrixPosition = new THREE.Vector3(); + var matrixPosition = new THREE.Vector3(); - return function (raycaster, intersects) { + return function raycast( raycaster, intersects ) { - matrixPosition.setFromMatrixPosition(this.matrixWorld); + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - var distance = raycaster.ray.origin.distanceTo(matrixPosition); + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - this.getObjectForDistance(distance).raycast(raycaster, intersects); + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - }; + }; }() ); THREE.LOD.prototype.update = function () { - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); - return function (camera) { + return function update( camera ) { - if (this.objects.length > 1) { + var levels = this.levels; - v1.setFromMatrixPosition(camera.matrixWorld); - v2.setFromMatrixPosition(this.matrixWorld); + if ( levels.length > 1 ) { - var distance = v1.distanceTo(v2); + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); - this.objects[0].object.visible = true; + var distance = v1.distanceTo( v2 ); - for (var i = 1, l = this.objects.length; i < l; i++) { + levels[ 0 ].object.visible = true; - if (distance >= this.objects[i].distance) { + for ( var i = 1, l = levels.length; i < l; i ++ ) { - this.objects[i - 1].object.visible = false; - this.objects[i].object.visible = true; + if ( distance >= levels[ i ].distance ) { - } else { + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; - break; + } else { - } + break; - } + } - for (; i < l; i++) { + } - this.objects[i].object.visible = false; + for ( ; i < l; i ++ ) { - } + levels[ i ].object.visible = false; - } + } - }; + } + + }; }(); -THREE.LOD.prototype.clone = function (object) { +THREE.LOD.prototype.copy = function ( source ) { - if (object === undefined) object = new THREE.LOD(); + THREE.Object3D.prototype.copy.call( this, source, false ); - THREE.Object3D.prototype.clone.call(this, object); + var levels = source.levels; - 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); - } + for ( var i = 0, l = levels.length; i < l; i ++ ) { - return object; + var level = levels[ i ]; + + this.addLevel( level.object.clone(), level.distance ); + + } + + return this; + +}; + +THREE.LOD.prototype.toJSON = function ( meta ) { + + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); + + data.object.levels = []; + + var levels = this.levels; + + for ( var i = 0, l = levels.length; i < l; i ++ ) { + + var level = levels[ i ]; + + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance + } ); + + } + + return data; }; @@ -17604,84 +19871,83 @@ THREE.LOD.prototype.clone = function (object) { * @author alteredq / http://alteredqualia.com/ */ -THREE.Sprite = (function () { +THREE.Sprite = ( function () { - 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 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)); + var geometry = new THREE.BufferGeometry(); + geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - return function (material) { + return function Sprite( material ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Sprite'; + this.type = 'Sprite'; - this.geometry = geometry; - this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - }; + }; -})(); +} )(); -THREE.Sprite.prototype = Object.create(THREE.Object3D.prototype); +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); THREE.Sprite.prototype.constructor = THREE.Sprite; THREE.Sprite.prototype.raycast = ( function () { - var matrixPosition = new THREE.Vector3(); + var matrixPosition = new THREE.Vector3(); - return function (raycaster, intersects) { + return function raycast( raycaster, intersects ) { - matrixPosition.setFromMatrixPosition(this.matrixWorld); + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - var distance = raycaster.ray.distanceToPoint(matrixPosition); + var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition ); + var guessSizeSq = this.scale.x * this.scale.y; - if (distance > this.scale.x) { + if ( distanceSq > guessSizeSq ) { - return; + return; - } + } - intersects.push({ + intersects.push( { - distance: distance, - point: this.position, - face: null, - object: this + distance: Math.sqrt( distanceSq ), + point: this.position, + face: null, + object: this - }); + } ); - }; + }; }() ); -THREE.Sprite.prototype.clone = function (object) { +THREE.Sprite.prototype.clone = function () { - if (object === undefined) object = new THREE.Sprite(this.material); + return new this.constructor( this.material ).copy( this ); - THREE.Object3D.prototype.clone.call(this, object); +}; - return object; +THREE.Sprite.prototype.toJSON = function ( meta ) { -}; + var data = THREE.Object3D.prototype.toJSON.call( this, meta ); -THREE.Sprite.prototype.toJSON = function (meta) { + // only serialize if not in meta materials cache + if ( meta.materials[ this.material.uuid ] === undefined ) { - var data = THREE.Object3D.prototype.toJSON.call(this, meta); + meta.materials[ this.material.uuid ] = this.material.toJSON(); - // only serialize if not in meta materials cache - if (meta.materials[this.material.uuid] === undefined) { - meta.materials[this.material.uuid] = this.material.toJSON(); - } + } - data.object.material = this.material.uuid; + data.object.material = this.material.uuid; - return data; + return data; }; @@ -17696,24 +19962,24 @@ THREE.Particle = THREE.Sprite; * @author alteredq / http://alteredqualia.com/ */ -THREE.LensFlare = function (texture, size, distance, blending, color) { +THREE.LensFlare = function ( texture, size, distance, blending, color ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.lensFlares = []; + this.lensFlares = []; - this.positionScreen = new THREE.Vector3(); - this.customUpdateCallback = undefined; + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; - if (texture !== undefined) { + if ( texture !== undefined ) { - this.add(texture, size, distance, blending, color); + this.add( texture, size, distance, blending, color ); - } + } }; -THREE.LensFlare.prototype = Object.create(THREE.Object3D.prototype); +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); THREE.LensFlare.prototype.constructor = THREE.LensFlare; @@ -17721,27 +19987,27 @@ THREE.LensFlare.prototype.constructor = THREE.LensFlare; * Add: adds another flare */ -THREE.LensFlare.prototype.add = function (texture, size, distance, blending, color, opacity) { +THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { - 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; + 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; - distance = Math.min(distance, Math.max(0, distance)); + distance = Math.min( distance, Math.max( 0, distance ) ); - 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 - }); + 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 in front z = 1 is back + scale: 1, // scale + rotation: 0, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending // blending + } ); }; @@ -17752,25 +20018,41 @@ THREE.LensFlare.prototype.add = function (texture, size, distance, blending, col 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; + 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++) { + for ( f = 0; f < fl; f ++ ) { - flare = this.lensFlares[f]; + flare = this.lensFlares[ f ]; - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - } + } }; +THREE.LensFlare.prototype.copy = function ( source ) { + + THREE.Object3D.prototype.copy.call( this, source ); + + this.positionScreen.copy( source.positionScreen ); + this.customUpdateCallback = source.customUpdateCallback; + + for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { + + this.lensFlares.push( source.lensFlares[ i ] ); + + } + + return this; + +}; // File:src/scenes/Scene.js @@ -17780,33 +20062,31 @@ THREE.LensFlare.prototype.updateLensFlares = function () { THREE.Scene = function () { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Scene'; + this.type = 'Scene'; - this.fog = null; - this.overrideMaterial = null; + this.fog = null; + this.overrideMaterial = null; - this.autoUpdate = true; // checked by the renderer + this.autoUpdate = true; // checked by the renderer }; -THREE.Scene.prototype = Object.create(THREE.Object3D.prototype); +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); THREE.Scene.prototype.constructor = THREE.Scene; -THREE.Scene.prototype.clone = function (object) { - - if (object === undefined) object = new THREE.Scene(); +THREE.Scene.prototype.copy = function ( source ) { - THREE.Object3D.prototype.clone.call(this, object); + THREE.Object3D.prototype.copy.call( this, source ); - if (this.fog !== null) object.fog = this.fog.clone(); - if (this.overrideMaterial !== null) object.overrideMaterial = this.overrideMaterial.clone(); + if ( source.fog !== null ) this.fog = source.fog.clone(); + if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - object.autoUpdate = this.autoUpdate; - object.matrixAutoUpdate = this.matrixAutoUpdate; + this.autoUpdate = source.autoUpdate; + this.matrixAutoUpdate = source.matrixAutoUpdate; - return object; + return this; }; @@ -17817,20 +20097,20 @@ THREE.Scene.prototype.clone = function (object) { * @author alteredq / http://alteredqualia.com/ */ -THREE.Fog = function (color, near, far) { +THREE.Fog = function ( color, near, far ) { - this.name = ''; + this.name = ''; - this.color = new THREE.Color(color); + this.color = new THREE.Color( color ); - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; }; THREE.Fog.prototype.clone = function () { - return new THREE.Fog(this.color.getHex(), this.near, this.far); + return new THREE.Fog( this.color.getHex(), this.near, this.far ); }; @@ -17841,18 +20121,18 @@ THREE.Fog.prototype.clone = function () { * @author alteredq / http://alteredqualia.com/ */ -THREE.FogExp2 = function (color, density) { +THREE.FogExp2 = function ( color, density ) { - this.name = ''; + this.name = ''; - this.color = new THREE.Color(color); - this.density = ( density !== undefined ) ? density : 0.00025; + this.color = new THREE.Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; }; THREE.FogExp2.prototype.clone = function () { - return new THREE.FogExp2(this.color.getHex(), this.density); + return new THREE.FogExp2( this.color.getHex(), this.density ); }; @@ -17862,231 +20142,263 @@ THREE.ShaderChunk = {}; // File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl -THREE.ShaderChunk['alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; +THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl -THREE.ShaderChunk['alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n\tuniform sampler2D alphaMap;\n\n#endif\n"; +THREE.ShaderChunk[ 'alphamap_pars_fragment'] = "#ifdef USE_ALPHAMAP\n\n uniform sampler2D alphaMap;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl -THREE.ShaderChunk['alphatest_fragment'] = "#ifdef ALPHATEST\n\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; +THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/aomap_fragment.glsl -THREE.ShaderChunk['aomap_fragment'] = "#ifdef USE_AOMAP\n\n\ttotalAmbientLight *= ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n#endif\n"; +THREE.ShaderChunk[ 'aomap_fragment'] = "#ifdef USE_AOMAP\n\n totalAmbientLight *= ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/aomap_pars_fragment.glsl -THREE.ShaderChunk['aomap_pars_fragment'] = "#ifdef USE_AOMAP\n\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n\n#endif"; +THREE.ShaderChunk[ 'aomap_pars_fragment'] = "#ifdef USE_AOMAP\n\n uniform sampler2D aoMap;\n uniform float aoMapIntensity;\n\n#endif"; + +// File:src/renderers/shaders/ShaderChunk/begin_vertex.glsl + +THREE.ShaderChunk[ 'begin_vertex'] = "\nvec3 transformed = vec3( position );\n"; + +// File:src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl + +THREE.ShaderChunk[ 'beginnormal_vertex'] = "\nvec3 objectNormal = vec3( normal );\n"; // File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/color_fragment.glsl -THREE.ShaderChunk['color_fragment'] = "#ifdef USE_COLOR\n\n\tdiffuseColor.rgb *= vColor;\n\n#endif"; +THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n diffuseColor.rgb *= vColor;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl -THREE.ShaderChunk['color_pars_fragment'] = "#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif\n"; +THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl -THREE.ShaderChunk['color_pars_vertex'] = "#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif"; +THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n varying vec3 vColor;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/color_vertex.glsl -THREE.ShaderChunk['color_vertex'] = "#ifdef USE_COLOR\n\n\tvColor.xyz = inputToLinear( color.xyz );\n\n#endif"; +THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n vColor.xyz = color.xyz;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/common.glsl -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\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\n\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n\n\treturn normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n\n}\n\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n\n\treturn normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n\n}\n\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\n\treturn - distance * planeNormal + point;\n\n}\n\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n\n}\n\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n\n}\n\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n\n\tif ( decayExponent > 0.0 ) {\n\n\t return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\n\t}\n\n\treturn 1.0;\n\n}\n\nvec3 F_Schlick( in vec3 specularColor, in float dotLH ) {\n\n\treturn ( 1.0 - specularColor ) * pow( 1.0 - dotLH, 5.0 ) + specularColor;\n\n}\n\nfloat G_BlinnPhong_Implicit( /* in float dotNL, in float dotNV */ ) {\n\n\t// geometry term is (nâ‹…l)(nâ‹…v) / 4(nâ‹…l)(nâ‹…v)\n\n\treturn 0.25;\n\n}\n\nfloat D_BlinnPhong( in float shininess, in float dotNH ) {\n\n\t// factor of 1/PI in distribution term omitted\n\n\treturn ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n\n}\n\nvec3 BRDF_BlinnPhong( in vec3 specularColor, in float shininess, in vec3 normal, in vec3 lightDir, in vec3 viewDir ) {\n\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\n\t//float dotNL = saturate( dot( normal, lightDir ) );\n\t//float dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( lightDir, halfDir ) );\n\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\n\tfloat G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );\n\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\n\treturn F * G * D;\n\n}\n\nvec3 inputToLinear( in vec3 a ) {\n\n\t#ifdef GAMMA_INPUT\n\n\t\treturn pow( a, vec3( float( GAMMA_FACTOR ) ) );\n\n\t#else\n\n\t\treturn a;\n\n\t#endif\n\n}\n\nvec3 linearToOutput( in vec3 a ) {\n\n\t#ifdef GAMMA_OUTPUT\n\n\t\treturn pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n\n\t#else\n\n\t\treturn a;\n\n\t#endif\n\n}\n"; +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\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\n\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n\n}\n\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n\n}\n\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n float distance = dot( planeNormal, point - pointOnPlane );\n\n return - distance * planeNormal + point;\n\n}\n\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n return sign( dot( point - pointOnPlane, planeNormal ) );\n\n}\n\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\n return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n\n}\n\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n\n if ( decayExponent > 0.0 ) {\n\n return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\n }\n\n return 1.0;\n\n}\n\nvec3 F_Schlick( in vec3 specularColor, in float dotLH ) {\n\n // Original approximation by Christophe Schlick '94\n //;float fresnel = pow( 1.0 - dotLH, 5.0 );\n\n // Optimized variant (presented by Epic at SIGGRAPH '13)\n float fresnel = exp2( ( -5.55437 * dotLH - 6.98316 ) * dotLH );\n\n return ( 1.0 - specularColor ) * fresnel + specularColor;\n\n}\n\nfloat G_BlinnPhong_Implicit( /* in float dotNL, in float dotNV */ ) {\n\n // geometry term is (nâ‹…l)(nâ‹…v) / 4(nâ‹…l)(nâ‹…v)\n\n return 0.25;\n\n}\n\nfloat D_BlinnPhong( in float shininess, in float dotNH ) {\n\n // factor of 1/PI in distribution term omitted\n\n return ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n\n}\n\nvec3 BRDF_BlinnPhong( in vec3 specularColor, in float shininess, in vec3 normal, in vec3 lightDir, in vec3 viewDir ) {\n\n vec3 halfDir = normalize( lightDir + viewDir );\n\n //float dotNL = saturate( dot( normal, lightDir ) );\n //float dotNV = saturate( dot( normal, viewDir ) );\n float dotNH = saturate( dot( normal, halfDir ) );\n float dotLH = saturate( dot( lightDir, halfDir ) );\n\n vec3 F = F_Schlick( specularColor, dotLH );\n\n float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );\n\n float D = D_BlinnPhong( shininess, dotNH );\n\n return F * G * D;\n\n}\n\nvec3 inputToLinear( in vec3 a ) {\n\n #ifdef GAMMA_INPUT\n\n return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n\n #else\n\n return a;\n\n #endif\n\n}\n\nvec3 linearToOutput( in vec3 a ) {\n\n #ifdef GAMMA_OUTPUT\n\n return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n\n #else\n\n return a;\n\n #endif\n\n}\n"; -// File:src/renderers/shaders/ShaderChunk/default_vertex.glsl +// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl -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[ 'defaultnormal_vertex'] = "#ifdef FLIP_SIDED\n\n objectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n"; -// File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl +// File:src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl + +THREE.ShaderChunk[ 'displacementmap_vertex'] = "#ifdef USE_DISPLACEMENTMAP\n\n transformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n\n#endif\n"; + +// File:src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl + +THREE.ShaderChunk[ 'displacementmap_pars_vertex'] = "#ifdef USE_DISPLACEMENTMAP\n\n uniform sampler2D displacementMap;\n uniform float displacementScale;\n uniform float displacementBias;\n\n#endif\n"; + +// File:src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl + +THREE.ShaderChunk[ 'emissivemap_fragment'] = "#ifdef USE_EMISSIVEMAP\n\n vec4 emissiveColor = texture2D( emissiveMap, vUv );\n\n emissiveColor.rgb = inputToLinear( emissiveColor.rgb );\n\n totalEmissiveLight *= emissiveColor.rgb;\n\n#endif\n"; + +// File:src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl -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[ 'emissivemap_pars_fragment'] = "#ifdef USE_EMISSIVEMAP\n\n uniform sampler2D emissiveMap;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl -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 = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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[ '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 = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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/envmap_pars_fragment.glsl -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[ '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/envmap_pars_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl -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 = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\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[ '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 = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\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/fog_pars_fragment.glsl -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[ '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"; + +// File:src/renderers/shaders/ShaderChunk/hemilight_fragment.glsl + +THREE.ShaderChunk[ 'hemilight_fragment'] = "#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lightDir = hemisphereLightDirection[ i ];\n\n float dotProduct = dot( normal, lightDir );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 lightColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n totalAmbientLight += lightColor;\n\n }\n\n#endif\n\n"; // File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl -THREE.ShaderChunk['lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n\ttotalAmbientLight += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\n#endif\n"; +THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n totalAmbientLight += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl -THREE.ShaderChunk['lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n\n#endif"; +THREE.ShaderChunk[ 'lightmap_pars_fragment'] = "#ifdef USE_LIGHTMAP\n\n uniform sampler2D lightMap;\n uniform float lightMapIntensity;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl -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"; +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"; // File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl -THREE.ShaderChunk['lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack = vec3( 0.0 );\n\n#endif\n\nvec3 normal = normalize( transformedNormal );\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec3 lightColor = pointLightColor[ i ];\n\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\t\t// attenuation\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\tvLightFront += lightColor * attenuation * saturate( dotProduct );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += lightColor * attenuation * saturate( - dotProduct );\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\tvec3 lightColor = spotLightColor[ i ];\n\n\t\tvec3 lightPosition = spotLightPosition[ i ];\n\t\tvec4 lPosition = viewMatrix * vec4( lightPosition, 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( lightPosition - worldPosition.xyz ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) );\n\n\t\t\t// attenuation\n\n\t\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\t\tattenuation *= spotEffect;\n\n\t\t\t// diffuse\n\n\t\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\t\tvLightFront += lightColor * attenuation * saturate( dotProduct );\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tvLightBack += lightColor * attenuation * saturate( - dotProduct );\n\n\t\t\t#endif\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 lightColor = directionalLightColor[ i ];\n\n\t\tvec3 lightDir = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\tvLightFront += lightColor * saturate( dotProduct );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += lightColor * saturate( - dotProduct );\n\n\t\t#endif\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 lightDir = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\tfloat hemiDiffuseWeight = 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\tfloat hemiDiffuseWeightBack = - 0.5 * dotProduct + 0.5;\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[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\nvec3 normal = normalize( transformedNormal );\n\n#if MAX_POINT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec3 lightColor = pointLightColor[ i ];\n\n vec3 lVector = pointLightPosition[ i ] - mvPosition.xyz;\n vec3 lightDir = normalize( lVector );\n\n // attenuation\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n // diffuse\n\n float dotProduct = dot( normal, lightDir );\n\n vLightFront += lightColor * attenuation * saturate( dotProduct );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += lightColor * attenuation * saturate( - dotProduct );\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 vec3 lightColor = spotLightColor[ i ];\n\n vec3 lightPosition = spotLightPosition[ i ];\n vec3 lVector = lightPosition - mvPosition.xyz;\n vec3 lightDir = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], lightDir );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) );\n\n // attenuation\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n attenuation *= spotEffect;\n\n // diffuse\n\n float dotProduct = dot( normal, lightDir );\n\n vLightFront += lightColor * attenuation * saturate( dotProduct );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += lightColor * attenuation * saturate( - dotProduct );\n\n #endif\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 lightColor = directionalLightColor[ i ];\n\n vec3 lightDir = directionalLightDirection[ i ];\n\n // diffuse\n\n float dotProduct = dot( normal, lightDir );\n\n vLightFront += lightColor * saturate( dotProduct );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += lightColor * saturate( - dotProduct );\n\n #endif\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 lightDir = hemisphereLightDirection[ i ];\n\n // diffuse\n\n float dotProduct = dot( normal, lightDir );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n float hemiDiffuseWeightBack = - 0.5 * dotProduct + 0.5;\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"; // File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl -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\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 viewDir = normalize( vViewPosition );\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\tvec3 lightColor = pointLightColor[ i ];\n\n\t\tvec3 lightPosition = pointLightPosition[ i ];\n\t\tvec4 lPosition = viewMatrix * vec4( lightPosition, 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\t\t// attenuation\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\t// diffuse\n\n\t\tfloat cosineTerm = saturate( dot( normal, lightDir ) );\n\n\t\ttotalDiffuseLight += lightColor * attenuation * cosineTerm;\n\n\t\t// specular\n\n\t\tvec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n\t\ttotalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm;\n\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\tvec3 lightColor = spotLightColor[ i ];\n\n\t\tvec3 lightPosition = spotLightPosition[ i ];\n\t\tvec4 lPosition = viewMatrix * vec4( lightPosition, 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\t\tvec3 lightDir = normalize( lVector );\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( lightPosition - vWorldPosition ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) );\n\n\t\t\t// attenuation\n\n\t\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\t\tattenuation *= spotEffect;\n\n\t\t\t// diffuse\n\n\t\t\tfloat cosineTerm = saturate( dot( normal, lightDir ) );\n\n\t\t\ttotalDiffuseLight += lightColor * attenuation * cosineTerm;\n\n\t\t\t// specular\n\n\t\t\tvec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n\t\t\ttotalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm;\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 lightColor = directionalLightColor[ i ];\n\n\t\tvec3 lightDir = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat cosineTerm = saturate( dot( normal, lightDir ) );\n\n\t\ttotalDiffuseLight += lightColor * cosineTerm;\n\n\t\t// specular\n\n\t\tvec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n\t\ttotalSpecularLight += brdf * specularStrength * lightColor * cosineTerm;\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 lightDir = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lightDir );\n\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n\t\tvec3 lightColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n\t\ttotalDiffuseLight += lightColor;\n\n\t\t// specular (sky term only)\n\n\t\tvec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n\t\ttotalSpecularLight += brdf * specularStrength * lightColor * max( dotProduct, 0.0 );\n\n\t}\n\n#endif\n\n#ifdef METAL\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) * specular + totalSpecularLight + emissive;\n\n#else\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) + totalSpecularLight + emissive;\n\n#endif\n"; +THREE.ShaderChunk[ 'lights_phong_fragment'] = "vec3 viewDir = normalize( vViewPosition );\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 vec3 lightColor = pointLightColor[ i ];\n\n vec3 lightPosition = pointLightPosition[ i ];\n vec3 lVector = lightPosition + vViewPosition.xyz;\n vec3 lightDir = normalize( lVector );\n\n // attenuation\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n // diffuse\n\n float cosineTerm = saturate( dot( normal, lightDir ) );\n\n totalDiffuseLight += lightColor * attenuation * cosineTerm;\n\n // specular\n\n vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n totalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm;\n\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 vec3 lightColor = spotLightColor[ i ];\n\n vec3 lightPosition = spotLightPosition[ i ];\n vec3 lVector = lightPosition + vViewPosition.xyz;\n vec3 lightDir = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], lightDir );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) );\n\n // attenuation\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n attenuation *= spotEffect;\n\n // diffuse\n\n float cosineTerm = saturate( dot( normal, lightDir ) );\n\n totalDiffuseLight += lightColor * attenuation * cosineTerm;\n\n // specular\n\n vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n totalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm;\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 lightColor = directionalLightColor[ i ];\n\n vec3 lightDir = directionalLightDirection[ i ];\n\n // diffuse\n\n float cosineTerm = saturate( dot( normal, lightDir ) );\n\n totalDiffuseLight += lightColor * cosineTerm;\n\n // specular\n\n vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir );\n\n totalSpecularLight += brdf * specularStrength * lightColor * cosineTerm;\n\n }\n\n#endif\n\n#ifdef METAL\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) * specular + totalSpecularLight + totalEmissiveLight;\n\n#else\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) + totalSpecularLight + totalEmissiveLight;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl -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\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n\tvarying vec3 vNormal;\n\n#endif\n"; +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_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n varying vec3 vNormal;\n\n#endif\n"; // 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\tvarying vec3 vWorldPosition;\n\n#endif\n"; +THREE.ShaderChunk[ 'lights_phong_pars_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl -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[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP )\n\n vWorldPosition = worldPosition.xyz;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl -THREE.ShaderChunk['linear_to_gamma_fragment'] = "\n\toutgoingLight = linearToOutput( outgoingLight );\n"; +THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n outgoingLight = linearToOutput( outgoingLight );\n"; // File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl -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[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl -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[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n uniform float logDepthBufFC;\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n varying float vFragDepth;\n\n #endif\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/map_fragment.glsl -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[ '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\n"; // File:src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl -THREE.ShaderChunk['map_pars_fragment'] = "#ifdef USE_MAP\n\n\tuniform sampler2D map;\n\n#endif"; +THREE.ShaderChunk[ 'map_pars_fragment'] = "#ifdef USE_MAP\n\n uniform sampler2D map;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl -THREE.ShaderChunk['map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n\n#endif\n"; +THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform vec4 offsetRepeat;\n uniform sampler2D map;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl -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[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n objectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n objectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n objectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n objectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl -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[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n transformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n transformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n transformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n transformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n #ifndef USE_MORPHNORMALS\n\n transformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n transformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n transformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n transformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n #endif\n\n#endif\n"; + +// File:src/renderers/shaders/ShaderChunk/normal_phong_fragment.glsl + +THREE.ShaderChunk[ 'normal_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\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\n"; // File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl -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[ '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"; + +// File:src/renderers/shaders/ShaderChunk/project_vertex.glsl + +THREE.ShaderChunk[ 'project_vertex'] = "#ifdef USE_SKINNING\n\n vec4 mvPosition = modelViewMatrix * skinned;\n\n#else\n\n vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; // File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl -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[ '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 float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n // to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine\n // whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light)\n bool isPointLight = shadowDarkness[ i ] < 0.0;\n\n // get the real shadow darkness\n float realShadowDarkness = abs( shadowDarkness[ i ] );\n\n // for point lights, the uniform @vShadowCoord is re-purposed to hold\n // the distance from the light to the world-space position of the fragment.\n vec3 lightToPosition = vShadowCoord[ i ].xyz;\n\n float texelSizeX = 1.0 / shadowMapSize[ i ].x;\n float texelSizeY = 1.0 / shadowMapSize[ i ].y;\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n float shadow = 0.0;\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 bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest || isPointLight ) { \n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n #if defined(POINT_LIGHT_SHADOWS)\n\n if( isPointLight ) {\n\n float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );\n vec3 baseDirection3D = normalize( lightToPosition );\n vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );\n\n initGridSamplingDisk();\n\n float diskRadius = 1.25;\n float numSamples = 1.0;\n shadow = 0.0;\n\n vec3 baseDirection = normalize( lightToPosition );\n float curDistance = length( lightToPosition );\n\n float dist = unpack1K( texture2D( shadowMap[ i ], baseDirection2D ) ) + 0.1;\n if ( curDistance >= dist )\n shadow += 1.0;\n \n // evaluate each sampling direction\n for( int s = 0; s < 20; s++ ) {\n \n vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;\n vec3 adjustedBaseDirection3D = baseDirection3D + offset;\n vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeY );\n dist = unpack1K( texture2D( shadowMap[ i ], adjustedBaseDirection2D ) ) + shadowBias[ i ];\n if ( curDistance >= dist )\n shadow += 1.0;\n numSamples += 1.0;\n\n }\n\n shadow /= numSamples;\n\n } else {\n\n #endif\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n \n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\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 vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\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 float fDepth = unpackDepth( rgbaDepth );\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n }\n shadow /= 9.0;\n */\n\n shadowCoord.z += shadowBias[ i ];\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = texelSizeX;\n float yPixelOffset = texelSizeY;\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 #if defined(POINT_LIGHT_SHADOWS)\n\n }\n\n #endif\n\n shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n #if defined(POINT_LIGHT_SHADOWS)\n\n if( isPointLight ) {\n\n float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );\n vec3 baseDirection3D = normalize( lightToPosition );\n vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );\n\n initGridSamplingDisk();\n\n float diskRadius = 2.25;\n float numSamples = 1.0;\n shadow = 0.0;\n\n vec3 baseDirection = normalize( lightToPosition );\n float curDistance = length( lightToPosition );\n\n float dist = unpack1K( texture2D( shadowMap[ i ], baseDirection2D ) ) + 0.1;\n if ( curDistance >= dist )\n shadow += 1.0;\n\n // evaluate each sampling direction\n for( int s = 0; s < 20; s++ ) {\n\n vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;\n vec3 adjustedBaseDirection3D = baseDirection3D + offset;\n vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeY );\n dist = unpack1K( texture2D( shadowMap[ i ], adjustedBaseDirection2D ) ) + shadowBias[ i ];\n if ( curDistance >= dist )\n shadow += 1.0;\n numSamples += 1.0;\n\n }\n\n shadow /= numSamples;\n\n } else {\n\n #endif\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n shadowCoord.z += shadowBias[ i ];\n\n float xPixelOffset = texelSizeX;\n float yPixelOffset = texelSizeY;\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 #if defined(POINT_LIGHT_SHADOWS)\n \n }\n\n #endif\n\n shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );\n\n #else\n\n #if defined(POINT_LIGHT_SHADOWS)\n\n if( isPointLight ) {\n\n vec3 baseDirection3D = normalize( lightToPosition );\n vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );\n vec4 data = texture2D( shadowMap[ i ], baseDirection2D );\n float dist = unpack1K( data ) + shadowBias[ i ];\n if ( length( lightToPosition ) >= dist)\n shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );\n\n } else {\n\n #endif\n shadowCoord.z += shadowBias[ i ];\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 - realShadowDarkness );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( realShadowDarkness ) );\n\n #if defined(POINT_LIGHT_SHADOWS)\n\n }\n\n #endif\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n #endif\n\n }\n\n outgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl -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[ '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 #if defined(POINT_LIGHT_SHADOWS)\n\n float unpack1K ( vec4 color ) {\n\n const vec4 bitSh = vec4( 1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0 );\n return dot( color, bitSh ) * 1000.0;\n\n }\n\n // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D\n // vector suitable for 2D texture mapping. This code uses the following layout for the\n // 2D texture:\n //\n // xzXZ\n // y Y\n //\n // Y - Positive y direction\n // y - Negative y direction\n // X - Positive x direction\n // x - Negative x direction\n // Z - Positive z direction\n // z - Negative z direction\n //\n // Source and test bed:\n // https://gist.github.com/tschw/da10c43c467ce8afd0c4\n\n vec2 cubeToUV( vec3 v, float texelSizeY ) {\n\n // Number of texels to avoid at the edge of each square\n\n vec3 absV = abs( v );\n\n // Intersect unit cube\n\n float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n absV *= scaleToCube;\n\n // Apply scale to avoid seams\n\n // two texels less per square (one texel will do for NEAREST)\n v *= scaleToCube * ( 1.0 - 4.0 * texelSizeY );\n\n // Unwrap\n\n // space: -1 ... 1 range for each square\n //\n // #X## dim := ( 4 , 2 )\n // # # center := ( 1 , 1 )\n\n vec2 planar = v.xy;\n\n float almostATexel = 1.5 * texelSizeY;\n float almostOne = 1.0 - almostATexel;\n\n if ( absV.z >= almostOne ) {\n\n if ( v.z > 0.0 )\n planar.x = 4.0 - v.x;\n\n } else if ( absV.x >= almostOne ) {\n\n float signX = sign( v.x );\n planar.x = v.z * signX + 2.0 * signX;\n\n } else if ( absV.y >= almostOne ) {\n\n float signY = sign( v.y );\n planar.x = v.x + 2.0 * signY + 2.0;\n planar.y = v.z * signY - 2.0;\n\n }\n\n // Transform to UV space\n\n // scale := 0.5 / dim\n // translate := ( center + 0.5 ) / dim\n return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\n }\n\n vec3 gridSamplingDisk[ 20 ];\n bool gridSamplingInitialized = false;\n\n void initGridSamplingDisk() {\n\n if( gridSamplingInitialized ) {\n\n return;\n\n }\n\n gridSamplingDisk[0] = vec3(1, 1, 1);\n gridSamplingDisk[1] = vec3(1, -1, 1);\n gridSamplingDisk[2] = vec3(-1, -1, 1);\n gridSamplingDisk[3] = vec3(-1, 1, 1);\n gridSamplingDisk[4] = vec3(1, 1, -1);\n gridSamplingDisk[5] = vec3(1, -1, -1);\n gridSamplingDisk[6] = vec3(-1, -1, -1);\n gridSamplingDisk[7] = vec3(-1, 1, -1);\n gridSamplingDisk[8] = vec3(1, 1, 0);\n gridSamplingDisk[9] = vec3(1, -1, 0);\n gridSamplingDisk[10] = vec3(-1, -1, 0);\n gridSamplingDisk[11] = vec3(-1, 1, 0);\n gridSamplingDisk[12] = vec3(1, 0, 1);\n gridSamplingDisk[13] = vec3(-1, 0, 1);\n gridSamplingDisk[14] = vec3(1, 0, -1);\n gridSamplingDisk[15] = vec3(-1, 0, -1);\n gridSamplingDisk[16] = vec3(0, 1, 1);\n gridSamplingDisk[17] = vec3(0, -1, 1);\n gridSamplingDisk[18] = vec3(0, -1, -1);\n gridSamplingDisk[19] = vec3(0, 1, -1);\n\n gridSamplingInitialized = true;\n\n }\n\n #endif\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl -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[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n uniform float shadowDarkness[ MAX_SHADOWS ];\n uniform mat4 shadowMatrix[ MAX_SHADOWS ];\n varying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl -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[ 'shadowmap_vertex'] = "#ifdef USE_SHADOWMAP\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n #if defined(POINT_LIGHT_SHADOWS)\n\n // if shadowDarkness[ i ] < 0.0, that means we have a point light with a cube\n // shadow map\n if( shadowDarkness[ i ] < 0.0 ) {\n\n // calculate vector from light to vertex in view space\n\n vec3 fromLight = mvPosition.xyz - pointLightPosition[ i ];\n\n // Transform 'fromLight' into world space by multiplying it on the left\n // side of 'viewMatrix'. This is equivalent to multiplying it on the right\n // side of the transpose of 'viewMatrix'. Since 'viewMatrix' is orthogonal, \n // its transpose is the same as its inverse.\n\n fromLight = fromLight * mat3( viewMatrix );\n\n // We repurpose vShadowCoord to hold the distance in world space from the\n // light to the vertex. This value will be interpolated correctly in the fragment shader.\n\n vShadowCoord[ i ] = vec4( fromLight, 1.0 );\n\n } else {\n\n vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n }\n\n #else\n\n vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n #endif\n\n }\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl -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[ '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/skinning_pars_vertex.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl -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[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\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"; // File:src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl -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[ '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 objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl -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[ '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"; // File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl -THREE.ShaderChunk['specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n\tuniform sampler2D specularMap;\n\n#endif"; +THREE.ShaderChunk[ 'specularmap_pars_fragment'] = "#ifdef USE_SPECULARMAP\n\n uniform sampler2D specularMap;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/uv2_pars_fragment.glsl -THREE.ShaderChunk['uv2_pars_fragment'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tvarying vec2 vUv2;\n\n#endif"; +THREE.ShaderChunk[ 'uv2_pars_fragment'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n varying vec2 vUv2;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/uv2_pars_vertex.glsl -THREE.ShaderChunk['uv2_pars_vertex'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\n#endif"; +THREE.ShaderChunk[ 'uv2_pars_vertex'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n attribute vec2 uv2;\n varying vec2 vUv2;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/uv2_vertex.glsl -THREE.ShaderChunk['uv2_vertex'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n\tvUv2 = uv2;\n\n#endif"; +THREE.ShaderChunk[ 'uv2_vertex'] = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\n vUv2 = uv2;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl -THREE.ShaderChunk['uv_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"; +THREE.ShaderChunk[ 'uv_pars_fragment'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n varying vec2 vUv;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl -THREE.ShaderChunk['uv_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[ 'uv_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n varying vec2 vUv;\n uniform vec4 offsetRepeat;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/uv_vertex.glsl -THREE.ShaderChunk['uv_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[ 'uv_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP )\n\n vUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl -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[ '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 #else\n\n vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\n #endif\n\n#endif\n"; // File:src/renderers/shaders/UniformsUtils.js @@ -18096,65 +20408,65 @@ THREE.ShaderChunk['worldpos_vertex'] = "#if defined( USE_ENVMAP ) || defined( PH THREE.UniformsUtils = { - merge: function (uniforms) { + merge: function ( uniforms ) { - var merged = {}; + var merged = {}; - for (var u = 0; u < uniforms.length; u++) { + for ( var u = 0; u < uniforms.length; u ++ ) { - var tmp = this.clone(uniforms[u]); + var tmp = this.clone( uniforms[ u ] ); - for (var p in tmp) { + for ( var p in tmp ) { - merged[p] = tmp[p]; + merged[ p ] = tmp[ p ]; - } + } - } + } - return merged; + return merged; - }, + }, - clone: function (uniforms_src) { + clone: function ( uniforms_src ) { - var uniforms_dst = {}; + var uniforms_dst = {}; - for (var u in uniforms_src) { + for ( var u in uniforms_src ) { - uniforms_dst[u] = {}; + uniforms_dst[ u ] = {}; - for (var p in uniforms_src[u]) { + for ( var p in uniforms_src[ u ] ) { - var parameter_src = uniforms_src[u][p]; + 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.Matrix3 || - parameter_src instanceof THREE.Matrix4 || - parameter_src instanceof THREE.Texture) { + 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.Matrix3 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { - uniforms_dst[u][p] = parameter_src.clone(); + uniforms_dst[ u ][ p ] = parameter_src.clone(); - } else if (parameter_src instanceof Array) { + } else if ( Array.isArray( parameter_src ) ) { - uniforms_dst[u][p] = parameter_src.slice(); + uniforms_dst[ u ][ p ] = parameter_src.slice(); - } else { + } else { - uniforms_dst[u][p] = parameter_src; + uniforms_dst[ u ][ p ] = parameter_src; - } + } - } + } - } + } - return uniforms_dst; + return uniforms_dst; - } + } }; @@ -18166,115 +20478,128 @@ THREE.UniformsUtils = { THREE.UniformsLib = { - common: { + common: { - "diffuse": {type: "c", value: new THREE.Color(0xeeeeee)}, - "opacity": {type: "f", value: 1.0}, + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, - "map": {type: "t", value: null}, - "offsetRepeat": {type: "v4", value: new THREE.Vector4(0, 0, 1, 1)}, + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "specularMap": {type: "t", value: null}, - "alphaMap": {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}, + "envMap" : { type: "t", value: null }, + "flipEnvMap" : { type: "f", value: - 1 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 } - "morphTargetInfluences": {type: "f", value: 0} + }, - }, + aomap: { - aomap: { + "aoMap" : { type: "t", value: null }, + "aoMapIntensity" : { type: "f", value: 1 }, - "aoMap": {type: "t", value: null}, - "aoMapIntensity": {type: "f", value: 1}, + }, - }, + lightmap: { - lightmap: { + "lightMap" : { type: "t", value: null }, + "lightMapIntensity" : { type: "f", value: 1 }, - "lightMap": {type: "t", value: null}, - "lightMapIntensity": {type: "f", value: 1}, + }, - }, + emissivemap: { - bump: { + "emissiveMap" : { type: "t", value: null }, - "bumpMap": {type: "t", value: null}, - "bumpScale": {type: "f", value: 1} + }, - }, + bumpmap: { - normalmap: { + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 } - "normalMap": {type: "t", value: null}, - "normalScale": {type: "v2", value: new THREE.Vector2(1, 1)} - }, + }, - fog: { + normalmap: { - "fogDensity": {type: "f", value: 0.00025}, - "fogNear": {type: "f", value: 1}, - "fogFar": {type: "f", value: 2000}, - "fogColor": {type: "c", value: new THREE.Color(0xffffff)} + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } - }, + }, - lights: { + displacementmap: { - "ambientLightColor": {type: "fv", value: []}, + "displacementMap" : { type: "t", value: null }, + "displacementScale" : { type: "f", value: 1 }, + "displacementBias" : { type: "f", value: 0 } - "directionalLightDirection": {type: "fv", value: []}, - "directionalLightColor": {type: "fv", value: []}, + }, - "hemisphereLightDirection": {type: "fv", value: []}, - "hemisphereLightSkyColor": {type: "fv", value: []}, - "hemisphereLightGroundColor": {type: "fv", value: []}, + fog : { - "pointLightColor": {type: "fv", value: []}, - "pointLightPosition": {type: "fv", value: []}, - "pointLightDistance": {type: "fv1", value: []}, - "pointLightDecay": {type: "fv1", value: []}, + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - "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: []} + }, - }, + lights: { - particle: { + "ambientLightColor" : { type: "fv", value: [] }, - "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)}, + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, - "fogDensity": {type: "f", value: 0.00025}, - "fogNear": {type: "f", value: 1}, - "fogFar": {type: "f", value: 2000}, - "fogColor": {type: "c", value: new THREE.Color(0xffffff)} + "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: [] }, - shadowmap: { + "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: [] } - "shadowMap": {type: "tv", value: []}, - "shadowMapSize": {type: "v2v", value: []}, + }, - "shadowBias": {type: "fv1", value: []}, - "shadowDarkness": {type: "fv1", value: []}, + points: { - "shadowMatrix": {type: "m4v", value: []} + "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 ) }, - } + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + shadowmap: { + + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, + + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, + + "shadowMatrix" : { type: "m4v", value: [] } + + } }; @@ -18291,820 +20616,904 @@ THREE.UniformsLib = { THREE.ShaderLib = { - 'basic': { + 'basic': { - uniforms: THREE.UniformsUtils.merge([ + uniforms: THREE.UniformsUtils.merge( [ - THREE.UniformsLib["common"], - THREE.UniformsLib["fog"], - THREE.UniformsLib["shadowmap"] + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "aomap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] - ]), + ] ), - vertexShader: [ + vertexShader: [ - THREE.ShaderChunk["common"], - THREE.ShaderChunk["uv_pars_vertex"], - THREE.ShaderChunk["uv2_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"], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "uv_pars_vertex" ], + THREE.ShaderChunk[ "uv2_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() {", + "void main() {", - THREE.ShaderChunk["uv_vertex"], - THREE.ShaderChunk["uv2_vertex"], - THREE.ShaderChunk["color_vertex"], - THREE.ShaderChunk["skinbase_vertex"], + THREE.ShaderChunk[ "uv_vertex" ], + THREE.ShaderChunk[ "uv2_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], - " #ifdef USE_ENVMAP", + " #ifdef USE_ENVMAP", - THREE.ShaderChunk["morphnormal_vertex"], - THREE.ShaderChunk["skinnormal_vertex"], - THREE.ShaderChunk["defaultnormal_vertex"], + THREE.ShaderChunk[ "beginnormal_vertex" ], + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - " #endif", + " #endif", - THREE.ShaderChunk["morphtarget_vertex"], - THREE.ShaderChunk["skinning_vertex"], - THREE.ShaderChunk["default_vertex"], - THREE.ShaderChunk["logdepthbuf_vertex"], + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["worldpos_vertex"], - THREE.ShaderChunk["envmap_vertex"], - THREE.ShaderChunk["shadowmap_vertex"], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "}" + "}" - ].join("\n"), + ].join( "\n" ), - fragmentShader: [ + fragmentShader: [ - "uniform vec3 diffuse;", - "uniform float opacity;", + "uniform vec3 diffuse;", + "uniform float opacity;", - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_fragment"], - THREE.ShaderChunk["uv_pars_fragment"], - THREE.ShaderChunk["uv2_pars_fragment"], - THREE.ShaderChunk["map_pars_fragment"], - THREE.ShaderChunk["alphamap_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"], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "uv_pars_fragment" ], + THREE.ShaderChunk[ "uv2_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "aomap_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() {", + "void main() {", - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", + " vec4 diffuseColor = vec4( diffuse, opacity );", + " vec3 totalAmbientLight = vec3( 1.0 );", // hardwired - 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[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "aomap_fragment" ], - " outgoingLight = diffuseColor.rgb;", // simple shader + " outgoingLight = diffuseColor.rgb * totalAmbientLight;", // simple shader - THREE.ShaderChunk["envmap_fragment"], - THREE.ShaderChunk["shadowmap_fragment"], // TODO: Shadows 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. - THREE.ShaderChunk["linear_to_gamma_fragment"], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk["fog_fragment"], + THREE.ShaderChunk[ "fog_fragment" ], - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - "}" + "}" - ].join("\n") + ].join( "\n" ) - }, + }, - 'lambert': { + 'lambert': { - uniforms: THREE.UniformsUtils.merge([ + uniforms: THREE.UniformsUtils.merge( [ - THREE.UniformsLib["common"], - THREE.UniformsLib["fog"], - THREE.UniformsLib["lights"], - THREE.UniformsLib["shadowmap"], + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - { - "emissive": {type: "c", value: new THREE.Color(0x000000)} - } + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) } + } - ]), + ] ), - vertexShader: [ + vertexShader: [ - "#define LAMBERT", + "#define LAMBERT", - "varying vec3 vLightFront;", + "varying vec3 vLightFront;", - "#ifdef DOUBLE_SIDED", + "#ifdef DOUBLE_SIDED", - " varying vec3 vLightBack;", + " varying vec3 vLightBack;", - "#endif", + "#endif", - THREE.ShaderChunk["common"], - THREE.ShaderChunk["uv_pars_vertex"], - THREE.ShaderChunk["uv2_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"], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "uv_pars_vertex" ], + THREE.ShaderChunk[ "uv2_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() {", + "void main() {", - THREE.ShaderChunk["uv_vertex"], - THREE.ShaderChunk["uv2_vertex"], - THREE.ShaderChunk["color_vertex"], + THREE.ShaderChunk[ "uv_vertex" ], + THREE.ShaderChunk[ "uv2_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk["morphnormal_vertex"], - THREE.ShaderChunk["skinbase_vertex"], - THREE.ShaderChunk["skinnormal_vertex"], - THREE.ShaderChunk["defaultnormal_vertex"], + THREE.ShaderChunk[ "beginnormal_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[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["worldpos_vertex"], - THREE.ShaderChunk["envmap_vertex"], - THREE.ShaderChunk["lights_lambert_vertex"], - THREE.ShaderChunk["shadowmap_vertex"], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - "}" + "}" - ].join("\n"), + ].join( "\n" ), - fragmentShader: [ + fragmentShader: [ - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - "uniform float opacity;", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform float opacity;", - "varying vec3 vLightFront;", + "varying vec3 vLightFront;", - "#ifdef DOUBLE_SIDED", + "#ifdef DOUBLE_SIDED", - " varying vec3 vLightBack;", + " varying vec3 vLightBack;", - "#endif", + "#endif", - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_fragment"], - THREE.ShaderChunk["uv_pars_fragment"], - THREE.ShaderChunk["uv2_pars_fragment"], - THREE.ShaderChunk["map_pars_fragment"], - THREE.ShaderChunk["alphamap_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"], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "uv_pars_fragment" ], + THREE.ShaderChunk[ "uv2_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_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() {", + "void main() {", - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 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[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphamap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], - " #ifdef DOUBLE_SIDED", + " #ifdef DOUBLE_SIDED", - //"float isFront = float( gl_FrontFacing );", - //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", + " if ( gl_FrontFacing )", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", + " else", + " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", - " if ( gl_FrontFacing )", - " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - " else", - " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", + " #else", - " #else", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", - " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", + " #endif", - " #endif", + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk["envmap_fragment"], - THREE.ShaderChunk["shadowmap_fragment"], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk["linear_to_gamma_fragment"], + THREE.ShaderChunk[ "fog_fragment" ], - THREE.ShaderChunk["fog_fragment"], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + 'phong': { - 'phong': { + uniforms: THREE.UniformsUtils.merge( [ - uniforms: THREE.UniformsUtils.merge([ + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "aomap" ], + THREE.UniformsLib[ "lightmap" ], + THREE.UniformsLib[ "emissivemap" ], + THREE.UniformsLib[ "bumpmap" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "displacementmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], - THREE.UniformsLib["common"], - THREE.UniformsLib["aomap"], - THREE.UniformsLib["lightmap"], - THREE.UniformsLib["bump"], - THREE.UniformsLib["normalmap"], - THREE.UniformsLib["fog"], - THREE.UniformsLib["lights"], - THREE.UniformsLib["shadowmap"], + { + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 } + } - { - "emissive": {type: "c", value: new THREE.Color(0x000000)}, - "specular": {type: "c", value: new THREE.Color(0x111111)}, - "shininess": {type: "f", value: 30} - } + ] ), - ]), + vertexShader: [ - vertexShader: [ + "#define PHONG", - "#define PHONG", + "varying vec3 vViewPosition;", - "varying vec3 vViewPosition;", + "#ifndef FLAT_SHADED", - "#ifndef FLAT_SHADED", + " varying vec3 vNormal;", - " varying vec3 vNormal;", + "#endif", - "#endif", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "uv_pars_vertex" ], + THREE.ShaderChunk[ "uv2_pars_vertex" ], + THREE.ShaderChunk[ "displacementmap_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" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["uv_pars_vertex"], - THREE.ShaderChunk["uv2_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() {", - "void main() {", + THREE.ShaderChunk[ "uv_vertex" ], + THREE.ShaderChunk[ "uv2_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk["uv_vertex"], - THREE.ShaderChunk["uv2_vertex"], - THREE.ShaderChunk["color_vertex"], + THREE.ShaderChunk[ "beginnormal_vertex" ], + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], - THREE.ShaderChunk["morphnormal_vertex"], - THREE.ShaderChunk["skinbase_vertex"], - THREE.ShaderChunk["skinnormal_vertex"], - THREE.ShaderChunk["defaultnormal_vertex"], + "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED - "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED + " vNormal = normalize( transformedNormal );", - " vNormal = normalize( transformedNormal );", + "#endif", - "#endif", + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "displacementmap_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["morphtarget_vertex"], - THREE.ShaderChunk["skinning_vertex"], - THREE.ShaderChunk["default_vertex"], - THREE.ShaderChunk["logdepthbuf_vertex"], + " vViewPosition = - mvPosition.xyz;", - " vViewPosition = -mvPosition.xyz;", + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "envmap_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - THREE.ShaderChunk["worldpos_vertex"], - THREE.ShaderChunk["envmap_vertex"], - THREE.ShaderChunk["lights_phong_vertex"], - THREE.ShaderChunk["shadowmap_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "#define PHONG", - "#define PHONG", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", - "uniform float opacity;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "uv_pars_fragment" ], + THREE.ShaderChunk[ "uv2_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "alphamap_pars_fragment" ], + THREE.ShaderChunk[ "aomap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "emissivemap_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" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_fragment"], - THREE.ShaderChunk["uv_pars_fragment"], - THREE.ShaderChunk["uv2_pars_fragment"], - THREE.ShaderChunk["map_pars_fragment"], - THREE.ShaderChunk["alphamap_pars_fragment"], - THREE.ShaderChunk["aomap_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() {", - "void main() {", + " vec3 outgoingLight = vec3( 0.0 );", + " vec4 diffuseColor = vec4( diffuse, opacity );", + " vec3 totalAmbientLight = ambientLightColor;", + " vec3 totalEmissiveLight = emissive;", - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", - " vec3 totalAmbientLight = ambientLightColor;", + 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[ "normal_phong_fragment" ], + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "hemilight_fragment" ], + THREE.ShaderChunk[ "aomap_fragment" ], + THREE.ShaderChunk[ "emissivemap_fragment" ], - 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["lightmap_fragment"], - THREE.ShaderChunk["aomap_fragment"], + THREE.ShaderChunk[ "lights_phong_fragment" ], - THREE.ShaderChunk["lights_phong_fragment"], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk["envmap_fragment"], - THREE.ShaderChunk["shadowmap_fragment"], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk["linear_to_gamma_fragment"], + THREE.ShaderChunk[ "fog_fragment" ], - THREE.ShaderChunk["fog_fragment"], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + 'points': { - 'particle_basic': { + uniforms: THREE.UniformsUtils.merge( [ - uniforms: THREE.UniformsUtils.merge([ + THREE.UniformsLib[ "points" ], + THREE.UniformsLib[ "shadowmap" ] - THREE.UniformsLib["particle"], - THREE.UniformsLib["shadowmap"] + ] ), - ]), + vertexShader: [ - vertexShader: [ + "uniform float size;", + "uniform float scale;", - "uniform float size;", - "uniform float scale;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_vertex"], - THREE.ShaderChunk["shadowmap_pars_vertex"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk["color_vertex"], + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + " #ifdef USE_SIZEATTENUATION", + " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + " #else", + " gl_PointSize = size;", + " #endif", - " #ifdef USE_SIZEATTENUATION", - " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", - " #else", - " gl_PointSize = size;", - " #endif", + " gl_Position = projectionMatrix * mvPosition;", - " gl_Position = projectionMatrix * mvPosition;", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], - THREE.ShaderChunk["logdepthbuf_vertex"], - THREE.ShaderChunk["worldpos_vertex"], - THREE.ShaderChunk["shadowmap_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform vec3 psColor;", + "uniform float opacity;", - "uniform vec3 psColor;", - "uniform 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" ], - 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() {", - "void main() {", + " vec3 outgoingLight = vec3( 0.0 );", + " vec4 diffuseColor = vec4( psColor, opacity );", - " 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" ], - THREE.ShaderChunk["logdepthbuf_fragment"], - THREE.ShaderChunk["map_particle_fragment"], - THREE.ShaderChunk["color_fragment"], - THREE.ShaderChunk["alphatest_fragment"], + " outgoingLight = diffuseColor.rgb;", // simple shader - " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], - THREE.ShaderChunk["shadowmap_fragment"], - THREE.ShaderChunk["fog_fragment"], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + 'dashed': { - 'dashed': { + uniforms: THREE.UniformsUtils.merge( [ - uniforms: THREE.UniformsUtils.merge([ + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], - THREE.UniformsLib["common"], - THREE.UniformsLib["fog"], + { + "scale" : { type: "f", value: 1 }, + "dashSize" : { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } - { - "scale": {type: "f", value: 1}, - "dashSize": {type: "f", value: 1}, - "totalSize": {type: "f", value: 2} - } + ] ), - ]), + vertexShader: [ - vertexShader: [ + "uniform float scale;", + "attribute float lineDistance;", - "uniform float scale;", - "attribute float lineDistance;", + "varying float vLineDistance;", - "varying float vLineDistance;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_vertex"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk["color_vertex"], + " vLineDistance = scale * lineDistance;", - " vLineDistance = scale * lineDistance;", + " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + " gl_Position = projectionMatrix * mvPosition;", - " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * mvPosition;", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["logdepthbuf_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform vec3 diffuse;", + "uniform float opacity;", - "uniform vec3 diffuse;", - "uniform float opacity;", + "uniform float dashSize;", + "uniform float totalSize;", - "uniform float dashSize;", - "uniform float totalSize;", + "varying float vLineDistance;", - "varying float vLineDistance;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["color_pars_fragment"], - THREE.ShaderChunk["fog_pars_fragment"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + "void main() {", - "void main() {", + " if ( mod( vLineDistance, totalSize ) > dashSize ) {", - " if ( mod( vLineDistance, totalSize ) > dashSize ) {", + " discard;", - " discard;", + " }", - " }", + " vec3 outgoingLight = vec3( 0.0 );", + " vec4 diffuseColor = vec4( diffuse, opacity );", - " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does - " vec4 diffuseColor = vec4( diffuse, opacity );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk["logdepthbuf_fragment"], - THREE.ShaderChunk["color_fragment"], + " outgoingLight = diffuseColor.rgb;", // simple shader - " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "fog_fragment" ], - THREE.ShaderChunk["fog_fragment"], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", - " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + 'depth': { - 'depth': { + uniforms: { - uniforms: { + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } - "mNear": {type: "f", value: 1.0}, - "mFar": {type: "f", value: 2000.0}, - "opacity": {type: "f", value: 1.0} + }, - }, + vertexShader: [ - vertexShader: [ + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["morphtarget_pars_vertex"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["morphtarget_vertex"], - THREE.ShaderChunk["default_vertex"], - THREE.ShaderChunk["logdepthbuf_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", - "uniform float mNear;", - "uniform float mFar;", - "uniform float opacity;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + "void main() {", - "void main() {", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk["logdepthbuf_fragment"], + " #ifdef USE_LOGDEPTHBUF_EXT", - " #ifdef USE_LOGDEPTHBUF_EXT", + " float depth = gl_FragDepthEXT / gl_FragCoord.w;", - " float depth = gl_FragDepthEXT / gl_FragCoord.w;", + " #else", - " #else", + " float depth = gl_FragCoord.z / gl_FragCoord.w;", - " float depth = gl_FragCoord.z / gl_FragCoord.w;", + " #endif", - " #endif", + " float color = 1.0 - smoothstep( mNear, mFar, depth );", + " gl_FragColor = vec4( vec3( color ), opacity );", - " 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 + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + 'normal': { - 'normal': { + uniforms: { - uniforms: { + "opacity" : { type: "f", value: 1.0 } - "opacity": {type: "f", value: 1.0} + }, - }, + vertexShader: [ - vertexShader: [ + "varying vec3 vNormal;", - "varying vec3 vNormal;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["morphtarget_pars_vertex"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + " vNormal = normalize( normalMatrix * normal );", - " vNormal = normalize( normalMatrix * normal );", + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["morphtarget_vertex"], - THREE.ShaderChunk["default_vertex"], - THREE.ShaderChunk["logdepthbuf_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform float opacity;", + "varying vec3 vNormal;", - "uniform float opacity;", - "varying vec3 vNormal;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + "void main() {", - "void main() {", + " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", - " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk["logdepthbuf_fragment"], + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ + 'cube': { - 'cube': { + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, - uniforms: { - "tCube": {type: "t", value: null}, - "tFlip": {type: "f", value: -1} - }, + vertexShader: [ - vertexShader: [ + "varying vec3 vWorldPosition;", - "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + " vWorldPosition = transformDirection( position, modelMatrix );", - " vWorldPosition = transformDirection( position, modelMatrix );", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["logdepthbuf_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform samplerCube tCube;", + "uniform float tFlip;", - "uniform samplerCube tCube;", - "uniform float tFlip;", + "varying vec3 vWorldPosition;", - "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + "void main() {", - "void main() {", + " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", - " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - THREE.ShaderChunk["logdepthbuf_fragment"], + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ + 'equirect': { - 'equirect': { + uniforms: { "tEquirect": { type: "t", value: null }, + "tFlip": { type: "f", value: - 1 } }, - uniforms: { - "tEquirect": {type: "t", value: null}, - "tFlip": {type: "f", value: -1} - }, + vertexShader: [ - vertexShader: [ + "varying vec3 vWorldPosition;", - "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + " vWorldPosition = transformDirection( position, modelMatrix );", - " vWorldPosition = transformDirection( position, modelMatrix );", + " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - THREE.ShaderChunk["logdepthbuf_vertex"], + "}" - "}" + ].join( "\n" ), - ].join("\n"), + fragmentShader: [ - fragmentShader: [ + "uniform sampler2D tEquirect;", + "uniform float tFlip;", - "uniform sampler2D tEquirect;", - "uniform float tFlip;", + "varying vec3 vWorldPosition;", - "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + "void main() {", - "void main() {", + // " 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 );", - // " 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" ], - THREE.ShaderChunk["logdepthbuf_fragment"], + "}" - "}" + ].join( "\n" ) - ].join("\n") + }, - }, + /* 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/ + */ - /* 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': { - 'depthRGBA': { + uniforms: {}, - uniforms: {}, + vertexShader: [ - vertexShader: [ + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], - THREE.ShaderChunk["common"], - THREE.ShaderChunk["morphtarget_pars_vertex"], - THREE.ShaderChunk["skinning_pars_vertex"], - THREE.ShaderChunk["logdepthbuf_pars_vertex"], + "void main() {", - "void main() {", + THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk["skinbase_vertex"], - THREE.ShaderChunk["morphtarget_vertex"], - THREE.ShaderChunk["skinning_vertex"], - THREE.ShaderChunk["default_vertex"], - THREE.ShaderChunk["logdepthbuf_vertex"], + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "logdepthbuf_vertex" ], - "}" + "}" - ].join("\n"), + ].join( "\n" ), - fragmentShader: [ + fragmentShader: [ - THREE.ShaderChunk["common"], - THREE.ShaderChunk["logdepthbuf_pars_fragment"], + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], - "vec4 pack_depth( const in float depth ) {", + "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 = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " 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() {", + "void main() {", - THREE.ShaderChunk["logdepthbuf_fragment"], + THREE.ShaderChunk[ "logdepthbuf_fragment" ], - " #ifdef USE_LOGDEPTHBUF_EXT", + " #ifdef USE_LOGDEPTHBUF_EXT", - " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", + " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", - " #else", + " #else", - " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", - " #endif", + " #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 );", - //"gl_FragData[ 0 ] = pack_depth( z );", - //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + //"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 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", - "}" + "}" - ].join("\n") + ].join( "\n" ) - } + }, + + + 'distanceRGBA': { + + uniforms: { + + "lightPos": { type: "v3", value: new THREE.Vector3( 0, 0, 0 ) } + + }, + + vertexShader: [ + + "varying vec4 vWorldPosition;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "begin_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "project_vertex" ], + THREE.ShaderChunk[ "worldpos_vertex" ], + + "vWorldPosition = worldPosition;", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform vec3 lightPos;", + "varying vec4 vWorldPosition;", + + THREE.ShaderChunk[ "common" ], + + "vec4 pack1K ( float depth ) {", + + " depth /= 1000.0;", + " const vec4 bitSh = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bitMsk = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = fract( depth * bitSh );", + " res -= res.xxyz * bitMsk;", + " return res; ", + + "}", + + "float unpack1K ( vec4 color ) {", + + " const vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", + " return dot( color, bitSh ) * 1000.0;", + + "}", + + "void main () {", + + " gl_FragColor = pack1K( length( vWorldPosition.xyz - lightPos.xyz ) );", + + "}" + + ].join( "\n" ) + + } }; + // File:src/renderers/WebGLRenderer.js /** @@ -19114,6120 +21523,6099 @@ THREE.ShaderLib = { * @author szimek / https://github.com/szimek/ */ -THREE.WebGLRenderer = function (parameters) { +THREE.WebGLRenderer = function ( parameters ) { - console.log('THREE.WebGLRenderer', THREE.REVISION); + console.log( 'THREE.WebGLRenderer', THREE.REVISION ); - parameters = parameters || {}; + parameters = parameters || {}; - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement('canvas'), - _context = parameters.context !== undefined ? parameters.context : null, + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, - _width = _canvas.width, - _height = _canvas.height, + _width = _canvas.width, + _height = _canvas.height, - pixelRatio = 1, + pixelRatio = 1, - _precision = parameters.precision !== undefined ? parameters.precision : 'highp', + _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, - _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; - _clearColor = new THREE.Color(0x000000), - _clearAlpha = 0; + var lights = []; - var lights = []; + var opaqueObjects = []; + var opaqueObjectsLastIndex = -1; + var transparentObjects = []; + var transparentObjectsLastIndex = -1; - var opaqueObjects = []; - var transparentObjects = []; + var morphInfluences = new Float32Array( 8 ); - var sprites = []; - var lensFlares = []; - // public properties + var sprites = []; + var lensFlares = []; - this.domElement = _canvas; - this.context = null; + // public properties - // clearing + this.domElement = _canvas; + this.context = null; - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + // clearing - // scene graph + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; - this.sortObjects = true; + // scene graph - // physically based shading + this.sortObjects = true; - this.gammaFactor = 2.0; // for backwards compatibility - this.gammaInput = false; - this.gammaOutput = false; + // physically based shading - // morphs + this.gammaFactor = 2.0; // for backwards compatibility + this.gammaInput = false; + this.gammaOutput = false; - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; + // morphs - // flags + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; - this.autoScaleCubemaps = true; + // flags - // info + this.autoScaleCubemaps = true; - this.info = { + // internal properties - memory: { + var _this = this, - programs: 0, - geometries: 0, - textures: 0 + // internal state cache - }, + _currentProgram = null, + _currentFramebuffer = null, + _currentMaterialId = - 1, + _currentGeometryProgram = '', + _currentCamera = null, - render: { + _usedTextureUnits = 0, - calls: 0, - vertices: 0, - faces: 0, - points: 0 + _viewportX = 0, + _viewportY = 0, + _viewportWidth = _canvas.width, + _viewportHeight = _canvas.height, + _currentWidth = 0, + _currentHeight = 0, - } + // frustum - }; + _frustum = new THREE.Frustum(), - // internal properties + // camera matrices cache - var _this = this, + _projScreenMatrix = new THREE.Matrix4(), - _programs = [], + _vector3 = new THREE.Vector3(), - // internal state cache + // light arrays cache - _currentProgram = null, - _currentFramebuffer = null, - _currentMaterialId = -1, - _currentGeometryProgram = '', - _currentCamera = null, + _direction = new THREE.Vector3(), - _usedTextureUnits = 0, + _lightsNeedUpdate = true, - _viewportX = 0, - _viewportY = 0, - _viewportWidth = _canvas.width, - _viewportHeight = _canvas.height, - _currentWidth = 0, - _currentHeight = 0, + _lights = { - // frustum + 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: [] } - _frustum = new THREE.Frustum(), + }, - // camera matrices cache + // info - _projScreenMatrix = new THREE.Matrix4(), + _infoMemory = { - _vector3 = new THREE.Vector3(), + geometries: 0, + textures: 0 - // light arrays cache + }, - _direction = new THREE.Vector3(), + _infoRender = { - _lightsNeedUpdate = true, + calls: 0, + vertices: 0, + faces: 0, + points: 0 - _lights = { + }; - 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: []} + this.info = { - }; + render: _infoRender, + memory: _infoMemory, + programs: null - // initialize + }; - var _gl; - try { + // initialize - var attributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer - }; + var _gl; - _gl = _context || _canvas.getContext('webgl', attributes) || _canvas.getContext('experimental-webgl', attributes); + try { - if (_gl === null) { + var attributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer + }; - if (_canvas.getContext('webgl') !== null) { + _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); - throw 'Error creating WebGL context with your selected attributes.'; + if ( _gl === null ) { - } else { + if ( _canvas.getContext( 'webgl' ) !== null ) { - throw 'Error creating WebGL context.'; + throw 'Error creating WebGL context with your selected attributes.'; - } + } else { - } + throw 'Error creating WebGL context.'; - _canvas.addEventListener('webglcontextlost', function (event) { + } - event.preventDefault(); + } - resetGLState(); - setDefaultGLState(); + _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - objects.objects = {}; + } catch ( error ) { - }, false); + console.error( 'THREE.WebGLRenderer: ' + error ); - } catch (error) { + } - THREE.error('THREE.WebGLRenderer: ' + error); + var extensions = new THREE.WebGLExtensions( _gl ); - } + extensions.get( 'OES_texture_float' ); + extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'WEBGL_depth_texture' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); + extensions.get( 'OES_standard_derivatives' ); + extensions.get( 'ANGLE_instanced_arrays' ); - var state = new THREE.WebGLState(_gl, paramThreeToGL); + if ( extensions.get( 'OES_element_index_uint' ) ) { - if (_gl.getShaderPrecisionFormat === undefined) { + THREE.BufferGeometry.MaxIndex = 4294967296; - _gl.getShaderPrecisionFormat = function () { + } - return { - 'rangeMin': 1, - 'rangeMax': 1, - 'precision': 1 - }; + var capabilities = new THREE.WebGLCapabilities( _gl, extensions, parameters ); - } + var state = new THREE.WebGLState( _gl, extensions, paramThreeToGL ); + var properties = new THREE.WebGLProperties(); + var objects = new THREE.WebGLObjects( _gl, properties, this.info ); + var programCache = new THREE.WebGLPrograms( this, capabilities ); - } + this.info.programs = programCache.programs; - var extensions = new THREE.WebGLExtensions(_gl); - var objects = new THREE.WebGLObjects(_gl, this.info); + var bufferRenderer = new THREE.WebGLBufferRenderer( _gl, extensions, _infoRender ); + var indexedBufferRenderer = new THREE.WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); - 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'); - extensions.get('WEBGL_depth_texture'); - extensions.get('ANGLE_instanced_arrays'); + // - if (extensions.get('OES_element_index_uint')) { + function glClearColor( r, g, b, a ) { - THREE.BufferGeometry.MaxIndex = 4294967296; + if ( _premultipliedAlpha === true ) { - } + r *= a; g *= a; b *= a; - if (_logarithmicDepthBuffer) { + } - extensions.get('EXT_frag_depth'); + _gl.clearColor( r, g, b, a ); - } + } - // + function setDefaultGLState() { - var glClearColor = function (r, g, b, a) { + state.init(); - if (_premultipliedAlpha === true) { + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - r *= a; - g *= a; - b *= a; + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - } + } - _gl.clearColor(r, g, b, a); + function resetGLState() { - }; + _currentProgram = null; + _currentCamera = null; - var setDefaultGLState = function () { + _currentGeometryProgram = ''; + _currentMaterialId = - 1; - _gl.clearColor(0, 0, 0, 1); - _gl.clearDepth(1); - _gl.clearStencil(0); + _lightsNeedUpdate = true; - _gl.enable(_gl.DEPTH_TEST); - _gl.depthFunc(_gl.LEQUAL); + state.reset(); - _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); + setDefaultGLState(); - _gl.viewport(_viewportX, _viewportY, _viewportWidth, _viewportHeight); + this.context = _gl; + this.capabilities = capabilities; + this.extensions = extensions; + this.state = state; - glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha); + // shadow map - }; + var shadowMap = new THREE.WebGLShadowMap( this, lights, objects ); - var resetGLState = function () { + this.shadowMap = shadowMap; - _currentProgram = null; - _currentCamera = null; - _currentGeometryProgram = ''; - _currentMaterialId = -1; + // Plugins - _lightsNeedUpdate = true; + var spritePlugin = new THREE.SpritePlugin( this, sprites ); + var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); - state.reset(); + // API - }; + this.getContext = function () { - setDefaultGLState(); + return _gl; - this.context = _gl; - this.extensions = extensions; - this.state = state; + }; - // shadow map + this.getContextAttributes = function () { - var shadowMap = new THREE.WebGLShadowMap(this, lights, objects); + return _gl.getContextAttributes(); - this.shadowMap = shadowMap; + }; - // GPU capabilities + this.forceContextLoss = function () { - var _maxTextures = _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS); - var _maxVertexTextures = _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS); - var _maxTextureSize = _gl.getParameter(_gl.MAX_TEXTURE_SIZE); - var _maxCubemapSize = _gl.getParameter(_gl.MAX_CUBE_MAP_TEXTURE_SIZE); + extensions.get( 'WEBGL_lose_context' ).loseContext(); - var _supportsVertexTextures = _maxVertexTextures > 0; - var _supportsBoneTextures = _supportsVertexTextures && extensions.get('OES_texture_float'); - var _supportsInstancedArrays = extensions.get('ANGLE_instanced_arrays'); + }; - // + this.getMaxAnisotropy = ( function () { - var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat(_gl.VERTEX_SHADER, _gl.HIGH_FLOAT); - var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat(_gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT); + var value; - var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat(_gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT); - var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat(_gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT); + return function getMaxAnisotropy() { - var getCompressedTextureFormats = (function () { + if ( value !== undefined ) return value; - var array; + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - return function () { + if ( extension !== null ) { - if (array !== undefined) { + value = _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - return array; + } else { - } + value = 0; - array = []; + } - if (extensions.get('WEBGL_compressed_texture_pvrtc') || extensions.get('WEBGL_compressed_texture_s3tc')) { + return value; - var formats = _gl.getParameter(_gl.COMPRESSED_TEXTURE_FORMATS); + } - for (var i = 0; i < formats.length; i++) { + } )(); - array.push(formats[i]); + this.getPrecision = function () { - } + return capabilities.precision; - } + }; - return array; + this.getPixelRatio = function () { - }; + return pixelRatio; - })(); + }; - // clamp precision to maximum available + this.setPixelRatio = function ( value ) { - var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; - var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; + if ( value !== undefined ) pixelRatio = value; - if (_precision === 'highp' && !highpAvailable) { + }; - if (mediumpAvailable) { + this.getSize = function () { - _precision = 'mediump'; - THREE.warn('THREE.WebGLRenderer: highp not supported, using mediump.'); + return { + width: _width, + height: _height + }; - } else { + }; - _precision = 'lowp'; - THREE.warn('THREE.WebGLRenderer: highp and mediump not supported, using lowp.'); + this.setSize = function ( width, height, updateStyle ) { - } + _width = width; + _height = height; - } + _canvas.width = width * pixelRatio; + _canvas.height = height * pixelRatio; - if (_precision === 'mediump' && !mediumpAvailable) { + if ( updateStyle !== false ) { - _precision = 'lowp'; - THREE.warn('THREE.WebGLRenderer: mediump not supported, using lowp.'); + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; - } + } - // Plugins + this.setViewport( 0, 0, width, height ); - var spritePlugin = new THREE.SpritePlugin(this, sprites); - var lensFlarePlugin = new THREE.LensFlarePlugin(this, lensFlares); + }; - // API + this.setViewport = function ( x, y, width, height ) { - this.getContext = function () { + _viewportX = x * pixelRatio; + _viewportY = y * pixelRatio; - return _gl; + _viewportWidth = width * pixelRatio; + _viewportHeight = height * pixelRatio; - }; + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - this.forceContextLoss = function () { + }; - extensions.get('WEBGL_lose_context').loseContext(); + this.getViewport = function ( dimensions ) { - }; + dimensions.x = _viewportX; + dimensions.y = _viewportY; - this.supportsVertexTextures = function () { + dimensions.z = _viewportWidth; + dimensions.w = _viewportHeight; - return _supportsVertexTextures; + }; - }; + this.setScissor = function ( x, y, width, height ) { - this.supportsInstancedArrays = function () { + _gl.scissor( + x * pixelRatio, + y * pixelRatio, + width * pixelRatio, + height * pixelRatio + ); - return _supportsInstancedArrays; + }; - }; + this.enableScissorTest = function ( boolean ) { - this.supportsFloatTextures = function () { + state.setScissorTest( boolean ); - return extensions.get('OES_texture_float'); + }; - }; + // Clearing - this.supportsHalfFloatTextures = function () { + this.getClearColor = function () { - return extensions.get('OES_texture_half_float'); + return _clearColor; - }; + }; - this.supportsDepthTextures = function () { + this.setClearColor = function ( color, alpha ) { - return extensions.get('WEBGL_depth_texture'); + _clearColor.set( color ); - }; + _clearAlpha = alpha !== undefined ? alpha : 1; - this.supportsStandardDerivatives = function () { + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - return extensions.get('OES_standard_derivatives'); + }; - }; + this.getClearAlpha = function () { - this.supportsCompressedTextureS3TC = function () { + return _clearAlpha; - return extensions.get('WEBGL_compressed_texture_s3tc'); + }; - }; + this.setClearAlpha = function ( alpha ) { - this.supportsCompressedTexturePVRTC = function () { + _clearAlpha = alpha; - return extensions.get('WEBGL_compressed_texture_pvrtc'); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - }; + }; - this.supportsBlendMinMax = function () { + this.clear = function ( color, depth, stencil ) { - return extensions.get('EXT_blend_minmax'); + var bits = 0; - }; + if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; + if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; - this.getMaxAnisotropy = (function () { + _gl.clear( bits ); - var value; + }; - return function () { + this.clearColor = function () { - if (value !== undefined) { + _gl.clear( _gl.COLOR_BUFFER_BIT ); - return value; + }; - } + this.clearDepth = function () { - var extension = extensions.get('EXT_texture_filter_anisotropic'); + _gl.clear( _gl.DEPTH_BUFFER_BIT ); - value = extension !== null ? _gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0; + }; - return value; + this.clearStencil = function () { - } + _gl.clear( _gl.STENCIL_BUFFER_BIT ); - })(); + }; - this.getPrecision = function () { + this.clearTarget = function ( renderTarget, color, depth, stencil ) { - return _precision; + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); - }; + }; - this.getPixelRatio = function () { + // Reset - return pixelRatio; + this.resetGLState = resetGLState; - }; + this.dispose = function() { - this.setPixelRatio = function (value) { + _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - pixelRatio = value; + }; - }; + // Events - this.getSize = function () { + function onContextLost( event ) { - return { - width: _width, - height: _height - }; + event.preventDefault(); - }; + resetGLState(); + setDefaultGLState(); - this.setSize = function (width, height, updateStyle) { + properties.clear(); - _width = width; - _height = height; + }; - _canvas.width = width * pixelRatio; - _canvas.height = height * pixelRatio; + function onTextureDispose( event ) { - if (updateStyle !== false) { + var texture = event.target; - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + texture.removeEventListener( 'dispose', onTextureDispose ); - } + deallocateTexture( texture ); - this.setViewport(0, 0, width, height); + _infoMemory.textures --; - }; - this.setViewport = function (x, y, width, height) { + } - _viewportX = x * pixelRatio; - _viewportY = y * pixelRatio; + function onRenderTargetDispose( event ) { - _viewportWidth = width * pixelRatio; - _viewportHeight = height * pixelRatio; + var renderTarget = event.target; - _gl.viewport(_viewportX, _viewportY, _viewportWidth, _viewportHeight); + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - }; + deallocateRenderTarget( renderTarget ); - this.setScissor = function (x, y, width, height) { + _infoMemory.textures --; - _gl.scissor( - x * pixelRatio, - y * pixelRatio, - width * pixelRatio, - height * pixelRatio - ); + } - }; + function onMaterialDispose( event ) { - this.enableScissorTest = function (enable) { + var material = event.target; - enable ? _gl.enable(_gl.SCISSOR_TEST) : _gl.disable(_gl.SCISSOR_TEST); + material.removeEventListener( 'dispose', onMaterialDispose ); - }; + deallocateMaterial( material ); - // Clearing + } - this.getClearColor = function () { + // Buffer deallocation - return _clearColor; + function deallocateTexture( texture ) { - }; + var textureProperties = properties.get( texture ); - this.setClearColor = function (color, alpha) { + if ( texture.image && textureProperties.__image__webglTextureCube ) { - _clearColor.set(color); + // cube texture - _clearAlpha = alpha !== undefined ? alpha : 1; + _gl.deleteTexture( textureProperties.__image__webglTextureCube ); - glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha); + } else { - }; + // 2D texture - this.getClearAlpha = function () { + if ( textureProperties.__webglInit === undefined ) return; - return _clearAlpha; + _gl.deleteTexture( textureProperties.__webglTexture ); - }; + } - this.setClearAlpha = function (alpha) { + // remove all webgl properties + properties.delete( texture ); - _clearAlpha = alpha; + } - glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha); + function deallocateRenderTarget( renderTarget ) { - }; + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); - this.clear = function (color, depth, stencil) { + if ( ! renderTarget || textureProperties.__webglTexture === undefined ) return; - var bits = 0; + _gl.deleteTexture( textureProperties.__webglTexture ); - if (color === undefined || color) bits |= _gl.COLOR_BUFFER_BIT; - if (depth === undefined || depth) bits |= _gl.DEPTH_BUFFER_BIT; - if (stencil === undefined || stencil) bits |= _gl.STENCIL_BUFFER_BIT; + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - _gl.clear(bits); + for ( var i = 0; i < 6; i ++ ) { - }; + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( renderTargetProperties.__webglRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglRenderbuffer[ i ] ); - this.clearColor = function () { + } - _gl.clear(_gl.COLOR_BUFFER_BIT); + } else { - }; + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( renderTargetProperties.__webglRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglRenderbuffer ); - this.clearDepth = function () { + } - _gl.clear(_gl.DEPTH_BUFFER_BIT); + properties.delete( renderTarget.texture ); + properties.delete( renderTarget ); - }; + } - this.clearStencil = function () { + function deallocateMaterial( material ) { - _gl.clear(_gl.STENCIL_BUFFER_BIT); + releaseMaterialProgramReference( material ); - }; + properties.delete( material ); - this.clearTarget = function (renderTarget, color, depth, stencil) { + } - this.setRenderTarget(renderTarget); - this.clear(color, depth, stencil); - }; + function releaseMaterialProgramReference( material ) { - // Reset + var programInfo = properties.get( material ).program; - this.resetGLState = resetGLState; + material.program = undefined; - // Events + if ( programInfo !== undefined ) { - var onTextureDispose = function (event) { + programCache.releaseProgram( programInfo ); + } - var texture = event.target; + } - texture.removeEventListener('dispose', onTextureDispose); + // Buffer rendering - deallocateTexture(texture); + this.renderBufferImmediate = function ( object, program, material ) { - _this.info.memory.textures--; + state.initAttributes(); + var buffers = properties.get( object ); - }; + if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); + if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); + if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); + if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); - var onRenderTargetDispose = function (event) { + var attributes = program.getAttributes(); - var renderTarget = event.target; + if ( object.hasPositions ) { - renderTarget.removeEventListener('dispose', onRenderTargetDispose); + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - deallocateRenderTarget(renderTarget); + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - _this.info.memory.textures--; + } - }; + if ( object.hasNormals ) { - var onMaterialDispose = function (event) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); - var material = event.target; + if ( material.type !== 'MeshPhongMaterial' && material.shading === THREE.FlatShading ) { - material.removeEventListener('dispose', onMaterialDispose); + for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { - deallocateMaterial(material); + var array = object.normalArray; - }; + var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; + var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; + var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; - // Buffer deallocation + array[ i + 0 ] = nx; + array[ i + 1 ] = ny; + array[ i + 2 ] = nz; - var deallocateTexture = function (texture) { + array[ i + 3 ] = nx; + array[ i + 4 ] = ny; + array[ i + 5 ] = nz; - if (texture.image && texture.image.__webglTextureCube) { + array[ i + 6 ] = nx; + array[ i + 7 ] = ny; + array[ i + 8 ] = nz; - // cube texture + } - _gl.deleteTexture(texture.image.__webglTextureCube); + } - delete texture.image.__webglTextureCube; + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - } else { + state.enableAttribute( attributes.normal ); - // 2D texture + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - if (texture.__webglInit === undefined) return; + } - _gl.deleteTexture(texture.__webglTexture); + if ( object.hasUvs && material.map ) { - delete texture.__webglTexture; - delete texture.__webglInit; + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - } + state.enableAttribute( attributes.uv ); - }; + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - var deallocateRenderTarget = function (renderTarget) { + } - if (!renderTarget || renderTarget.texture.__webglTexture === undefined) return; + if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { - _gl.deleteTexture(renderTarget.texture.__webglTexture); + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - delete renderTarget.__webglTexture; + state.enableAttribute( attributes.color ); - if (renderTarget instanceof THREE.WebGLRenderTargetCube) { + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - for (var i = 0; i < 6; i++) { + } - _gl.deleteFramebuffer(renderTarget.texture.__webglFramebuffer[i]); - if (renderTarget.__webglRenderbuffer) _gl.deleteRenderbuffer(renderTarget.__webglRenderbuffer[i]); + state.disableUnusedAttributes(); - } + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); - } else { + object.count = 0; - _gl.deleteFramebuffer(renderTarget.texture.__webglFramebuffer); - if (renderTarget.__webglRenderbuffer) _gl.deleteRenderbuffer(renderTarget.__webglRenderbuffer); + }; - } + this.renderBufferDirect = function ( camera, lights, fog, geometry, material, object, group ) { - delete renderTarget.__webglFramebuffer; - delete renderTarget.__webglRenderbuffer; + setMaterial( material ); - }; + var program = setProgram( camera, lights, fog, material, object ); - var deallocateMaterial = function (material) { + var updateBuffers = false; + var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe; - var program = material.program.program; + if ( geometryProgram !== _currentGeometryProgram ) { - if (program === undefined) return; + _currentGeometryProgram = geometryProgram; + updateBuffers = true; - material.program = undefined; + } - // only deallocate GL program if this was the last use of shared program - // assumed there is only single copy of any program in the _programs list - // (that's how it's constructed) + // morph targets - var i, il, programInfo; - var deleteProgram = false; + var morphTargetInfluences = object.morphTargetInfluences; - for (i = 0, il = _programs.length; i < il; i++) { + if ( morphTargetInfluences !== undefined ) { - programInfo = _programs[i]; + var activeInfluences = []; - if (programInfo.program === program) { + for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { - programInfo.usedTimes--; + var influence = morphTargetInfluences[ i ]; + activeInfluences.push( [ influence, i ] ); - if (programInfo.usedTimes === 0) { + } - deleteProgram = true; + activeInfluences.sort( numericalSort ); - } + if ( activeInfluences.length > 8 ) { - break; + activeInfluences.length = 8; - } + } - } + var morphAttributes = geometry.morphAttributes; - if (deleteProgram === true) { + for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) { - // avoid using array.splice, this is costlier than creating new array from scratch + var influence = activeInfluences[ i ]; + morphInfluences[ i ] = influence[ 0 ]; - var newPrograms = []; + if ( influence[ 0 ] !== 0 ) { - for (i = 0, il = _programs.length; i < il; i++) { + var index = influence[ 1 ]; - programInfo = _programs[i]; + if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] ); + if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] ); - if (programInfo.program !== program) { + } else { - newPrograms.push(programInfo); + if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i ); + if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i ); - } + } - } + } - _programs = newPrograms; + var uniforms = program.getUniforms(); - _gl.deleteProgram(program); + if ( uniforms.morphTargetInfluences !== null ) { - _this.info.memory.programs--; + _gl.uniform1fv( uniforms.morphTargetInfluences, morphInfluences ); - } + } - }; + updateBuffers = true; - // Buffer rendering + } - this.renderBufferImmediate = function (object, program, material) { + // - state.initAttributes(); + var index = geometry.index; + var position = geometry.attributes.position; - if (object.hasPositions && !object.__webglVertexBuffer) object.__webglVertexBuffer = _gl.createBuffer(); - if (object.hasNormals && !object.__webglNormalBuffer) object.__webglNormalBuffer = _gl.createBuffer(); - if (object.hasUvs && !object.__webglUvBuffer) object.__webglUvBuffer = _gl.createBuffer(); - if (object.hasColors && !object.__webglColorBuffer) object.__webglColorBuffer = _gl.createBuffer(); + if ( material.wireframe === true ) { - if (object.hasPositions) { + index = objects.getWireframeAttribute( geometry ); - _gl.bindBuffer(_gl.ARRAY_BUFFER, object.__webglVertexBuffer); - _gl.bufferData(_gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW); + } - state.enableAttribute(program.attributes.position); + var renderer; - _gl.vertexAttribPointer(program.attributes.position, 3, _gl.FLOAT, false, 0, 0); + if ( index !== null ) { - } + renderer = indexedBufferRenderer; + renderer.setIndex( index ); - if (object.hasNormals) { + } else { - _gl.bindBuffer(_gl.ARRAY_BUFFER, object.__webglNormalBuffer); + renderer = bufferRenderer; - 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; + if ( updateBuffers ) { - for (i = 0; i < il; i += 9) { + setupVertexAttributes( material, program, geometry ); - normalArray = object.normalArray; + if ( index !== null ) { - nax = normalArray[i]; - nay = normalArray[i + 1]; - naz = normalArray[i + 2]; + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) ); - nbx = normalArray[i + 3]; - nby = normalArray[i + 4]; - nbz = normalArray[i + 5]; + } - ncx = normalArray[i + 6]; - ncy = normalArray[i + 7]; - ncz = normalArray[i + 8]; + } - nx = ( nax + nbx + ncx ) / 3; - ny = ( nay + nby + ncy ) / 3; - nz = ( naz + nbz + ncz ) / 3; + if ( group === null ) { - normalArray[i] = nx; - normalArray[i + 1] = ny; - normalArray[i + 2] = nz; + var count; - normalArray[i + 3] = nx; - normalArray[i + 4] = ny; - normalArray[i + 5] = nz; + if ( index !== null ) { - normalArray[i + 6] = nx; - normalArray[i + 7] = ny; - normalArray[i + 8] = nz; + count = index.array.length; - } + } else { - } + count = position.count; - _gl.bufferData(_gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW); + } - state.enableAttribute(program.attributes.normal); + var drawRange = geometry.drawRange; - _gl.vertexAttribPointer(program.attributes.normal, 3, _gl.FLOAT, false, 0, 0); + group = { + start: drawRange.start, + count: Math.min( drawRange.count, count ) + }; - } + } - if (object.hasUvs && material.map) { + if ( object instanceof THREE.Mesh ) { - _gl.bindBuffer(_gl.ARRAY_BUFFER, object.__webglUvBuffer); - _gl.bufferData(_gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW); + if ( material.wireframe === true ) { - state.enableAttribute(program.attributes.uv); + state.setLineWidth( material.wireframeLinewidth * pixelRatio ); + renderer.setMode( _gl.LINES ); - _gl.vertexAttribPointer(program.attributes.uv, 2, _gl.FLOAT, false, 0, 0); + } else { - } + renderer.setMode( _gl.TRIANGLES ); - if (object.hasColors && material.vertexColors !== THREE.NoColors) { + } - _gl.bindBuffer(_gl.ARRAY_BUFFER, object.__webglColorBuffer); - _gl.bufferData(_gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW); + if ( geometry instanceof THREE.InstancedBufferGeometry && geometry.maxInstancedCount > 0 ) { - state.enableAttribute(program.attributes.color); + renderer.renderInstances( geometry ); - _gl.vertexAttribPointer(program.attributes.color, 3, _gl.FLOAT, false, 0, 0); + } else { - } + renderer.render( group.start, group.count ); - state.disableUnusedAttributes(); + } - _gl.drawArrays(_gl.TRIANGLES, 0, object.count); + } else if ( object instanceof THREE.Line ) { - object.count = 0; + var lineWidth = material.linewidth; - }; + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - function setupVertexAttributes(material, program, geometry, startIndex) { + state.setLineWidth( lineWidth * pixelRatio ); - var extension; + if ( object instanceof THREE.LineSegments ) { - if (geometry instanceof THREE.InstancedBufferGeometry) { + renderer.setMode( _gl.LINES ); - extension = extensions.get('ANGLE_instanced_arrays'); + } else { - if (extension === null) { + renderer.setMode( _gl.LINE_STRIP ); - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); - return; + } - } + renderer.render( group.start, group.count ); - } + } else if ( object instanceof THREE.Points ) { - var geometryAttributes = geometry.attributes; + renderer.setMode( _gl.POINTS ); + renderer.render( group.start, group.count ); - var programAttributes = program.attributes; - var programAttributesKeys = program.attributesKeys; + } - for (var i = 0, l = programAttributesKeys.length; i < l; i++) { + }; - var key = programAttributesKeys[i]; - var programAttribute = programAttributes[key]; + function setupVertexAttributes( material, program, geometry, startIndex ) { - if (programAttribute >= 0) { + var extension; - var geometryAttribute = geometryAttributes[key]; + if ( geometry instanceof THREE.InstancedBufferGeometry ) { - if (geometryAttribute !== undefined) { + extension = extensions.get( 'ANGLE_instanced_arrays' ); - var size = geometryAttribute.itemSize; - state.enableAttribute(programAttribute); + if ( extension === null ) { - if (geometryAttribute instanceof THREE.InterleavedBufferAttribute) { + console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - var data = geometryAttribute.data; - var stride = data.stride; - var offset = geometryAttribute.offset; + } - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryAttribute.data.buffer); - _gl.vertexAttribPointer(programAttribute, size, _gl.FLOAT, false, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT); + } - if (data instanceof THREE.InstancedInterleavedBuffer) { + if ( startIndex === undefined ) startIndex = 0; - if (extension === null) { + state.initAttributes(); - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.'); - return; + var geometryAttributes = geometry.attributes; - } + var programAttributes = program.getAttributes(); - extension.vertexAttribDivisorANGLE(programAttribute, data.meshPerAttribute); + var materialDefaultAttributeValues = material.defaultAttributeValues; - if (geometry.maxInstancedCount === undefined) { + for ( var name in programAttributes ) { - geometry.maxInstancedCount = data.meshPerAttribute * ( data.array.length / data.stride ); + var programAttribute = programAttributes[ name ]; - } + if ( programAttribute >= 0 ) { - } + var geometryAttribute = geometryAttributes[ name ]; - } else { + if ( geometryAttribute !== undefined ) { - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryAttribute.buffer); - _gl.vertexAttribPointer(programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4); // 4 bytes per Float32 + var size = geometryAttribute.itemSize; + var buffer = objects.getAttributeBuffer( geometryAttribute ); - if (geometryAttribute instanceof THREE.InstancedBufferAttribute) { + if ( geometryAttribute instanceof THREE.InterleavedBufferAttribute ) { - if (extension === null) { + var data = geometryAttribute.data; + var stride = data.stride; + var offset = geometryAttribute.offset; - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.'); - return; + if ( data instanceof THREE.InstancedInterleavedBuffer ) { - } + state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension ); - extension.vertexAttribDivisorANGLE(programAttribute, geometryAttribute.meshPerAttribute); + if ( geometry.maxInstancedCount === undefined ) { - if (geometry.maxInstancedCount === undefined) { + geometry.maxInstancedCount = data.meshPerAttribute * data.count; - geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * ( geometryAttribute.array.length / geometryAttribute.itemSize ); + } - } + } else { - } + state.enableAttribute( programAttribute ); - } + } - } else if (material.defaultAttributeValues !== undefined) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); + _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT ); - if (material.defaultAttributeValues[key].length === 2) { + } else { - _gl.vertexAttrib2fv(programAttribute, material.defaultAttributeValues[key]); + if ( geometryAttribute instanceof THREE.InstancedBufferAttribute ) { - } else if (material.defaultAttributeValues[key].length === 3) { + state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension ); - _gl.vertexAttrib3fv(programAttribute, material.defaultAttributeValues[key]); + if ( geometry.maxInstancedCount === undefined ) { - } + geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - } + } - } + } else { - } + state.enableAttribute( programAttribute ); - state.disableUnusedAttributes(); + } - } + _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); + _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 - this.renderBufferDirect = function (camera, lights, fog, material, geometry, object) { + } - if (material.visible === false) return; + } else if ( materialDefaultAttributeValues !== undefined ) { - objects.update(object); + var value = materialDefaultAttributeValues[ name ]; - var program = setProgram(camera, lights, fog, material, object); + if ( value !== undefined ) { - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryProgram = 'direct_' + geometry.id + '_' + program.id + '_' + wireframeBit; + switch ( value.length ) { - if (geometryProgram !== _currentGeometryProgram) { + case 2: + _gl.vertexAttrib2fv( programAttribute, value ); + break; - _currentGeometryProgram = geometryProgram; - updateBuffers = true; + case 3: + _gl.vertexAttrib3fv( programAttribute, value ); + break; - } + case 4: + _gl.vertexAttrib4fv( programAttribute, value ); + break; - if (updateBuffers) { + default: + _gl.vertexAttrib1fv( programAttribute, value ); - state.initAttributes(); + } - } + } - // render mesh + } - if (object instanceof THREE.Mesh) { + } - var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES; + } - var index = geometry.attributes.index; + state.disableUnusedAttributes(); - if (index) { + } - // indexed triangles + // Sorting - var type, size; + function numericalSort ( a, b ) { - if (index.array instanceof Uint32Array && extensions.get('OES_element_index_uint')) { + return b[ 0 ] - a[ 0 ]; - type = _gl.UNSIGNED_INT; - size = 4; + } - } else { + function painterSortStable ( a, b ) { - type = _gl.UNSIGNED_SHORT; - size = 2; + if ( a.object.renderOrder !== b.object.renderOrder ) { - } + return a.object.renderOrder - b.object.renderOrder; - var offsets = geometry.offsets; + } else if ( a.material.id !== b.material.id ) { - if (offsets.length === 0) { + return a.material.id - b.material.id; - if (updateBuffers) { + } else if ( a.z !== b.z ) { - setupVertexAttributes(material, program, geometry, 0); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + return a.z - b.z; - } + } else { - if (geometry instanceof THREE.InstancedBufferGeometry && geometry.maxInstancedCount > 0) { + return a.id - b.id; - var extension = extensions.get('ANGLE_instanced_arrays'); + } - if (extension === null) { + } - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); - return; + function reversePainterSortStable ( a, b ) { - } + if ( a.object.renderOrder !== b.object.renderOrder ) { - extension.drawElementsInstancedANGLE(mode, index.array.length, type, 0, geometry.maxInstancedCount); // Draw the instanced meshes + return a.object.renderOrder - b.object.renderOrder; - } else { + } if ( a.z !== b.z ) { - _gl.drawElements(mode, index.array.length, type, 0); + return b.z - a.z; - } - _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; + } else { - } else { + return a.id - b.id; - // 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; + } - for (var i = 0, il = offsets.length; i < il; i++) { + // Rendering - var startIndex = offsets[i].index; + this.render = function ( scene, camera, renderTarget, forceClear ) { - if (updateBuffers) { + if ( camera instanceof THREE.Camera === false ) { - setupVertexAttributes(material, program, geometry, startIndex); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - } + } - // render indexed triangles + var fog = scene.fog; - if (geometry instanceof THREE.InstancedBufferGeometry && offsets[i].instances > 0) { + // reset caching for this frame - var extension = extensions.get('ANGLE_instanced_arrays'); + _currentGeometryProgram = ''; + _currentMaterialId = - 1; + _currentCamera = null; + _lightsNeedUpdate = true; - if (extension === null) { + // update scene graph - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); - return; + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - } + // update camera matrices and frustum - extension.drawElementsInstancedANGLE(mode, offsets[i].count, type, offsets[i].start * size, offsets[i].count, type, offsets[i].instances); // Draw the instanced meshes + if ( camera.parent === null ) camera.updateMatrixWorld(); - } else { + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - _gl.drawElements(mode, offsets[i].count, type, offsets[i].start * size); + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - } + lights.length = 0; - _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; + opaqueObjectsLastIndex = -1; + transparentObjectsLastIndex = -1; - } + sprites.length = 0; + lensFlares.length = 0; - } + projectObject( scene ); - } else { + opaqueObjects.length = opaqueObjectsLastIndex + 1; + transparentObjects.length = transparentObjectsLastIndex + 1; - // non-indexed triangles + if ( _this.sortObjects === true ) { - if (updateBuffers) { + opaqueObjects.sort( painterSortStable ); + transparentObjects.sort( reversePainterSortStable ); - setupVertexAttributes(material, program, geometry, 0); + } - } + // - var position = geometry.attributes['position']; + shadowMap.render( scene ); - // render non-indexed triangles + // - if (geometry instanceof THREE.InstancedBufferGeometry && geometry.maxInstancedCount > 0) { + _infoRender.calls = 0; + _infoRender.vertices = 0; + _infoRender.faces = 0; + _infoRender.points = 0; - var extension = extensions.get('ANGLE_instanced_arrays'); + this.setRenderTarget( renderTarget ); - if (extension === null) { + if ( this.autoClear || forceClear ) { - THREE.error('THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); - return; + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); - } + } - if (position instanceof THREE.InterleavedBufferAttribute) { + // - extension.drawArraysInstancedANGLE(mode, 0, position.data.array.length / position.data.stride, geometry.maxInstancedCount); // Draw the instanced meshes + if ( scene.overrideMaterial ) { - } else { + var overrideMaterial = scene.overrideMaterial; - extension.drawArraysInstancedANGLE(mode, 0, position.array.length / position.itemSize, geometry.maxInstancedCount); // Draw the instanced meshes + renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); + renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); - } + } else { - } else { + // opaque pass (front-to-back order) - if (position instanceof THREE.InterleavedBufferAttribute) { + state.setBlending( THREE.NoBlending ); + renderObjects( opaqueObjects, camera, lights, fog ); - _gl.drawArrays(mode, 0, position.data.array.length / position.data.stride); + // transparent pass (back-to-front order) - } else { + renderObjects( transparentObjects, camera, lights, fog ); - _gl.drawArrays(mode, 0, position.array.length / position.itemSize); + } - } + // custom render plugins (post pass) - } + spritePlugin.render( scene, camera ); + lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); - _this.info.render.calls++; - _this.info.render.vertices += position.array.length / position.itemSize; - _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); + // Generate mipmap if we're using any kind of mipmap filtering - } + if ( renderTarget && renderTarget.generateMipmaps && renderTarget.texture.minFilter !== THREE.NearestFilter && renderTarget.texture.minFilter !== THREE.LinearFilter ) { - } else if (object instanceof THREE.PointCloud) { + updateRenderTargetMipmap( renderTarget ); - // render particles + } - var mode = _gl.POINTS; + // Ensure depth buffer writing is enabled so it can be cleared on next render - var index = geometry.attributes.index; + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); - if (index) { + // _gl.finish(); - // indexed points + }; - var type, size; + function pushRenderItem( object, geometry, material, z, group ) { - if (index.array instanceof Uint32Array && extensions.get('OES_element_index_uint')) { + var array, index; - type = _gl.UNSIGNED_INT; - size = 4; + // allocate the next position in the appropriate array - } else { + if ( material.transparent ) { - type = _gl.UNSIGNED_SHORT; - size = 2; + array = transparentObjects; + index = ++ transparentObjectsLastIndex; - } + } else { - var offsets = geometry.offsets; + array = opaqueObjects; + index = ++ opaqueObjectsLastIndex; - if (offsets.length === 0) { + } - if (updateBuffers) { + // recycle existing render item or grow the array - setupVertexAttributes(material, program, geometry, 0); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + var renderItem = array[ index ]; - } + if ( renderItem !== undefined ) { - _gl.drawElements(mode, index.array.length, type, 0); + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.z = _vector3.z; + renderItem.group = group; - _this.info.render.calls++; - _this.info.render.points += index.array.length; + } else { - } else { + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + z: _vector3.z, + group: group + }; - // 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 + // assert( index === array.length ); + array.push( renderItem ); - if (offsets.length > 1) updateBuffers = true; + } - for (var i = 0, il = offsets.length; i < il; i++) { + } - var startIndex = offsets[i].index; + function projectObject( object ) { - if (updateBuffers) { + if ( object.visible === false ) return; - setupVertexAttributes(material, program, geometry, startIndex); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + if ( object instanceof THREE.Light ) { - } + lights.push( object ); - // render indexed points + } else if ( object instanceof THREE.Sprite ) { - _gl.drawElements(mode, offsets[i].count, type, offsets[i].start * size); + sprites.push( object ); - _this.info.render.calls++; - _this.info.render.points += offsets[i].count; + } else if ( object instanceof THREE.LensFlare ) { - } + lensFlares.push( object ); - } + } else if ( object instanceof THREE.ImmediateRenderObject ) { - } else { + if ( _this.sortObjects === true ) { - // non-indexed points + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); - if (updateBuffers) { + } - setupVertexAttributes(material, program, geometry, 0); + pushRenderItem( object, null, object.material, _vector3.z, null ); - } + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { - var position = geometry.attributes.position; - var offsets = geometry.offsets; + if ( object instanceof THREE.SkinnedMesh ) { - if (offsets.length === 0) { + object.skeleton.update(); - _gl.drawArrays(mode, 0, position.array.length / 3); + } - _this.info.render.calls++; - _this.info.render.points += position.array.length / 3; + if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { - } else { + var material = object.material; - for (var i = 0, il = offsets.length; i < il; i++) { + if ( material.visible === true ) { - _gl.drawArrays(mode, offsets[i].index, offsets[i].count); + if ( _this.sortObjects === true ) { - _this.info.render.calls++; - _this.info.render.points += offsets[i].count; + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); - } + } - } + var geometry = objects.update( object ); - } + if ( material instanceof THREE.MeshFaceMaterial ) { - } else if (object instanceof THREE.Line) { + var groups = geometry.groups; + var materials = material.materials; - var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + for ( var i = 0, l = groups.length; i < l; i ++ ) { - // In case user is not using Line*Material by mistake - var lineWidth = material.linewidth !== undefined ? material.linewidth : 1; + var group = groups[ i ]; + var groupMaterial = materials[ group.materialIndex ]; - state.setLineWidth(lineWidth * pixelRatio); + if ( groupMaterial.visible === true ) { - var index = geometry.attributes.index; + pushRenderItem( object, geometry, groupMaterial, _vector3.z, group ); - if (index) { + } - // indexed lines + } - var type, size; + } else { - if (index.array instanceof Uint32Array) { + pushRenderItem( object, geometry, material, _vector3.z, null ); - type = _gl.UNSIGNED_INT; - size = 4; + } - } else { + } - type = _gl.UNSIGNED_SHORT; - size = 2; + } - } + } - var offsets = geometry.offsets; + var children = object.children; - if (offsets.length === 0) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - if (updateBuffers) { + projectObject( children[ i ] ); - setupVertexAttributes(material, program, geometry, 0); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + } - } + } - _gl.drawElements(mode, index.array.length, type, 0); // 2 bytes per Uint16Array + function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { - _this.info.render.calls++; - _this.info.render.vertices += index.array.length; // not really true, here vertices can be shared + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - } else { + var renderItem = renderList[ i ]; - // 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 + var object = renderItem.object; + var geometry = renderItem.geometry; + var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; + var group = renderItem.group; - if (offsets.length > 1) updateBuffers = true; + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - for (var i = 0, il = offsets.length; i < il; i++) { + if ( object instanceof THREE.ImmediateRenderObject ) { - var startIndex = offsets[i].index; + setMaterial( material ); - if (updateBuffers) { + var program = setProgram( camera, lights, fog, material, object ); - setupVertexAttributes(material, program, geometry, startIndex); - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, index.buffer); + _currentGeometryProgram = ''; - } + object.render( function ( object ) { - // render indexed lines + _this.renderBufferImmediate( object, program, material ); - _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 + } else { - } + _this.renderBufferDirect( camera, lights, fog, geometry, material, object, group ); - } + } - } else { + } - // non-indexed lines + } - if (updateBuffers) { + function initMaterial( material, lights, fog, object ) { - setupVertexAttributes(material, program, geometry, 0); + var materialProperties = properties.get( material ); - } + var parameters = programCache.getParameters( material, lights, fog, object ); + var code = programCache.getProgramCode( material, parameters ); - var position = geometry.attributes.position; - var offsets = geometry.offsets; + var program = materialProperties.program; + var programChange = true; - if (offsets.length === 0) { + if ( program === undefined ) { - _gl.drawArrays(mode, 0, position.array.length / 3); + // new material + material.addEventListener( 'dispose', onMaterialDispose ); - _this.info.render.calls++; - _this.info.render.vertices += position.array.length / 3; + } else if ( program.code !== code ) { - } else { + // changed glsl or parameters + releaseMaterialProgramReference( material ); - for (var i = 0, il = offsets.length; i < il; i++) { + } else if ( parameters.shaderID !== undefined ) { - _gl.drawArrays(mode, offsets[i].index, offsets[i].count); + // same glsl and uniform list + return; - _this.info.render.calls++; - _this.info.render.vertices += offsets[i].count; + } else { - } + // only rebuild uniform list + programChange = false; - } + } - } + if ( programChange ) { - } + if ( parameters.shaderID ) { - }; + var shader = THREE.ShaderLib[ parameters.shaderID ]; - function setupMorphTargets(material, geometryGroup, object) { + materialProperties.__webglShader = { + name: material.type, + uniforms: THREE.UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + }; - // set base + } else { - var attributes = material.program.attributes; + materialProperties.__webglShader = { + name: material.type, + uniforms: material.uniforms, + vertexShader: material.vertexShader, + fragmentShader: material.fragmentShader + }; - if (object.morphTargetBase !== -1 && attributes.position >= 0) { + } - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[object.morphTargetBase]); + material.__webglShader = materialProperties.__webglShader; - state.enableAttribute(attributes.position); + program = programCache.acquireProgram( material, parameters, code ); - _gl.vertexAttribPointer(attributes.position, 3, _gl.FLOAT, false, 0, 0); + materialProperties.program = program; + material.program = program; - } else if (attributes.position >= 0) { + } - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer); + var attributes = program.getAttributes(); - state.enableAttribute(attributes.position); + if ( material.morphTargets ) { - _gl.vertexAttribPointer(attributes.position, 3, _gl.FLOAT, false, 0, 0); + material.numSupportedMorphTargets = 0; - } + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - if (object.morphTargetForcedOrder.length) { + if ( attributes[ 'morphTarget' + i ] >= 0 ) { - // set forced order + material.numSupportedMorphTargets ++; - var m = 0; - var order = object.morphTargetForcedOrder; - var influences = object.morphTargetInfluences; + } - var attribute; + } - while (m < material.numSupportedMorphTargets && m < order.length) { + } - attribute = attributes['morphTarget' + m]; + if ( material.morphNormals ) { - if (attribute >= 0) { + material.numSupportedMorphNormals = 0; - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[order[m]]); + for ( i = 0; i < _this.maxMorphNormals; i ++ ) { - state.enableAttribute(attribute); + if ( attributes[ 'morphNormal' + i ] >= 0 ) { - _gl.vertexAttribPointer(attribute, 3, _gl.FLOAT, false, 0, 0); + material.numSupportedMorphNormals ++; - } + } - attribute = attributes['morphNormal' + m]; + } - if (attribute >= 0 && material.morphNormals) { + } - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[order[m]]); + materialProperties.uniformsList = []; - state.enableAttribute(attribute); + var uniformLocations = materialProperties.program.getUniforms(); - _gl.vertexAttribPointer(attribute, 3, _gl.FLOAT, false, 0, 0); + for ( var u in materialProperties.__webglShader.uniforms ) { - } + var location = uniformLocations[ u ]; - object.__webglMorphTargetInfluences[m] = influences[order[m]]; + if ( location ) { - m++; + materialProperties.uniformsList.push( [ materialProperties.__webglShader.uniforms[ u ], location ] ); - } + } - } else { + } - // find the most influencing + } - var activeInfluenceIndices = []; - var influences = object.morphTargetInfluences; - var morphTargets = object.geometry.morphTargets; + function setMaterial( material ) { - if (influences.length > morphTargets.length) { + setMaterialFaces( material ); - THREE.warn('THREE.WebGLRenderer: Influences array is bigger than morphTargets array.'); - influences.length = morphTargets.length; + if ( material.transparent === true ) { - } + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - for (var i = 0, il = influences.length; i < il; i++) { + } else { - var influence = influences[i]; + state.setBlending( THREE.NoBlending ); - activeInfluenceIndices.push([influence, i]); + } - } + state.setDepthFunc( material.depthFunc ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - if (activeInfluenceIndices.length > material.numSupportedMorphTargets) { + } - activeInfluenceIndices.sort(numericalSort); - activeInfluenceIndices.length = material.numSupportedMorphTargets; + function setMaterialFaces( material ) { - } else if (activeInfluenceIndices.length > material.numSupportedMorphNormals) { + material.side !== THREE.DoubleSide ? state.enable( _gl.CULL_FACE ) : state.disable( _gl.CULL_FACE ); + state.setFlipSided( material.side === THREE.BackSide ); - activeInfluenceIndices.sort(numericalSort); + } - } else if (activeInfluenceIndices.length === 0) { + function setProgram( camera, lights, fog, material, object ) { - activeInfluenceIndices.push([0, 0]); + _usedTextureUnits = 0; - } + var materialProperties = properties.get( material ); - var attribute; + if ( material.needsUpdate || ! materialProperties.program ) { - for (var m = 0, ml = material.numSupportedMorphTargets; m < ml; m++) { + initMaterial( material, lights, fog, object ); + material.needsUpdate = false; - if (activeInfluenceIndices[m]) { + } - var influenceIndex = activeInfluenceIndices[m][1]; + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; - attribute = attributes['morphTarget' + m]; + var program = materialProperties.program, + p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.__webglShader.uniforms; - if (attribute >= 0) { + if ( program.id !== _currentProgram ) { - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[influenceIndex]); + _gl.useProgram( program.program ); + _currentProgram = program.id; - state.enableAttribute(attribute); + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - _gl.vertexAttribPointer(attribute, 3, _gl.FLOAT, false, 0, 0); + } - } + if ( material.id !== _currentMaterialId ) { - attribute = attributes['morphNormal' + m]; + if ( _currentMaterialId === - 1 ) refreshLights = true; + _currentMaterialId = material.id; - if (attribute >= 0 && material.morphNormals) { + refreshMaterial = true; - _gl.bindBuffer(_gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[influenceIndex]); + } - state.enableAttribute(attribute); + if ( refreshProgram || camera !== _currentCamera ) { - _gl.vertexAttribPointer(attribute, 3, _gl.FLOAT, false, 0, 0); + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - } + if ( capabilities.logarithmicDepthBuffer ) { - object.__webglMorphTargetInfluences[m] = influences[influenceIndex]; + _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - } else { + } - /* - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - if ( material.morphNormals ) { + if ( camera !== _currentCamera ) _currentCamera = camera; - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - } - */ + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material.envMap ) { - object.__webglMorphTargetInfluences[m] = 0; + if ( p_uniforms.cameraPosition !== undefined ) { - } + _vector3.setFromMatrixPosition( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); - } + } - } + } - // load updated influences uniform + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { - if (material.program.uniforms.morphTargetInfluences !== null) { + if ( p_uniforms.viewMatrix !== undefined ) { - _gl.uniform1fv(material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences); + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); - } + } - } + } - // Sorting + } - function painterSortStable(a, b) { + // 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 (a.object.renderOrder !== b.object.renderOrder) { + if ( material.skinning ) { - return a.object.renderOrder - b.object.renderOrder; + if ( object.bindMatrix && p_uniforms.bindMatrix !== undefined ) { - } else if (a.material.id !== b.material.id) { + _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); - return a.material.id - b.material.id; + } - } else if (a.z !== b.z) { + if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== undefined ) { - return a.z - b.z; + _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); - } else { + } - return a.id - b.id; + if ( capabilities.floatVertexTextures && object.skeleton && object.skeleton.useVertexTexture ) { - } + if ( p_uniforms.boneTexture !== undefined ) { - } + var textureUnit = getTextureUnit(); - function reversePainterSortStable(a, b) { + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.skeleton.boneTexture, textureUnit ); - if (a.object.renderOrder !== b.object.renderOrder) { + } - return a.object.renderOrder - b.object.renderOrder; + if ( p_uniforms.boneTextureWidth !== undefined ) { - } - if (a.z !== b.z) { + _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); - return b.z - a.z; + } - } else { + if ( p_uniforms.boneTextureHeight !== undefined ) { - return a.id - b.id; + _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); - } + } - } + } else if ( object.skeleton && object.skeleton.boneMatrices ) { - function numericalSort(a, b) { + if ( p_uniforms.boneGlobalMatrices !== undefined ) { - return b[0] - a[0]; + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices ); - } + } - // Rendering + } - this.render = function (scene, camera, renderTarget, forceClear) { + } - if (camera instanceof THREE.Camera === false) { + if ( refreshMaterial ) { - THREE.error('THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.'); - return; + // refresh uniforms common to several materials - } + if ( fog && material.fog ) { - var fog = scene.fog; + refreshUniformsFog( m_uniforms, fog ); - // reset caching for this frame + } - _currentGeometryProgram = ''; - _currentMaterialId = -1; - _currentCamera = null; - _lightsNeedUpdate = true; + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material.lights ) { - // update scene graph + if ( _lightsNeedUpdate ) { - if (scene.autoUpdate === true) scene.updateMatrixWorld(); + refreshLights = true; + setupLights( lights, camera ); + _lightsNeedUpdate = false; - // update camera matrices and frustum + } - if (camera.parent === undefined) camera.updateMatrixWorld(); + if ( refreshLights ) { - // update Skeleton objects + refreshUniformsLights( m_uniforms, _lights ); + markUniformsLightsNeedsUpdate( m_uniforms, true ); - scene.traverse(function (object) { + } else { - if (object instanceof THREE.SkinnedMesh) { + markUniformsLightsNeedsUpdate( m_uniforms, false ); - object.skeleton.update(); + } - } + } - }); + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhongMaterial ) { - camera.matrixWorldInverse.getInverse(camera.matrixWorld); + refreshUniformsCommon( m_uniforms, material ); - _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); - _frustum.setFromMatrix(_projScreenMatrix); + } - lights.length = 0; - opaqueObjects.length = 0; - transparentObjects.length = 0; + // refresh single material specific uniforms - sprites.length = 0; - lensFlares.length = 0; + if ( material instanceof THREE.LineBasicMaterial ) { - projectObject(scene); + refreshUniformsLine( m_uniforms, material ); - if (_this.sortObjects === true) { + } else if ( material instanceof THREE.LineDashedMaterial ) { - opaqueObjects.sort(painterSortStable); - transparentObjects.sort(reversePainterSortStable); + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); - } + } else if ( material instanceof THREE.PointsMaterial ) { - // + refreshUniformsParticle( m_uniforms, material ); - shadowMap.render(scene, camera); + } else if ( material instanceof THREE.MeshPhongMaterial ) { - // + refreshUniformsPhong( m_uniforms, material ); - _this.info.render.calls = 0; - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - _this.info.render.points = 0; + } else if ( material instanceof THREE.MeshDepthMaterial ) { - this.setRenderTarget(renderTarget); + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; - if (this.autoClear || forceClear) { + } else if ( material instanceof THREE.MeshNormalMaterial ) { - this.clear(this.autoClearColor, this.autoClearDepth, this.autoClearStencil); + m_uniforms.opacity.value = material.opacity; - } + } - // set matrices for immediate objects + if ( object.receiveShadow && ! material._shadowPass ) { - for (var i = 0, il = objects.objectsImmediate.length; i < il; i++) { + refreshUniformsShadow( m_uniforms, lights, camera ); - var webglObject = objects.objectsImmediate[i]; - var object = webglObject.object; + } - if (object.visible) { + // load common uniforms - setupMatrices(object, camera); + loadUniformsGeneric( materialProperties.uniformsList ); - unrollImmediateBufferMaterial(webglObject); + } - } + loadUniformsMatrices( p_uniforms, object ); - } + if ( p_uniforms.modelMatrix !== undefined ) { - if (scene.overrideMaterial) { + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); - var overrideMaterial = scene.overrideMaterial; + } - setMaterial(overrideMaterial); + return program; - renderObjects(opaqueObjects, camera, lights, fog, overrideMaterial); - renderObjects(transparentObjects, camera, lights, fog, overrideMaterial); - renderObjectsImmediate(objects.objectsImmediate, '', camera, lights, fog, overrideMaterial); + } - } else { + // Uniforms (refresh uniforms objects) - // opaque pass (front-to-back order) + function refreshUniformsCommon ( uniforms, material ) { - state.setBlending(THREE.NoBlending); + uniforms.opacity.value = material.opacity; - renderObjects(opaqueObjects, camera, lights, fog, null); - renderObjectsImmediate(objects.objectsImmediate, 'opaque', camera, lights, fog, null); + uniforms.diffuse.value = material.color; - // transparent pass (back-to-front order) + if ( material.emissive ) { - renderObjects(transparentObjects, camera, lights, fog, null); - renderObjectsImmediate(objects.objectsImmediate, 'transparent', camera, lights, fog, null); + uniforms.emissive.value = material.emissive; - } + } - // custom render plugins (post pass) + uniforms.map.value = material.map; + uniforms.specularMap.value = material.specularMap; + uniforms.alphaMap.value = material.alphaMap; - spritePlugin.render(scene, camera); - lensFlarePlugin.render(scene, camera, _currentWidth, _currentHeight); + if ( material.aoMap ) { - // Generate mipmap if we're using any kind of mipmap filtering + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; - if (renderTarget && renderTarget.generateMipmaps && renderTarget.texture.minFilter !== THREE.NearestFilter && renderTarget.texture.minFilter !== THREE.LinearFilter) { + } - updateRenderTargetMipmap(renderTarget); + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map + // 6. emissive map - } + var uvScaleMap; - // Ensure depth buffer writing is enabled so it can be cleared on next render + if ( material.map ) { - state.setDepthTest(true); - state.setDepthWrite(true); - state.setColorWrite(true); + uvScaleMap = material.map; - // _gl.finish(); + } else if ( material.specularMap ) { - }; + uvScaleMap = material.specularMap; - function projectObject(object) { + } else if ( material.displacementMap ) { - if (object.visible === false) return; + uvScaleMap = material.displacementMap; - if (object instanceof THREE.Scene || object instanceof THREE.Group) { + } else if ( material.normalMap ) { - // skip + uvScaleMap = material.normalMap; - } else { + } else if ( material.bumpMap ) { - objects.init(object); + uvScaleMap = material.bumpMap; - if (object instanceof THREE.Light) { + } else if ( material.alphaMap ) { - lights.push(object); + uvScaleMap = material.alphaMap; - } else if (object instanceof THREE.Sprite) { + } else if ( material.emissiveMap ) { - sprites.push(object); + uvScaleMap = material.emissiveMap; - } else if (object instanceof THREE.LensFlare) { + } - lensFlares.push(object); + if ( uvScaleMap !== undefined ) { - } else { + if ( uvScaleMap instanceof THREE.WebGLRenderTarget ) uvScaleMap = uvScaleMap.texture; - var webglObject = objects.objects[object.id]; + var offset = uvScaleMap.offset; + var repeat = uvScaleMap.repeat; - if (webglObject && ( object.frustumCulled === false || _frustum.intersectsObject(object) === true )) { + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - unrollBufferMaterial(webglObject); + } - webglObject.render = true; + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - if (_this.sortObjects === true) { + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; - _vector3.setFromMatrixPosition(object.matrixWorld); - _vector3.applyProjection(_projScreenMatrix); + } - webglObject.z = _vector3.z; + function refreshUniformsLine ( uniforms, material ) { - } + 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; - for (var i = 0, l = object.children.length; i < l; i++) { + } - projectObject(object.children[i]); + 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. - } + uniforms.map.value = material.map; - function renderObjects(renderList, camera, lights, fog, overrideMaterial) { + if ( material.map !== null ) { - var material; + var offset = material.map.offset; + var repeat = material.map.repeat; - for (var i = 0, l = renderList.length; i < l; i++) { + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - var webglObject = renderList[i]; + } - var object = webglObject.object; - var buffer = objects.geometries.get(object); + } - setupMatrices(object, camera); + function refreshUniformsFog ( uniforms, fog ) { - if (overrideMaterial) { + uniforms.fogColor.value = fog.color; - material = overrideMaterial; + if ( fog instanceof THREE.Fog ) { - } else { + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - material = webglObject.material; + } else if ( fog instanceof THREE.FogExp2 ) { - if (!material) continue; + uniforms.fogDensity.value = fog.density; - setMaterial(material); + } - } + } - _this.setMaterialFaces(material); - _this.renderBufferDirect(camera, lights, fog, material, buffer, object); + function refreshUniformsPhong ( uniforms, material ) { - } + uniforms.specular.value = material.specular; + uniforms.shininess.value = material.shininess; - } + if ( material.lightMap ) { - function renderObjectsImmediate(renderList, materialType, camera, lights, fog, overrideMaterial) { + uniforms.lightMap.value = material.lightMap; + uniforms.lightMapIntensity.value = material.lightMapIntensity; - var material; + } - for (var i = 0, l = renderList.length; i < l; i++) { + if ( material.emissiveMap ) { - var webglObject = renderList[i]; - var object = webglObject.object; + uniforms.emissiveMap.value = material.emissiveMap; - if (object.visible) { + } - if (overrideMaterial) { + if ( material.bumpMap ) { - material = overrideMaterial; + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; - } else { + } - material = webglObject[materialType]; + if ( material.normalMap ) { - if (!material) continue; + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); - setMaterial(material); + } - } + if ( material.displacementMap ) { - _this.renderImmediateObject(camera, lights, fog, material, object); + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - } + } - } + } - } + function refreshUniformsLights ( uniforms, lights ) { - this.renderImmediateObject = function (camera, lights, fog, material, object) { + uniforms.ambientLightColor.value = lights.ambient; - var program = setProgram(camera, lights, fog, material, object); + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; - _currentGeometryProgram = ''; + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecay.value = lights.point.decays; - _this.setMaterialFaces(material); + 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; - if (object.immediateRenderCallback) { + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; - object.immediateRenderCallback(program, _gl, _frustum); + } - } else { + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - object.render(function (object) { - _this.renderBufferImmediate(object, program, material); - }); + function markUniformsLightsNeedsUpdate ( uniforms, value ) { - } + uniforms.ambientLightColor.needsUpdate = value; - }; + uniforms.directionalLightColor.needsUpdate = value; + uniforms.directionalLightDirection.needsUpdate = value; - function unrollImmediateBufferMaterial(globject) { + uniforms.pointLightColor.needsUpdate = value; + uniforms.pointLightPosition.needsUpdate = value; + uniforms.pointLightDistance.needsUpdate = value; + uniforms.pointLightDecay.needsUpdate = value; - var object = globject.object, - material = object.material; + 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; - if (material.transparent) { + uniforms.hemisphereLightSkyColor.needsUpdate = value; + uniforms.hemisphereLightGroundColor.needsUpdate = value; + uniforms.hemisphereLightDirection.needsUpdate = value; - globject.transparent = material; - globject.opaque = null; + } - } else { + function refreshUniformsShadow ( uniforms, lights, camera ) { - globject.opaque = material; - globject.transparent = null; + if ( uniforms.shadowMatrix ) { - } + var j = 0; - } + for ( var i = 0, il = lights.length; i < il; i ++ ) { - function unrollBufferMaterial(globject) { + var light = lights[ i ]; - var object = globject.object; - var material = object.material; + if ( ! light.castShadow ) continue; - if (material) { + if ( light instanceof THREE.PointLight || light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) { - globject.material = material; + if ( light instanceof THREE.PointLight ) { - if (material.transparent) { + // for point lights we set the sign of the shadowDarkness uniform to be negative + uniforms.shadowDarkness.value[ j ] = - light.shadowDarkness; - transparentObjects.push(globject); + } else { + + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; - } else { + } - opaqueObjects.push(globject); + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + uniforms.shadowBias.value[ j ] = light.shadowBias; - } + j ++; - } + } - } + } - // Materials + } - var shaderIDs = { - MeshDepthMaterial: 'depth', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointCloudMaterial: 'particle_basic' - }; + } - function initMaterial(material, lights, fog, object) { + // Uniforms (load to GPU) - var shaderID = shaderIDs[material.type]; + function loadUniformsMatrices ( uniforms, object ) { - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object.modelViewMatrix.elements ); - var maxLightCount = allocateLights(lights); - var maxShadows = allocateShadows(lights); - var maxBones = allocateBones(object); + if ( uniforms.normalMatrix ) { - var parameters = { + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object.normalMatrix.elements ); - precision: _precision, - supportsVertexTextures: _supportsVertexTextures, + } - map: !!material.map, - envMap: !!material.envMap, - envMapMode: material.envMap && material.envMap.mapping, - lightMap: !!material.lightMap, - aoMap: !!material.aoMap, - bumpMap: !!material.bumpMap, - normalMap: !!material.normalMap, - specularMap: !!material.specularMap, - alphaMap: !!material.alphaMap, + } - combine: material.combine, + function getTextureUnit() { - vertexColors: material.vertexColors, + var textureUnit = _usedTextureUnits; - fog: fog, - useFog: material.fog, - fogExp: fog instanceof THREE.FogExp2, + if ( textureUnit >= capabilities.maxTextures ) { - flatShading: material.shading === THREE.FlatShading, + console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: _logarithmicDepthBuffer, + } - skinning: material.skinning, - maxBones: maxBones, - useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture, + _usedTextureUnits += 1; - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: _this.maxMorphTargets, - maxMorphNormals: _this.maxMorphNormals, + return textureUnit; - maxDirLights: maxLightCount.directional, - maxPointLights: maxLightCount.point, - maxSpotLights: maxLightCount.spot, - maxHemiLights: maxLightCount.hemi, + } - maxShadows: maxShadows, - shadowMapEnabled: shadowMap.enabled && object.receiveShadow && maxShadows > 0, - shadowMapType: shadowMap.type, - shadowMapDebug: shadowMap.debug, - shadowMapCascade: shadowMap.cascade, + function loadUniformsGeneric ( uniforms ) { - alphaTest: material.alphaTest, - metal: material.metal, - doubleSided: material.side === THREE.DoubleSide, - flipSided: material.side === THREE.BackSide + var texture, textureUnit; - }; + for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { - // Generate code + var uniform = uniforms[ j ][ 0 ]; - var chunks = []; + // needsUpdate property is not added to all uniforms. + if ( uniform.needsUpdate === false ) continue; - if (shaderID) { + var type = uniform.type; + var value = uniform.value; + var location = uniforms[ j ][ 1 ]; - chunks.push(shaderID); + switch ( type ) { - } else { + case '1i': + _gl.uniform1i( location, value ); + break; - chunks.push(material.fragmentShader); - chunks.push(material.vertexShader); + case '1f': + _gl.uniform1f( location, value ); + break; - } + case '2f': + _gl.uniform2f( location, value[ 0 ], value[ 1 ] ); + break; - if (material.defines !== undefined) { + case '3f': + _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); + break; - for (var name in material.defines) { + case '4f': + _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); + break; - chunks.push(name); - chunks.push(material.defines[name]); + case '1iv': + _gl.uniform1iv( location, value ); + break; - } + case '3iv': + _gl.uniform3iv( location, value ); + break; - } + case '1fv': + _gl.uniform1fv( location, value ); + break; - for (var name in parameters) { + case '2fv': + _gl.uniform2fv( location, value ); + break; - chunks.push(name); - chunks.push(parameters[name]); + case '3fv': + _gl.uniform3fv( location, value ); + break; - } + case '4fv': + _gl.uniform4fv( location, value ); + break; - var code = chunks.join(); + case 'Matrix3fv': + _gl.uniformMatrix3fv( location, false, value ); + break; - if (!material.program) { + case 'Matrix4fv': + _gl.uniformMatrix4fv( location, false, value ); + break; - // new material - material.addEventListener('dispose', onMaterialDispose); + // - } else if (material.program.code !== code) { + case 'i': - // changed glsl or parameters - deallocateMaterial(material); + // single integer + _gl.uniform1i( location, value ); - } else { + break; - // same glsl and parameters - return; + case 'f': - } + // single float + _gl.uniform1f( location, value ); - if (shaderID) { + break; - var shader = THREE.ShaderLib[shaderID]; + case 'v2': - material.__webglShader = { - uniforms: THREE.UniformsUtils.clone(shader.uniforms), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader - } + // single THREE.Vector2 + _gl.uniform2f( location, value.x, value.y ); - } else { + break; - material.__webglShader = { - uniforms: material.uniforms, - vertexShader: material.vertexShader, - fragmentShader: material.fragmentShader - } + case 'v3': - } + // single THREE.Vector3 + _gl.uniform3f( location, value.x, value.y, value.z ); - var program; + break; - // Check if code has been already compiled + case 'v4': - for (var p = 0, pl = _programs.length; p < pl; p++) { + // single THREE.Vector4 + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); - var programInfo = _programs[p]; + break; - if (programInfo.code === code) { + case 'c': - program = programInfo; - program.usedTimes++; + // single THREE.Color + _gl.uniform3f( location, value.r, value.g, value.b ); - break; + break; - } + case 'iv1': - } + // flat array of integers (JS or typed array) + _gl.uniform1iv( location, value ); - if (program === undefined) { + break; - program = new THREE.WebGLProgram(_this, code, material, parameters); - _programs.push(program); + case 'iv': - _this.info.memory.programs = _programs.length; + // flat array of integers with 3 x N size (JS or typed array) + _gl.uniform3iv( location, value ); - } + break; - material.program = program; + case 'fv1': - var attributes = program.attributes; + // flat array of floats (JS or typed array) + _gl.uniform1fv( location, value ); - if (material.morphTargets) { + break; - material.numSupportedMorphTargets = 0; + case 'fv': - var id, base = 'morphTarget'; + // flat array of floats with 3 x N size (JS or typed array) + _gl.uniform3fv( location, value ); - for (var i = 0; i < _this.maxMorphTargets; i++) { + break; - id = base + i; + case 'v2v': - if (attributes[id] >= 0) { + // array of THREE.Vector2 - material.numSupportedMorphTargets++; + if ( uniform._array === undefined ) { - } + uniform._array = new Float32Array( 2 * value.length ); - } + } - } + for ( var i = 0, i2 = 0, il = value.length; i < il; i ++, i2 += 2 ) { - if (material.morphNormals) { + uniform._array[ i2 + 0 ] = value[ i ].x; + uniform._array[ i2 + 1 ] = value[ i ].y; - material.numSupportedMorphNormals = 0; + } - var id, base = 'morphNormal'; + _gl.uniform2fv( location, uniform._array ); - for (i = 0; i < _this.maxMorphNormals; i++) { + break; - id = base + i; + case 'v3v': - if (attributes[id] >= 0) { + // array of THREE.Vector3 - material.numSupportedMorphNormals++; + if ( uniform._array === undefined ) { - } + uniform._array = new Float32Array( 3 * value.length ); - } + } - } + for ( var i = 0, i3 = 0, il = value.length; i < il; i ++, i3 += 3 ) { - material.uniformsList = []; + uniform._array[ i3 + 0 ] = value[ i ].x; + uniform._array[ i3 + 1 ] = value[ i ].y; + uniform._array[ i3 + 2 ] = value[ i ].z; - for (var u in material.__webglShader.uniforms) { + } - var location = material.program.uniforms[u]; + _gl.uniform3fv( location, uniform._array ); - if (location) { - material.uniformsList.push([material.__webglShader.uniforms[u], location]); - } + break; - } + case 'v4v': - } + // array of THREE.Vector4 - function setMaterial(material) { + if ( uniform._array === undefined ) { - if (material.transparent === true) { + uniform._array = new Float32Array( 4 * value.length ); - state.setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha); + } - } else { + for ( var i = 0, i4 = 0, il = value.length; i < il; i ++, i4 += 4 ) { - state.setBlending(THREE.NoBlending); + uniform._array[ i4 + 0 ] = value[ i ].x; + uniform._array[ i4 + 1 ] = value[ i ].y; + uniform._array[ i4 + 2 ] = value[ i ].z; + uniform._array[ i4 + 3 ] = value[ i ].w; - } + } - state.setDepthFunc(material.depthFunc); - state.setDepthTest(material.depthTest); - state.setDepthWrite(material.depthWrite); - state.setColorWrite(material.colorWrite); - state.setPolygonOffset(material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits); + _gl.uniform4fv( location, uniform._array ); - } + break; - function setProgram(camera, lights, fog, material, object) { + case 'm3': - _usedTextureUnits = 0; + // single THREE.Matrix3 + _gl.uniformMatrix3fv( location, false, value.elements ); - if (material.needsUpdate) { + break; - initMaterial(material, lights, fog, object); - material.needsUpdate = false; + case 'm3v': - } + // array of THREE.Matrix3 - if (material.morphTargets) { + if ( uniform._array === undefined ) { - if (!object.__webglMorphTargetInfluences) { + uniform._array = new Float32Array( 9 * value.length ); - object.__webglMorphTargetInfluences = new Float32Array(_this.maxMorphTargets); + } - } + for ( var i = 0, il = value.length; i < il; i ++ ) { - } + value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); - var refreshProgram = false; - var refreshMaterial = false; - var refreshLights = false; + } - var program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.__webglShader.uniforms; + _gl.uniformMatrix3fv( location, false, uniform._array ); - if (program.id !== _currentProgram) { + break; - _gl.useProgram(program.program); - _currentProgram = program.id; + case 'm4': - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + // single THREE.Matrix4 + _gl.uniformMatrix4fv( location, false, value.elements ); - } + break; - if (material.id !== _currentMaterialId) { + case 'm4v': - if (_currentMaterialId === -1) refreshLights = true; - _currentMaterialId = material.id; + // array of THREE.Matrix4 - refreshMaterial = true; + if ( uniform._array === undefined ) { - } + uniform._array = new Float32Array( 16 * value.length ); - if (refreshProgram || camera !== _currentCamera) { + } - _gl.uniformMatrix4fv(p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements); + for ( var i = 0, il = value.length; i < il; i ++ ) { - if (_logarithmicDepthBuffer) { + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); - _gl.uniform1f(p_uniforms.logDepthBufFC, 2.0 / ( Math.log(camera.far + 1.0) / Math.LN2 )); + } - } + _gl.uniformMatrix4fv( location, false, uniform._array ); + break; - if (camera !== _currentCamera) _currentCamera = camera; + case 't': - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + // single THREE.Texture (2d or cube) - if (material instanceof THREE.ShaderMaterial || - material instanceof THREE.MeshPhongMaterial || - material.envMap) { + texture = value; + textureUnit = getTextureUnit(); - if (p_uniforms.cameraPosition !== null) { + _gl.uniform1i( location, textureUnit ); - _vector3.setFromMatrixPosition(camera.matrixWorld); - _gl.uniform3f(p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z); + if ( ! texture ) continue; - } + if ( texture instanceof THREE.CubeTexture || + ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { - } + // CompressedTexture can have Array in image :/ - if (material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.ShaderMaterial || - material.skinning) { + setCubeTexture( texture, textureUnit ); - if (p_uniforms.viewMatrix !== null) { + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - _gl.uniformMatrix4fv(p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements); + setCubeTextureDynamic( texture.texture, textureUnit ); - } + } else if ( texture instanceof THREE.WebGLRenderTarget ) { + + _this.setTexture( texture.texture, textureUnit ); - } + } else { - } + _this.setTexture( texture, textureUnit ); - // 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 (material.skinning) { + break; - if (object.bindMatrix && p_uniforms.bindMatrix !== null) { + case 'tv': - _gl.uniformMatrix4fv(p_uniforms.bindMatrix, false, object.bindMatrix.elements); + // array of THREE.Texture (2d or cube) - } + if ( uniform._array === undefined ) { - if (object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== null) { + uniform._array = []; - _gl.uniformMatrix4fv(p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements); + } - } + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - if (_supportsBoneTextures && object.skeleton && object.skeleton.useVertexTexture) { + uniform._array[ i ] = getTextureUnit(); - if (p_uniforms.boneTexture !== null) { + } - var textureUnit = getTextureUnit(); + _gl.uniform1iv( location, uniform._array ); - _gl.uniform1i(p_uniforms.boneTexture, textureUnit); - _this.setTexture(object.skeleton.boneTexture, textureUnit); + for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { - } + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; - if (p_uniforms.boneTextureWidth !== null) { + if ( ! texture ) continue; - _gl.uniform1i(p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth); + if ( texture instanceof THREE.CubeTexture || + ( texture.image instanceof Array && texture.image.length === 6 ) ) { - } + // CompressedTexture can have Array in image :/ - if (p_uniforms.boneTextureHeight !== null) { + setCubeTexture( texture, textureUnit ); - _gl.uniform1i(p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight); + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - } + setCubeTextureDynamic( texture, textureUnit ); - } else if (object.skeleton && object.skeleton.boneMatrices) { + } else { - if (p_uniforms.boneGlobalMatrices !== null) { + _this.setTexture( texture, textureUnit ); - _gl.uniformMatrix4fv(p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices); + } - } + } - } + break; - } + default: - if (refreshMaterial) { + console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); - // refresh uniforms common to several materials + } - if (fog && material.fog) { + } - refreshUniformsFog(m_uniforms, fog); + } - } + function setColorLinear( array, offset, color, intensity ) { - if (material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material.lights) { + array[ offset + 0 ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; - if (_lightsNeedUpdate) { + } - refreshLights = true; - setupLights(lights); - _lightsNeedUpdate = false; - } + function setupLights ( lights, camera ) { - if (refreshLights) { - refreshUniformsLights(m_uniforms, _lights); - markUniformsLightsNeedsUpdate(m_uniforms, true); - } else { - markUniformsLightsNeedsUpdate(m_uniforms, false); - } + var l, ll, light, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, + distance, - } + zlights = _lights, - if (material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial) { + viewMatrix = camera.matrixWorldInverse, - refreshUniformsCommon(m_uniforms, material); + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, - } + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + pointDecays = zlights.point.decays, - // refresh single material specific uniforms + 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, - if (material instanceof THREE.LineBasicMaterial) { + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, - refreshUniformsLine(m_uniforms, material); + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, - } else if (material instanceof THREE.LineDashedMaterial) { + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, - refreshUniformsLine(m_uniforms, material); - refreshUniformsDash(m_uniforms, material); + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0; - } else if (material instanceof THREE.PointCloudMaterial) { + for ( l = 0, ll = lights.length; l < ll; l ++ ) { - refreshUniformsParticle(m_uniforms, material); + light = lights[ l ]; - } else if (material instanceof THREE.MeshPhongMaterial) { + if ( light.onlyShadow ) continue; - refreshUniformsPhong(m_uniforms, material); + color = light.color; + intensity = light.intensity; + distance = light.distance; - } else if (material instanceof THREE.MeshLambertMaterial) { + if ( light instanceof THREE.AmbientLight ) { - refreshUniformsLambert(m_uniforms, material); + if ( ! light.visible ) continue; - } else if (material instanceof THREE.MeshDepthMaterial) { + r += color.r; + g += color.g; + b += color.b; - m_uniforms.mNear.value = camera.near; - m_uniforms.mFar.value = camera.far; - m_uniforms.opacity.value = material.opacity; + } else if ( light instanceof THREE.DirectionalLight ) { - } else if (material instanceof THREE.MeshNormalMaterial) { + dirCount += 1; - m_uniforms.opacity.value = material.opacity; + if ( ! light.visible ) continue; - } + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.transformDirection( viewMatrix ); - if (object.receiveShadow && !material._shadowPass) { + dirOffset = dirLength * 3; - refreshUniformsShadow(m_uniforms, lights); + dirPositions[ dirOffset + 0 ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; - } + setColorLinear( dirColors, dirOffset, color, intensity ); - // load common uniforms + dirLength += 1; - loadUniformsGeneric(material.uniformsList); + } else if ( light instanceof THREE.PointLight ) { - } + pointCount += 1; - loadUniformsMatrices(p_uniforms, object); + if ( ! light.visible ) continue; - if (p_uniforms.modelMatrix !== null) { + pointOffset = pointLength * 3; - _gl.uniformMatrix4fv(p_uniforms.modelMatrix, false, object.matrixWorld.elements); + setColorLinear( pointColors, pointOffset, color, intensity ); - } + _vector3.setFromMatrixPosition( light.matrixWorld ); + _vector3.applyMatrix4( viewMatrix ); - return program; + pointPositions[ pointOffset + 0 ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; - } + // 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; - // Uniforms (refresh uniforms objects) + pointLength += 1; - function refreshUniformsCommon(uniforms, material) { + } else if ( light instanceof THREE.SpotLight ) { - uniforms.opacity.value = material.opacity; + spotCount += 1; - uniforms.diffuse.value = material.color; + if ( ! light.visible ) continue; - uniforms.map.value = material.map; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; + spotOffset = spotLength * 3; - if (material.bumpMap) { + setColorLinear( spotColors, spotOffset, color, intensity ); - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.copy( _direction ).applyMatrix4( viewMatrix ); - } + spotPositions[ spotOffset + 0 ] = _vector3.x; + spotPositions[ spotOffset + 1 ] = _vector3.y; + spotPositions[ spotOffset + 2 ] = _vector3.z; - if (material.normalMap) { + spotDistances[ spotLength ] = distance; - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy(material.normalScale); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.transformDirection( viewMatrix ); - } + spotDirections[ spotOffset + 0 ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; - var uvScaleMap; + spotLength += 1; - if (material.map) { + } else if ( light instanceof THREE.HemisphereLight ) { - uvScaleMap = material.map; + hemiCount += 1; - } else if (material.specularMap) { + if ( ! light.visible ) continue; - uvScaleMap = material.specularMap; + _direction.setFromMatrixPosition( light.matrixWorld ); + _direction.transformDirection( viewMatrix ); - } else if (material.normalMap) { + hemiOffset = hemiLength * 3; - uvScaleMap = material.normalMap; + hemiPositions[ hemiOffset + 0 ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; - } else if (material.bumpMap) { + skyColor = light.color; + groundColor = light.groundColor; - uvScaleMap = material.bumpMap; + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - } else if (material.alphaMap) { + hemiLength += 1; - uvScaleMap = material.alphaMap; + } - } + } - if (uvScaleMap !== undefined) { + // null eventual remains from removed lights + // (this is to avoid if in shader) - if (uvScaleMap instanceof THREE.WebGLRenderTarget) uvScaleMap = uvScaleMap.texture; + 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; - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; - uniforms.offsetRepeat.value.set(offset.x, offset.y, repeat.x, repeat.y); + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; - } + } - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + // GL state setting - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - } + if ( cullFace === THREE.CullFaceNone ) { - function refreshUniformsLine(uniforms, material) { + state.disable( _gl.CULL_FACE ); - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; + } else { - } + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { - function refreshUniformsDash(uniforms, material) { + _gl.frontFace( _gl.CW ); - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; + } else { - } + _gl.frontFace( _gl.CCW ); - 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. + if ( cullFace === THREE.CullFaceBack ) { - uniforms.map.value = material.map; + _gl.cullFace( _gl.BACK ); - if (material.map !== null) { + } else if ( cullFace === THREE.CullFaceFront ) { - var offset = material.map.offset; - var repeat = material.map.repeat; + _gl.cullFace( _gl.FRONT ); - uniforms.offsetRepeat.value.set(offset.x, offset.y, repeat.x, repeat.y); + } else { - } + _gl.cullFace( _gl.FRONT_AND_BACK ); - } + } - function refreshUniformsFog(uniforms, fog) { + state.enable( _gl.CULL_FACE ); - uniforms.fogColor.value = fog.color; + } - if (fog instanceof THREE.Fog) { + }; - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + // Textures - } else if (fog instanceof THREE.FogExp2) { + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { - uniforms.fogDensity.value = fog.density; + var extension; - } + if ( isImagePowerOfTwo ) { - } + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); - function refreshUniformsPhong(uniforms, material) { + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); - uniforms.shininess.value = material.shininess; + } else { - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; + if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); - } + } - function refreshUniformsLambert(uniforms, material) { + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - uniforms.emissive.value = material.emissive; + if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { - } + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); - function refreshUniformsLights(uniforms, lights) { + } - uniforms.ambientLightColor.value = lights.ambient; + } - uniforms.directionalLightColor.value = lights.directional.colors; - uniforms.directionalLightDirection.value = lights.directional.positions; + extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - uniforms.pointLightColor.value = lights.point.colors; - uniforms.pointLightPosition.value = lights.point.positions; - uniforms.pointLightDistance.value = lights.point.distances; - uniforms.pointLightDecay.value = lights.point.decays; + if ( extension ) { - 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; + if ( texture.type === THREE.FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; + if ( texture.type === THREE.HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; - uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; - uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; - uniforms.hemisphereLightDirection.value = lights.hemi.positions; + if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - } + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); + properties.get( texture ).__currentAnisotropy = texture.anisotropy; - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + } - function markUniformsLightsNeedsUpdate(uniforms, value) { + } - uniforms.ambientLightColor.needsUpdate = value; + } - uniforms.directionalLightColor.needsUpdate = value; - uniforms.directionalLightDirection.needsUpdate = value; + function uploadTexture( textureProperties, texture, slot ) { - uniforms.pointLightColor.needsUpdate = value; - uniforms.pointLightPosition.needsUpdate = value; - uniforms.pointLightDistance.needsUpdate = value; - uniforms.pointLightDecay.needsUpdate = value; + if ( textureProperties.__webglInit === undefined ) { - 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; + textureProperties.__webglInit = true; - uniforms.hemisphereLightSkyColor.needsUpdate = value; - uniforms.hemisphereLightGroundColor.needsUpdate = value; - uniforms.hemisphereLightDirection.needsUpdate = value; + texture.__webglInit = true; - } + texture.addEventListener( 'dispose', onTextureDispose ); - function refreshUniformsShadow(uniforms, lights) { + textureProperties.__webglTexture = _gl.createTexture(); - if (uniforms.shadowMatrix) { + _infoMemory.textures ++; - var j = 0; + } - for (var i = 0, il = lights.length; i < il; i++) { + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - var light = lights[i]; + _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 ); - if (!light.castShadow) continue; + texture.image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); - if (light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && !light.shadowCascade )) { + var image = texture.image, + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); - uniforms.shadowMap.value[j] = light.shadowMap; - uniforms.shadowMapSize.value[j] = light.shadowMapSize; + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); - uniforms.shadowMatrix.value[j] = light.shadowMatrix; + var mipmap, mipmaps = texture.mipmaps; - uniforms.shadowDarkness.value[j] = light.shadowDarkness; - uniforms.shadowBias.value[j] = light.shadowBias; + if ( texture instanceof THREE.DataTexture ) { - j++; + // 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 ) { - } + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } + } - // Uniforms (load to GPU) + texture.generateMipmaps = false; - function loadUniformsMatrices(uniforms, object) { + } else { - _gl.uniformMatrix4fv(uniforms.modelViewMatrix, false, object._modelViewMatrix.elements); + state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - if (uniforms.normalMatrix) { + } - _gl.uniformMatrix3fv(uniforms.normalMatrix, false, object._normalMatrix.elements); + } else if ( texture instanceof THREE.CompressedTexture ) { - } + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; - function getTextureUnit() { + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - var textureUnit = _usedTextureUnits; + if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { - if (textureUnit >= _maxTextures) { + state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - THREE.warn('WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures); + } else { - } + console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); - _usedTextureUnits += 1; + } - return textureUnit; + } else { - } + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - function loadUniformsGeneric(uniforms) { + } - var texture, textureUnit, offset; + } - for (var j = 0, jl = uniforms.length; j < jl; j++) { + } else { - var uniform = uniforms[j][0]; + // regular Texture (image, video, canvas) - // needsUpdate property is not added to all uniforms. - if (uniform.needsUpdate === false) continue; + // 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 - var type = uniform.type; - var value = uniform.value; - var location = uniforms[j][1]; + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - switch (type) { + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - case '1i': - _gl.uniform1i(location, value); - break; + mipmap = mipmaps[ i ]; + state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - case '1f': - _gl.uniform1f(location, value); - break; + } - case '2f': - _gl.uniform2f(location, value[0], value[1]); - break; + texture.generateMipmaps = false; - case '3f': - _gl.uniform3f(location, value[0], value[1], value[2]); - break; + } else { - case '4f': - _gl.uniform4f(location, value[0], value[1], value[2], value[3]); - break; + state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); - case '1iv': - _gl.uniform1iv(location, value); - break; + } - case '3iv': - _gl.uniform3iv(location, value); - break; + } - case '1fv': - _gl.uniform1fv(location, value); - break; + if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - case '2fv': - _gl.uniform2fv(location, value); - break; + textureProperties.__version = texture.version; - case '3fv': - _gl.uniform3fv(location, value); - break; + if ( texture.onUpdate ) texture.onUpdate( texture ); - case '4fv': - _gl.uniform4fv(location, value); - break; + } - case 'Matrix3fv': - _gl.uniformMatrix3fv(location, false, value); - break; + this.setTexture = function ( texture, slot ) { - case 'Matrix4fv': - _gl.uniformMatrix4fv(location, false, value); - break; + var textureProperties = properties.get( texture ); - // + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - case 'i': + var image = texture.image; - // single integer - _gl.uniform1i(location, value); + if ( image === undefined ) { - break; + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); + return; - case 'f': + } - // single float - _gl.uniform1f(location, value); + if ( image.complete === false ) { - break; + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); + return; - case 'v2': + } - // single THREE.Vector2 - _gl.uniform2f(location, value.x, value.y); + uploadTexture( textureProperties, texture, slot ); + return; - break; + } - case 'v3': + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - // single THREE.Vector3 - _gl.uniform3f(location, value.x, value.y, value.z); + }; - break; + function clampToMaxSize ( image, maxSize ) { - case 'v4': + if ( image.width > maxSize || image.height > maxSize ) { - // single THREE.Vector4 - _gl.uniform4f(location, value.x, value.y, value.z, value.w); + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. - break; + var scale = maxSize / Math.max( image.width, image.height ); - case 'c': + var canvas = document.createElement( 'canvas' ); + canvas.width = Math.floor( image.width * scale ); + canvas.height = Math.floor( image.height * scale ); - // single THREE.Color - _gl.uniform3f(location, value.r, value.g, value.b); + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - break; + console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); - case 'iv1': + return canvas; - // flat array of integers (JS or typed array) - _gl.uniform1iv(location, value); + } - break; + return image; - case 'iv': + } - // flat array of integers with 3 x N size (JS or typed array) - _gl.uniform3iv(location, value); + function setCubeTexture ( texture, slot ) { - break; + var textureProperties = properties.get( texture ); - case 'fv1': + if ( texture.image.length === 6 ) { - // flat array of floats (JS or typed array) - _gl.uniform1fv(location, value); + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - break; + if ( ! textureProperties.__image__webglTextureCube ) { - case 'fv': + texture.addEventListener( 'dispose', onTextureDispose ); - // flat array of floats with 3 x N size (JS or typed array) - _gl.uniform3fv(location, value); + textureProperties.__image__webglTextureCube = _gl.createTexture(); - break; + _infoMemory.textures ++; - case 'v2v': + } - // array of THREE.Vector2 + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); - if (uniform._array === undefined) { + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - uniform._array = new Float32Array(2 * value.length); + var isCompressed = texture instanceof THREE.CompressedTexture; + var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; - } + var cubeImage = []; - for (var i = 0, il = value.length; i < il; i++) { + for ( var i = 0; i < 6; i ++ ) { - offset = i * 2; + if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { - uniform._array[offset + 0] = value[i].x; - uniform._array[offset + 1] = value[i].y; + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); - } + } else { - _gl.uniform2fv(location, uniform._array); + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - break; + } - case 'v3v': + } - // array of THREE.Vector3 + var image = cubeImage[ 0 ], + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); - if (uniform._array === undefined) { + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); - uniform._array = new Float32Array(3 * value.length); + for ( var i = 0; i < 6; i ++ ) { - } + if ( ! isCompressed ) { - for (var i = 0, il = value.length; i < il; i++) { + if ( isDataTexture ) { - offset = i * 3; + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - uniform._array[offset + 0] = value[i].x; - uniform._array[offset + 1] = value[i].y; - uniform._array[offset + 2] = value[i].z; + } else { - } + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - _gl.uniform3fv(location, uniform._array); + } - break; + } else { - case 'v4v': + var mipmap, mipmaps = cubeImage[ i ].mipmaps; - // array of THREE.Vector4 + for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - if (uniform._array === undefined) { + mipmap = mipmaps[ j ]; - uniform._array = new Float32Array(4 * value.length); + if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { - } + if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { - for (var i = 0, il = value.length; i < il; i++) { + state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - offset = i * 4; + } else { - uniform._array[offset + 0] = value[i].x; - uniform._array[offset + 1] = value[i].y; - uniform._array[offset + 2] = value[i].z; - uniform._array[offset + 3] = value[i].w; + console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); - } + } - _gl.uniform4fv(location, uniform._array); + } else { - break; + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - case 'm3': + } - // single THREE.Matrix3 - _gl.uniformMatrix3fv(location, false, value.elements); + } - break; + } - case 'm3v': + } - // array of THREE.Matrix3 + if ( texture.generateMipmaps && isImagePowerOfTwo ) { - if (uniform._array === undefined) { + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - uniform._array = new Float32Array(9 * value.length); + } - } + textureProperties.__version = texture.version; - for (var i = 0, il = value.length; i < il; i++) { + if ( texture.onUpdate ) texture.onUpdate( texture ); - value[i].flattenToArrayOffset(uniform._array, i * 9); + } else { - } + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); - _gl.uniformMatrix3fv(location, false, uniform._array); + } - break; + } - case 'm4': + } - // single THREE.Matrix4 - _gl.uniformMatrix4fv(location, false, value.elements); + function setCubeTextureDynamic ( texture, slot ) { - break; + state.activeTexture( _gl.TEXTURE0 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); - case 'm4v': + } - // array of THREE.Matrix4 + // Render targets - if (uniform._array === undefined) { + function setupFrameBufferTexture ( framebuffer, renderTarget, attachment, textureTarget ) { - uniform._array = new Float32Array(16 * value.length); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); - } + } - for (var i = 0, il = value.length; i < il; i++) { + function setupRenderBufferStorage ( renderbuffer, renderTarget ) { - value[i].flattenToArrayOffset(uniform._array, i * 16); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - } + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - _gl.uniformMatrix4fv(location, false, uniform._array); + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - break; + /* For some reason this is not working. Defaulting to RGBA4. + } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - case 't': + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + */ - // single THREE.Texture (2d or cube) + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - texture = value; - textureUnit = getTextureUnit(); + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - _gl.uniform1i(location, textureUnit); + } else { - if (!texture) continue; + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); - if (texture instanceof THREE.CubeTexture || - ( texture.image instanceof Array && texture.image.length === 6 )) { // CompressedTexture can have Array in image :/ + } - setCubeTexture(texture, textureUnit); + } - } else if (texture instanceof THREE.WebGLRenderTargetCube) { + function setupDepthRenderbuffer(renderTarget) { + + var renderTargetProperties = properties.get( renderTarget ); + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); + if ( isCube ) { - setCubeTextureDynamic(texture.texture, textureUnit); + renderTargetProperties.__webglRenderbuffer = []; + for ( var i = 0; i < 6; i ++ ) { - } else if (texture instanceof THREE.WebGLRenderTarget) { + renderTargetProperties.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglRenderbuffer[ i ], renderTarget ); - _this.setTexture(texture.texture, textureUnit); + } - } else { + } + else { - _this.setTexture(texture, textureUnit); + if ( renderTarget.shareDepthFrom ) { + var sharedProperties = properties.get( renderTarget.shareDepthFrom ); + renderTargetProperties.__webglRenderbuffer = sharedProperties.__webglRenderbuffer; + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTargetProperties.__webglRenderbuffer ); + + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTargetProperties.__webglRenderbuffer ); + + } + + } else { + + renderTargetProperties.__webglRenderbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglRenderbuffer, renderTarget ); + + } + + } + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - } + }; - break; + function setupDepthTexture(renderTarget) { - case 'tv': + var depthTexture = renderTarget.depthTexture; + var depthTextureProperties = properties.get( renderTarget.depthTexture ); + var isPowerOfTwo = THREE.Math.isPowerOfTwo( depthTexture.width ) && THREE.Math.isPowerOfTwo( depthTexture.height ); - // array of THREE.Texture (2d) + depthTextureProperties.__webglTexture = _gl.createTexture(); + _gl.bindTexture(_gl.TEXTURE_2D, depthTextureProperties.__webglTexture); + setTextureParameters(_gl.TEXTURE_2D, depthTexture, isPowerOfTwo); - if (uniform._array === undefined) { + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - uniform._array = []; + _gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.DEPTH_COMPONENT, depthTexture.width, depthTexture.height, 0, _gl.DEPTH_COMPONENT, _gl.UNSIGNED_INT, null); + _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, depthTextureProperties.__webglTexture, 0); - } + } else if ( renderTarget.stencilBuffer ) { + + _gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.DEPTH_STENCIL, depthTexture.width, depthTexture.height, 0, _gl.DEPTH_STENCIL, extensions.get( 'WEBGL_depth_texture' ).UNSIGNED_INT_24_8_WEBGL, null); + _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, depthTextureProperties.__webglTexture, 0); - for (var i = 0, il = uniform.value.length; i < il; i++) { + } - uniform._array[i] = getTextureUnit(); + _gl.bindTexture(_gl.TEXTURE_2D, null); - } + }; + + this.setRenderTarget = function ( renderTarget ) { - _gl.uniform1iv(location, uniform._array); + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - for (var i = 0, il = uniform.value.length; i < il; i++) { + if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { - texture = uniform.value[i]; - textureUnit = uniform._array[i]; + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); - if (!texture) continue; + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - _this.setTexture(texture, textureUnit); + textureProperties.__webglTexture = _gl.createTexture(); - } + _infoMemory.textures ++; - break; + // + // Setup color buffer + // - default: + var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), + glFormat = paramThreeToGL( renderTarget.texture.format ), + glType = paramThreeToGL( renderTarget.texture.type ); - THREE.warn('THREE.WebGLRenderer: Unknown uniform type: ' + type); + if ( isCube ) { - } + renderTargetProperties.__webglFramebuffer = []; - } + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); - } + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); - function setupMatrices(object, camera) { + for ( var i = 0; i < 6; i ++ ) { - object._modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); - object._normalMatrix.getNormalMatrix(object._modelViewMatrix); + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + renderTargetProperties.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - } + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); - function setColorLinear(array, offset, color, intensity) { + } - array[offset + 0] = color.r * intensity; - array[offset + 1] = color.g * intensity; - array[offset + 2] = color.b * intensity; + if ( renderTarget.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - } + } else { - function setupLights(lights) { + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - var l, ll, light, - r = 0, g = 0, b = 0, - color, skyColor, groundColor, - intensity, - distance, + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); - zlights = _lights, + state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - dirColors = zlights.directional.colors, - dirPositions = zlights.directional.positions, + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D ); - pointColors = zlights.point.colors, - pointPositions = zlights.point.positions, - pointDistances = zlights.point.distances, - pointDecays = zlights.point.decays, + if ( renderTarget.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); - 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, + } - hemiSkyColors = zlights.hemi.skyColors, - hemiGroundColors = zlights.hemi.groundColors, - hemiPositions = zlights.hemi.positions, + // Release textures - dirLength = 0, - pointLength = 0, - spotLength = 0, - hemiLength = 0, + if ( isCube ) { - dirCount = 0, - pointCount = 0, - spotCount = 0, - hemiCount = 0, + state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - dirOffset = 0, - pointOffset = 0, - spotOffset = 0, - hemiOffset = 0; + } else { - for (l = 0, ll = lights.length; l < ll; l++) { + state.bindTexture( _gl.TEXTURE_2D, null ); - light = lights[l]; + } - if (light.onlyShadow) continue; + // + // Setup depth and stencil buffers + // + if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; + if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; - color = light.color; - intensity = light.intensity; - distance = light.distance; + if (renderTarget.depthBuffer || renderTarget.stencilBuffer) { - if (light instanceof THREE.AmbientLight) { + if ( renderTarget.depthTexture && extensions.get( 'WEBGL_depth_texture' ) ) setupDepthTexture(renderTarget); + else setupDepthRenderbuffer(renderTarget); - if (!light.visible) continue; + } - r += color.r; - g += color.g; - b += color.b; + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - } else if (light instanceof THREE.DirectionalLight) { + } - dirCount += 1; + var framebuffer, width, height, vx, vy; - if (!light.visible) continue; + if ( renderTarget ) { - _direction.setFromMatrixPosition(light.matrixWorld); - _vector3.setFromMatrixPosition(light.target.matrixWorld); - _direction.sub(_vector3); - _direction.normalize(); + var renderTargetProperties = properties.get( renderTarget ); - dirOffset = dirLength * 3; + if ( isCube ) { - dirPositions[dirOffset + 0] = _direction.x; - dirPositions[dirOffset + 1] = _direction.y; - dirPositions[dirOffset + 2] = _direction.z; + framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ]; - setColorLinear(dirColors, dirOffset, color, intensity); + } else { - dirLength += 1; + framebuffer = renderTargetProperties.__webglFramebuffer; - } else if (light instanceof THREE.PointLight) { + } - pointCount += 1; + width = renderTarget.width; + height = renderTarget.height; - if (!light.visible) continue; + vx = 0; + vy = 0; - pointOffset = pointLength * 3; + } else { - setColorLinear(pointColors, pointOffset, color, intensity); + framebuffer = null; - _vector3.setFromMatrixPosition(light.matrixWorld); + width = _viewportWidth; + height = _viewportHeight; - pointPositions[pointOffset + 0] = _vector3.x; - pointPositions[pointOffset + 1] = _vector3.y; - pointPositions[pointOffset + 2] = _vector3.z; + vx = _viewportX; + vy = _viewportY; - // 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; + if ( framebuffer !== _currentFramebuffer ) { - } else if (light instanceof THREE.SpotLight) { + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.viewport( vx, vy, width, height ); - spotCount += 1; + _currentFramebuffer = framebuffer; - if (!light.visible) continue; + } - spotOffset = spotLength * 3; + if ( isCube ) { - setColorLinear(spotColors, spotOffset, color, intensity); + var renderTargetProperties = properties.get( renderTarget ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, renderTargetProperties.__webglTexture, 0 ); - _direction.setFromMatrixPosition(light.matrixWorld); + } - spotPositions[spotOffset + 0] = _direction.x; - spotPositions[spotOffset + 1] = _direction.y; - spotPositions[spotOffset + 2] = _direction.z; + _currentWidth = width; + _currentHeight = height; - spotDistances[spotLength] = distance; + }; - _vector3.setFromMatrixPosition(light.target.matrixWorld); - _direction.sub(_vector3); - _direction.normalize(); + this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { - spotDirections[spotOffset + 0] = _direction.x; - spotDirections[spotOffset + 1] = _direction.y; - spotDirections[spotOffset + 2] = _direction.z; + if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { - spotAnglesCos[spotLength] = Math.cos(light.angle); - spotExponents[spotLength] = light.exponent; - spotDecays[spotLength] = ( light.distance === 0 ) ? 0.0 : light.decay; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - spotLength += 1; + } - } else if (light instanceof THREE.HemisphereLight) { + if ( properties.get( renderTarget ).__webglFramebuffer ) { - hemiCount += 1; + var restore = false; - if (!light.visible) continue; + if ( properties.get( renderTarget ).__webglFramebuffer !== _currentFramebuffer ) { - _direction.setFromMatrixPosition(light.matrixWorld); - _direction.normalize(); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, properties.get( renderTarget ).__webglFramebuffer ); - hemiOffset = hemiLength * 3; + restore = true; - hemiPositions[hemiOffset + 0] = _direction.x; - hemiPositions[hemiOffset + 1] = _direction.y; - hemiPositions[hemiOffset + 2] = _direction.z; + } - skyColor = light.color; - groundColor = light.groundColor; + if ( renderTarget.texture.format !== THREE.RGBAFormat && paramThreeToGL( renderTarget.texture.format ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - setColorLinear(hemiSkyColors, hemiOffset, skyColor, intensity); - setColorLinear(hemiGroundColors, hemiOffset, groundColor, intensity); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - hemiLength += 1; + } - } + if ( renderTarget.texture.type !== THREE.UnsignedByteType && paramThreeToGL( renderTarget.texture.type ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) ) { - } + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - // 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; + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - zlights.directional.length = dirLength; - zlights.point.length = pointLength; - zlights.spot.length = spotLength; - zlights.hemi.length = hemiLength; + _gl.readPixels( x, y, width, height, paramThreeToGL( renderTarget.texture.format ), paramThreeToGL( renderTarget.texture.type ), buffer ); - zlights.ambient[0] = r; - zlights.ambient[1] = g; - zlights.ambient[2] = b; + } else { - } + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - // GL state setting + } - this.setFaceCulling = function (cullFace, frontFaceDirection) { + if ( restore ) { - if (cullFace === THREE.CullFaceNone) { + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - _gl.disable(_gl.CULL_FACE); + } - } else { + } - if (frontFaceDirection === THREE.FrontFaceDirectionCW) { + }; - _gl.frontFace(_gl.CW); + function updateRenderTargetMipmap( renderTarget ) { - } else { + var target = renderTarget instanceof THREE.WebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; + var texture = properties.get( renderTarget.texture ).__webglTexture; - _gl.frontFace(_gl.CCW); + state.bindTexture( target, texture ); + _gl.generateMipmap( target ); + state.bindTexture( target, null ); - } + } - if (cullFace === THREE.CullFaceBack) { + // Fallback filters for non-power-of-2 textures - _gl.cullFace(_gl.BACK); + function filterFallback ( f ) { - } else if (cullFace === THREE.CullFaceFront) { + if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { - _gl.cullFace(_gl.FRONT); + return _gl.NEAREST; - } else { + } - _gl.cullFace(_gl.FRONT_AND_BACK); + return _gl.LINEAR; - } + } - _gl.enable(_gl.CULL_FACE); + // Map three.js constants to WebGL constants - } + function paramThreeToGL ( p ) { - }; + var extension; - this.setMaterialFaces = function (material) { + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; + if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; - state.setDoubleSided(material.side === THREE.DoubleSide); - state.setFlipSided(material.side === THREE.BackSide); + if ( p === THREE.NearestFilter ) return _gl.NEAREST; + if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; - }; + if ( p === THREE.LinearFilter ) return _gl.LINEAR; + if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; - // Textures + if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; - function setTextureParameters(textureType, texture, isImagePowerOfTwo) { + if ( p === THREE.ByteType ) return _gl.BYTE; + if ( p === THREE.ShortType ) return _gl.SHORT; + if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === THREE.IntType ) return _gl.INT; + if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === THREE.FloatType ) return _gl.FLOAT; - var extension; + extension = extensions.get( 'OES_texture_half_float' ); - if (isImagePowerOfTwo) { + if ( extension !== null ) { - _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL(texture.wrapS)); - _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL(texture.wrapT)); + if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; - _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL(texture.magFilter)); - _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL(texture.minFilter)); + } - } else { + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; + if ( p === THREE.RGBFormat ) return _gl.RGB; + if ( p === THREE.RGBAFormat ) return _gl.RGBA; + if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; + if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; - _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE); - _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE); + if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; + if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; - if (texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping) { + if ( p === THREE.ZeroFactor ) return _gl.ZERO; + if ( p === THREE.OneFactor ) return _gl.ONE; + if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; - THREE.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )'); + if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; + if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; - } + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, filterFallback(texture.magFilter)); - _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, filterFallback(texture.minFilter)); + if ( extension !== null ) { - if (texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter) { + 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; - THREE.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )'); + } - } + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - } + if ( extension !== null ) { - extension = extensions.get('EXT_texture_filter_anisotropic'); + 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; - if (extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType) { + } - if (texture.anisotropy > 1 || texture.__currentAnisotropy) { + extension = extensions.get( 'EXT_blend_minmax' ); - _gl.texParameterf(textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropy, _this.getMaxAnisotropy())); - texture.__currentAnisotropy = texture.anisotropy; + if ( extension !== null ) { - } + if ( p === THREE.MinEquation ) return extension.MIN_EXT; + if ( p === THREE.MaxEquation ) return extension.MAX_EXT; - } + } - } + return 0; - this.uploadTexture = function (texture, slot) { + } - if (texture.__webglInit === undefined) { + // DEPRECATED - texture.__webglInit = true; + this.supportsFloatTextures = function () { - texture.addEventListener('dispose', onTextureDispose); + console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); + return extensions.get( 'OES_texture_float' ); - texture.__webglTexture = _gl.createTexture(); + }; - _this.info.memory.textures++; + this.supportsHalfFloatTextures = function () { - } + console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); + return extensions.get( 'OES_texture_half_float' ); - state.activeTexture(_gl.TEXTURE0 + slot); - state.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); + this.supportsStandardDerivatives = function () { - texture.image = clampToMaxSize(texture.image, _maxTextureSize); + console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); + return extensions.get( 'OES_standard_derivatives' ); - 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); + this.supportsCompressedTextureS3TC = function () { - var mipmap, mipmaps = texture.mipmaps; + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); + return extensions.get( 'WEBGL_compressed_texture_s3tc' ); - 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 + this.supportsCompressedTexturePVRTC = function () { - if (mipmaps.length > 0 && isImagePowerOfTwo) { + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); + return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - 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); + this.supportsBlendMinMax = function () { - } + console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); + return extensions.get( 'EXT_blend_minmax' ); - texture.generateMipmaps = false; + }; - } else { + this.supportsVertexTextures = function () { - _gl.texImage2D(_gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data); + return capabilities.vertexTextures; - } + }; - } else if (texture instanceof THREE.CompressedTexture) { + this.supportsInstancedArrays = function () { - for (var i = 0, il = mipmaps.length; i < il; i++) { + console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); + return extensions.get( 'ANGLE_instanced_arrays' ); - mipmap = mipmaps[i]; + }; - if (texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat) { + // - if (getCompressedTextureFormats().indexOf(glFormat) > -1) { + this.initMaterial = function () { - _gl.compressedTexImage2D(_gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data); + console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); - } else { + }; - THREE.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"); + this.addPrePlugin = function () { - } + console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - } else { + }; - _gl.texImage2D(_gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); + this.addPostPlugin = function () { - } + console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); - } + }; - } else { // regular Texture (image, video, canvas) + this.updateShadowMap = function () { - // 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 + console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - if (mipmaps.length > 0 && isImagePowerOfTwo) { + }; - for (var i = 0, il = mipmaps.length; i < il; i++) { + Object.defineProperties( this, { + shadowMapEnabled: { + get: function () { - mipmap = mipmaps[i]; - _gl.texImage2D(_gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap); + return shadowMap.enabled; - } + }, + set: function ( value ) { - texture.generateMipmaps = false; + console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); + shadowMap.enabled = value; - } else { + } + }, + shadowMapType: { + get: function () { - _gl.texImage2D(_gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image); + return shadowMap.type; - } + }, + set: function ( value ) { - } + console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); + shadowMap.type = value; - if (texture.generateMipmaps && isImagePowerOfTwo) _gl.generateMipmap(_gl.TEXTURE_2D); + } + }, + shadowMapCullFace: { + get: function () { - texture.needsUpdate = false; + return shadowMap.cullFace; - if (texture.onUpdate) texture.onUpdate(texture); + }, + set: function ( value ) { - }; + console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' ); + shadowMap.cullFace = value; - this.setTexture = function (texture, slot) { + } + }, + shadowMapDebug: { + get: function () { - if (texture.needsUpdate === true) { + return shadowMap.debug; - var image = texture.image; + }, + set: function ( value ) { - if (image.complete === false) { + console.warn( 'THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.' ); + shadowMap.debug = value; - THREE.warn('THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture); - return; + } + } + } ); - } +}; - _this.uploadTexture(texture, slot); - return; +// File:src/renderers/WebGLRenderTarget.js - } +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + * @author Marius Kintel / https://github.com/kintel + */ - state.activeTexture(_gl.TEXTURE0 + slot); - state.bindTexture(_gl.TEXTURE_2D, texture.__webglTexture); +/* + In options, we can specify: + * Texture parameters for an auto-generated target texture + * An actual texture of type THREE.Texture + * An optional depthtexture of type THREE.DepthTexture +*/ +THREE.WebGLRenderTarget = function ( width, height, options ) { - }; + this.uuid = THREE.Math.generateUUID(); - function clampToMaxSize(image, maxSize) { + this.width = width; + this.height = height; - if (image.width > maxSize || image.height > maxSize) { + options = options || {}; - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. + this.texture = options.texture; + if (!this.texture) { + this.texture = new THREE.Texture(undefined, undefined, + options.wrapS, options.wrapT, + options.magFilter, options.minFilter, + options.format, options.type, + options.anisotropy); + } + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + this.depthTexture = options.depthTexture; - var scale = maxSize / Math.max(image.width, image.height); + this.generateMipmaps = true; - var canvas = document.createElement('canvas'); - canvas.width = Math.floor(image.width * scale); - canvas.height = Math.floor(image.height * scale); + this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height); +}; - THREE.warn('THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image); +THREE.WebGLRenderTarget.prototype = { - return canvas; + constructor: THREE.WebGLRenderTarget, - } + setSize: function ( width, height ) { - return image; + if ( this.width !== width || this.height !== height ) { - } + this.width = width; + this.height = height; - function setCubeTexture(texture, slot) { + this.dispose(); - if (texture.image.length === 6) { + } - if (texture.needsUpdate) { + }, - if (!texture.image.__webglTextureCube) { + clone: function () { - texture.addEventListener('dispose', onTextureDispose); + return new this.constructor().copy( this ); - texture.image.__webglTextureCube = _gl.createTexture(); + }, - _this.info.memory.textures++; + copy: function ( source ) { - } + this.width = source.width; + this.height = source.height; - state.activeTexture(_gl.TEXTURE0 + slot); - state.bindTexture(_gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube); + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; + this.texture = this.texture.clone(); + if (this.depthTexture) this.depthTexture = this.depthTexture.clone(); - _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); + this.generateMipmaps = source.generateMipmaps; - var isCompressed = texture instanceof THREE.CompressedTexture; - var isDataTexture = texture.image[0] instanceof THREE.DataTexture; + this.shareDepthFrom = source.shareDepthFrom; - var cubeImage = []; + return this; - for (var i = 0; i < 6; i++) { + }, - if (_this.autoScaleCubemaps && !isCompressed && !isDataTexture) { + dispose: function () { - cubeImage[i] = clampToMaxSize(texture.image[i], _maxCubemapSize); + this.dispatchEvent( { type: 'dispose' } ); - } else { + } - cubeImage[i] = isDataTexture ? texture.image[i].image : texture.image[i]; +}; - } +THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); - } +// File:src/renderers/WebGLRenderTargetCube.js - var image = cubeImage[0], - isImagePowerOfTwo = THREE.Math.isPowerOfTwo(image.width) && THREE.Math.isPowerOfTwo(image.height), - glFormat = paramThreeToGL(texture.format), - glType = paramThreeToGL(texture.type); +/** + * @author alteredq / http://alteredqualia.com + */ - setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo); +THREE.WebGLRenderTargetCube = function ( width, height, options ) { - for (var i = 0; i < 6; i++) { + THREE.WebGLRenderTarget.call( this, width, height, options ); - if (!isCompressed) { + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - 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); +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); +THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; - } else { +// File:src/renderers/webgl/WebGLBufferRenderer.js - _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[i]); +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } +THREE.WebGLBufferRenderer = function ( _gl, extensions, _infoRender ) { - } else { + var mode; - var mipmap, mipmaps = cubeImage[i].mipmaps; + function setMode( value ) { - for (var j = 0, jl = mipmaps.length; j < jl; j++) { + mode = value; - mipmap = mipmaps[j]; + } - if (texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat) { + function render( start, count ) { - if (getCompressedTextureFormats().indexOf(glFormat) > -1) { + _gl.drawArrays( mode, start, count ); - _gl.compressedTexImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data); + _infoRender.calls ++; + _infoRender.vertices += count; + if ( mode === _gl.TRIANGLES ) _infoRender.faces += count / 3; - } else { + } - THREE.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()"); + function renderInstances( geometry ) { - } + var extension = extensions.get( 'ANGLE_instanced_arrays' ); - } else { + if ( extension === null ) { - _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - } + } - } + var position = geometry.attributes.position; - } + if ( position instanceof THREE.InterleavedBufferAttribute ) { - } + extension.drawArraysInstancedANGLE( mode, 0, position.data.count, geometry.maxInstancedCount ); - if (texture.generateMipmaps && isImagePowerOfTwo) { + } else { - _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP); + extension.drawArraysInstancedANGLE( mode, 0, position.count, geometry.maxInstancedCount ); - } + } - texture.needsUpdate = false; + } - if (texture.onUpdate) texture.onUpdate(texture); + this.setMode = setMode; + this.render = render; + this.renderInstances = renderInstances; - } else { +}; - state.activeTexture(_gl.TEXTURE0 + slot); - state.bindTexture(_gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube); +// File:src/renderers/webgl/WebGLIndexedBufferRenderer.js - } +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } +THREE.WebGLIndexedBufferRenderer = function ( _gl, extensions, _infoRender ) { - } + var mode; - function setCubeTextureDynamic(texture, slot) { + function setMode( value ) { - state.activeTexture(_gl.TEXTURE0 + slot); - state.bindTexture(_gl.TEXTURE_CUBE_MAP, texture.__webglTexture); + mode = value; - } + } - // Render targets + var type, size; - function setupFrameBufferTexture(framebuffer, texture, attachment, textureTarget) { + function setIndex( index ) { - _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); - _gl.framebufferTexture2D(_gl.FRAMEBUFFER, attachment, textureTarget, texture, 0); + if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { - } + type = _gl.UNSIGNED_INT; + size = 4; - function setupRenderBufferStorage(renderbuffer, renderTarget) { + } else { - _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer); + type = _gl.UNSIGNED_SHORT; + size = 2; - if (renderTarget.depthBuffer && !renderTarget.stencilBuffer) { + } - _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height); - _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 ) { + function render( start, count ) { - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - */ - } else if (renderTarget.depthBuffer && renderTarget.stencilBuffer) { + _gl.drawElements( mode, count, type, start * size ); - _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height); - _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer); + _infoRender.calls ++; + _infoRender.vertices += count; + if ( mode === _gl.TRIANGLES ) _infoRender.faces += count / 3; - } else { + } - _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height); + function renderInstances( geometry ) { - } + var extension = extensions.get( 'ANGLE_instanced_arrays' ); - } + if ( extension === null ) { - function setupDepthRenderbuffer(renderTarget) { + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - if (isCube) { + } - renderTarget.__webglRenderbuffer = []; - for (var i = 0; i < 6; i++) { + var index = geometry.index; - renderTarget.__webglRenderbuffer[i] = _gl.createRenderbuffer(); - setupRenderBufferStorage(renderTarget.__webglRenderbuffer[i], renderTarget); + extension.drawElementsInstancedANGLE( mode, index.array.length, type, 0, geometry.maxInstancedCount ); - } + } - } - else { + this.setMode = setMode; + this.setIndex = setIndex; + this.render = render; + this.renderInstances = renderInstances; - if (renderTarget.shareDepthFrom) { +}; - renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; - if (renderTarget.depthBuffer && !renderTarget.stencilBuffer) { +// File:src/renderers/webgl/WebGLExtensions.js - _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer); +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } else if (renderTarget.depthBuffer && renderTarget.stencilBuffer) { +THREE.WebGLExtensions = function ( gl ) { - _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer); + var extensions = {}; - } + this.get = function ( name ) { - } else { + if ( extensions[ name ] !== undefined ) { - renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage(renderTarget.__webglRenderbuffer, renderTarget); + return extensions[ name ]; - } + } - } + var extension; - _gl.bindRenderbuffer(_gl.RENDERBUFFER, null); + switch ( name ) { - }; + 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; - function setupDepthTexture(renderTarget) { + 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; - var depthTexture = renderTarget.depthTexture; - var isPowerOfTwo = THREE.Math.isPowerOfTwo(depthTexture.width) && THREE.Math.isPowerOfTwo(depthTexture.height); + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; - depthTexture.__webglTexture = _gl.createTexture(); - _gl.bindTexture(_gl.TEXTURE_2D, depthTexture.__webglTexture); - setTextureParameters(_gl.TEXTURE_2D, depthTexture, isPowerOfTwo); + default: + extension = gl.getExtension( name ); - if (renderTarget.depthBuffer && !renderTarget.stencilBuffer) { + } - _gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.DEPTH_COMPONENT, depthTexture.width, depthTexture.height, 0, _gl.DEPTH_COMPONENT, _gl.UNSIGNED_INT, null); - _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, depthTexture.__webglTexture, 0); + if ( extension === null ) { - } else if (renderTarget.stencilBuffer) { + console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - _gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.DEPTH_STENCIL, depthTexture.width, depthTexture.height, 0, _gl.DEPTH_STENCIL, extensions.get('WEBGL_depth_texture').UNSIGNED_INT_24_8_WEBGL, null); - _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, depthTexture.__webglTexture, 0); + } - } + extensions[ name ] = extension; - _gl.bindTexture(_gl.TEXTURE_2D, null); + return extension; - }; + }; - this.setRenderTarget = function (renderTarget) { +}; - var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); +// File:src/renderers/webgl/WebGLCapabilities.js - if (renderTarget && renderTarget.__webglFramebuffer === undefined) { +THREE.WebGLCapabilities = function ( gl, extensions, parameters ) { - renderTarget.addEventListener('dispose', onRenderTargetDispose); + function getMaxPrecision( precision ) { - renderTarget.texture.__webglTexture = _gl.createTexture(); + if ( precision === 'highp' ) { - _this.info.memory.textures++; + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { - // - // Setup color buffer - // - var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo(renderTarget.width) && THREE.Math.isPowerOfTwo(renderTarget.height), - glFormat = paramThreeToGL(renderTarget.texture.format), - glType = paramThreeToGL(renderTarget.texture.type); + return 'highp'; - if (isCube) { + } - renderTarget.__webglFramebuffer = []; + precision = 'mediump'; - state.bindTexture(_gl.TEXTURE_CUBE_MAP, renderTarget.texture.__webglTexture); - setTextureParameters(_gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo); + } - for (var i = 0; i < 6; i++) { + if ( precision === 'mediump' ) { - renderTarget.__webglFramebuffer[i] = _gl.createFramebuffer(); + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { - _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null); + return 'mediump'; - setupFrameBufferTexture(renderTarget.__webglFramebuffer[i], renderTarget.texture.__webglTexture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i); + } - } + } - if (renderTarget.generateMipmaps && isTargetPowerOfTwo) _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP); + return 'lowp'; - } else { + } - renderTarget.__webglFramebuffer = _gl.createFramebuffer(); + this.getMaxPrecision = getMaxPrecision; - state.bindTexture(_gl.TEXTURE_2D, renderTarget.texture.__webglTexture); - setTextureParameters(_gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo); + this.precision = parameters.precision !== undefined ? parameters.precision : 'highp', + this.logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false; - _gl.texImage2D(_gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null); + this.maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + this.maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + this.maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); + this.maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - setupFrameBufferTexture(renderTarget.__webglFramebuffer, renderTarget.texture.__webglTexture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D); + this.maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + this.maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); + this.maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); + this.maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); - if (renderTarget.generateMipmaps && isTargetPowerOfTwo) _gl.generateMipmap(_gl.TEXTURE_2D); + this.vertexTextures = this.maxVertexTextures > 0; + this.floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); + this.floatVertexTextures = this.vertexTextures && this.floatFragmentTextures; - } + var _maxPrecision = getMaxPrecision( this.precision ); - // Release textures + if ( _maxPrecision !== this.precision ) { - if (isCube) { + console.warn( 'THREE.WebGLRenderer:', this.precision, 'not supported, using', _maxPrecision, 'instead.' ); + this.precision = _maxPrecision; - state.bindTexture(_gl.TEXTURE_CUBE_MAP, null); + } - } else { + if ( this.logarithmicDepthBuffer ) { - state.bindTexture(_gl.TEXTURE_2D, null); + this.logarithmicDepthBuffer = !! extensions.get( 'EXT_frag_depth' ); - } + } - // - // Setup depth and stencil buffers - // - if (renderTarget.depthBuffer === undefined) renderTarget.depthBuffer = true; - if (renderTarget.stencilBuffer === undefined) renderTarget.stencilBuffer = true; +}; - if (renderTarget.depthBuffer || renderTarget.stencilBuffer) { +// File:src/renderers/webgl/WebGLGeometries.js - if (renderTarget.depthTexture && this.supportsDepthTextures()) setupDepthTexture(renderTarget); - else setupDepthRenderbuffer(renderTarget); +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } +THREE.WebGLGeometries = function ( gl, properties, info ) { - _gl.bindFramebuffer(_gl.FRAMEBUFFER, null); + var geometries = {}; - } + function get( object ) { - var framebuffer, width, height, vx, vy; + var geometry = object.geometry; - if (renderTarget) { + if ( geometries[ geometry.id ] !== undefined ) { - if (isCube) { + return geometries[ geometry.id ]; - framebuffer = renderTarget.__webglFramebuffer[renderTarget.activeCubeFace]; + } - } else { + geometry.addEventListener( 'dispose', onGeometryDispose ); - framebuffer = renderTarget.__webglFramebuffer; + var buffergeometry; - } + if ( geometry instanceof THREE.BufferGeometry ) { - width = renderTarget.width; - height = renderTarget.height; + buffergeometry = geometry; - vx = 0; - vy = 0; + } else if ( geometry instanceof THREE.Geometry ) { - } else { + if ( geometry._bufferGeometry === undefined ) { - framebuffer = null; + geometry._bufferGeometry = new THREE.BufferGeometry().setFromObject( object ); - width = _viewportWidth; - height = _viewportHeight; + } - vx = _viewportX; - vy = _viewportY; + buffergeometry = geometry._bufferGeometry; - } + } - if (framebuffer !== _currentFramebuffer) { + geometries[ geometry.id ] = buffergeometry; - _gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); - _gl.viewport(vx, vy, width, height); + info.memory.geometries ++; - _currentFramebuffer = framebuffer; + return buffergeometry; - } + } - _currentWidth = width; - _currentHeight = height; + function onGeometryDispose( event ) { - }; + var geometry = event.target; + var buffergeometry = geometries[ geometry.id ]; - this.readRenderTargetPixels = function (renderTarget, x, y, width, height, buffer) { + deleteAttributes( buffergeometry.attributes ); - if (!( renderTarget instanceof THREE.WebGLRenderTarget )) { + geometry.removeEventListener( 'dispose', onGeometryDispose ); - THREE.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.'); - return; + delete geometries[ geometry.id ]; - } + var property = properties.get( geometry ); + if ( property.wireframe ) deleteAttribute( property.wireframe ); - if (renderTarget.__webglFramebuffer) { + info.memory.geometries --; - var restore = false; + } - if (renderTarget.__webglFramebuffer !== _currentFramebuffer) { + function getAttributeBuffer( attribute ) { - _gl.bindFramebuffer(_gl.FRAMEBUFFER, renderTarget.__webglFramebuffer); + if ( attribute instanceof THREE.InterleavedBufferAttribute ) { - restore = true; + return properties.get( attribute.data ).__webglBuffer; - } + } - if (renderTarget.texture.format !== THREE.RGBAFormat && paramThreeToGL(renderTarget.texture.format) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_FORMAT)) { + return properties.get( attribute ).__webglBuffer; - THREE.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.'); - return; + } - } + function deleteAttribute( attribute ) { - if (renderTarget.texture.type !== THREE.UnsignedByteType - && paramThreeToGL(renderTarget.texture.type) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_TYPE) - && !(renderTarget.texture.type == THREE.FloatType && _gl.getExtension('WEBGL_color_buffer_float'))) { + var buffer = getAttributeBuffer( attribute ); - THREE.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.'); - return; + if ( buffer !== undefined ) { - } + gl.deleteBuffer( buffer ); + removeAttributeBuffer( attribute ); - if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) === _gl.FRAMEBUFFER_COMPLETE) { + } - _gl.readPixels(x, y, width, height, paramThreeToGL(renderTarget.texture.format), paramThreeToGL(renderTarget.texture.type), buffer); + } - } else { + function deleteAttributes( attributes ) { - console.error('THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.'); + for ( var name in attributes ) { - } + deleteAttribute( attributes[ name ] ); - if (restore) { + } - _gl.bindFramebuffer(_gl.FRAMEBUFFER, _currentFramebuffer); + } - } + function removeAttributeBuffer( attribute ) { - } + if ( attribute instanceof THREE.InterleavedBufferAttribute ) { - }; + properties.delete( attribute.data ); - function updateRenderTargetMipmap(renderTarget) { + } else { - if (renderTarget instanceof THREE.WebGLRenderTargetCube) { + properties.delete( attribute ); - state.bindTexture(_gl.TEXTURE_CUBE_MAP, renderTarget.texture.__webglTexture); - _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP); - state.bindTexture(_gl.TEXTURE_CUBE_MAP, null); + } - } else { + } - state.bindTexture(_gl.TEXTURE_2D, renderTarget.texture.__webglTexture); - _gl.generateMipmap(_gl.TEXTURE_2D); - state.bindTexture(_gl.TEXTURE_2D, null); + this.get = get; - } +}; - } +// File:src/renderers/webgl/WebGLObjects.js - // Fallback filters for non-power-of-2 textures +/** +* @author mrdoob / http://mrdoob.com/ +*/ - function filterFallback(f) { +THREE.WebGLObjects = function ( gl, properties, info ) { - if (f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter) { + var geometries = new THREE.WebGLGeometries( gl, properties, info ); - return _gl.NEAREST; + // - } + function update( object ) { - return _gl.LINEAR; + // TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter. - } + var geometry = geometries.get( object ); - // Map three.js constants to WebGL constants + if ( object.geometry instanceof THREE.Geometry ) { - function paramThreeToGL(p) { + geometry.updateFromObject( object ); - 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; + var index = geometry.index; + var attributes = geometry.attributes; - if (p === THREE.NearestFilter) return _gl.NEAREST; - if (p === THREE.NearestMipMapNearestFilter) return _gl.NEAREST_MIPMAP_NEAREST; - if (p === THREE.NearestMipMapLinearFilter) return _gl.NEAREST_MIPMAP_LINEAR; + if ( index !== null ) { - if (p === THREE.LinearFilter) return _gl.LINEAR; - if (p === THREE.LinearMipMapNearestFilter) return _gl.LINEAR_MIPMAP_NEAREST; - if (p === THREE.LinearMipMapLinearFilter) return _gl.LINEAR_MIPMAP_LINEAR; + updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER ); - if (p === THREE.UnsignedByteType) return _gl.UNSIGNED_BYTE; - if (p === THREE.UnsignedShort4444Type) return _gl.UNSIGNED_SHORT_4_4_4_4; - if (p === THREE.UnsignedShort5551Type) return _gl.UNSIGNED_SHORT_5_5_5_1; - if (p === THREE.UnsignedShort565Type) return _gl.UNSIGNED_SHORT_5_6_5; + } - if (p === THREE.ByteType) return _gl.BYTE; - if (p === THREE.ShortType) return _gl.SHORT; - if (p === THREE.UnsignedShortType) return _gl.UNSIGNED_SHORT; - if (p === THREE.IntType) return _gl.INT; - if (p === THREE.UnsignedIntType) return _gl.UNSIGNED_INT; - if (p === THREE.FloatType) return _gl.FLOAT; + for ( var name in attributes ) { - extension = extensions.get('OES_texture_half_float'); + updateAttribute( attributes[ name ], gl.ARRAY_BUFFER ); - if (extension !== null) { + } - if (p === THREE.HalfFloatType) return extension.HALF_FLOAT_OES; + // morph targets - } + var morphAttributes = geometry.morphAttributes; - if (p === THREE.AlphaFormat) return _gl.ALPHA; - if (p === THREE.RGBFormat) return _gl.RGB; - if (p === THREE.RGBAFormat) return _gl.RGBA; - if (p === THREE.LuminanceFormat) return _gl.LUMINANCE; - if (p === THREE.LuminanceAlphaFormat) return _gl.LUMINANCE_ALPHA; + for ( var name in morphAttributes ) { - if (p === THREE.AddEquation) return _gl.FUNC_ADD; - if (p === THREE.SubtractEquation) return _gl.FUNC_SUBTRACT; - if (p === THREE.ReverseSubtractEquation) return _gl.FUNC_REVERSE_SUBTRACT; + var array = morphAttributes[ name ]; - if (p === THREE.ZeroFactor) return _gl.ZERO; - if (p === THREE.OneFactor) return _gl.ONE; - if (p === THREE.SrcColorFactor) return _gl.SRC_COLOR; - if (p === THREE.OneMinusSrcColorFactor) return _gl.ONE_MINUS_SRC_COLOR; - if (p === THREE.SrcAlphaFactor) return _gl.SRC_ALPHA; - if (p === THREE.OneMinusSrcAlphaFactor) return _gl.ONE_MINUS_SRC_ALPHA; - if (p === THREE.DstAlphaFactor) return _gl.DST_ALPHA; - if (p === THREE.OneMinusDstAlphaFactor) return _gl.ONE_MINUS_DST_ALPHA; + for ( var i = 0, l = array.length; i < l; i ++ ) { - if (p === THREE.DstColorFactor) return _gl.DST_COLOR; - if (p === THREE.OneMinusDstColorFactor) return _gl.ONE_MINUS_DST_COLOR; - if (p === THREE.SrcAlphaSaturateFactor) return _gl.SRC_ALPHA_SATURATE; + updateAttribute( array[ i ], gl.ARRAY_BUFFER ); - 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; + return geometry; - } + } - extension = extensions.get('WEBGL_compressed_texture_pvrtc'); + function updateAttribute( attribute, bufferType ) { - if (extension !== null) { + var data = ( attribute instanceof THREE.InterleavedBufferAttribute ) ? attribute.data : attribute; - 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; + var attributeProperties = properties.get( data ); - } + if ( attributeProperties.__webglBuffer === undefined ) { - extension = extensions.get('EXT_blend_minmax'); + createBuffer( attributeProperties, data, bufferType ); - if (extension !== null) { + } else if ( attributeProperties.version !== data.version ) { - if (p === THREE.MinEquation) return extension.MIN_EXT; - if (p === THREE.MaxEquation) return extension.MAX_EXT; + updateBuffer( attributeProperties, data, bufferType ); - } + } - return 0; + } - } + function createBuffer( attributeProperties, data, bufferType ) { - // Allocations + attributeProperties.__webglBuffer = gl.createBuffer(); + gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); - function allocateBones(object) { + var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; - if (_supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture) { + gl.bufferData( bufferType, data.array, usage ); - return 1024; + attributeProperties.version = data.version; - } else { + } - // default for when object is not specified - // ( for example when prebuilding shader to be used with multiple objects ) - // - // - leave some extra space for other uniforms - // - limit here is ANGLE's 254 max uniform vectors - // (up to 54 should be safe) + function updateBuffer( attributeProperties, data, bufferType ) { - var nVertexUniforms = _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS); - var nVertexMatrices = Math.floor(( nVertexUniforms - 20 ) / 4); + gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); - var maxBones = nVertexMatrices; + if ( data.dynamic === false || data.updateRange.count === - 1 ) { - if (object !== undefined && object instanceof THREE.SkinnedMesh) { + // Not using update ranges - maxBones = Math.min(object.skeleton.bones.length, maxBones); + gl.bufferSubData( bufferType, 0, data.array ); - if (maxBones < object.skeleton.bones.length) { + } else if ( data.updateRange.count === 0 ) { - THREE.warn('WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)'); + console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); - } + } else { - } + gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, + data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) ); - return maxBones; + data.updateRange.count = 0; // reset range - } + } - } + attributeProperties.version = data.version; - function allocateLights(lights) { + } - var dirLights = 0; - var pointLights = 0; - var spotLights = 0; - var hemiLights = 0; + function getAttributeBuffer( attribute ) { - for (var l = 0, ll = lights.length; l < ll; l++) { + if ( attribute instanceof THREE.InterleavedBufferAttribute ) { - var light = lights[l]; + return properties.get( attribute.data ).__webglBuffer; - if (light.onlyShadow || light.visible === false) continue; + } - if (light instanceof THREE.DirectionalLight) dirLights++; - if (light instanceof THREE.PointLight) pointLights++; - if (light instanceof THREE.SpotLight) spotLights++; - if (light instanceof THREE.HemisphereLight) hemiLights++; + return properties.get( attribute ).__webglBuffer; - } + } - return {'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights}; + function getWireframeAttribute( geometry ) { - } + var property = properties.get( geometry ); - function allocateShadows(lights) { + if ( property.wireframe !== undefined ) { - var maxShadows = 0; + return property.wireframe; - for (var l = 0, ll = lights.length; l < ll; l++) { + } - var light = lights[l]; + var indices = []; - if (!light.castShadow) continue; + var index = geometry.index; + var attributes = geometry.attributes; + var position = attributes.position; - if (light instanceof THREE.SpotLight) maxShadows++; - if (light instanceof THREE.DirectionalLight && !light.shadowCascade) maxShadows++; + // console.time( 'wireframe' ); - } + if ( index !== null ) { - return maxShadows; + var edges = {}; + var array = index.array; - } + for ( var i = 0, l = array.length; i < l; i += 3 ) { - // DEPRECATED - - 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.'); - - }; - - Object.defineProperties(this, { - shadowMapEnabled: { - get: function () { - return shadowMap.enabled; - }, - set: function (value) { - THREE.warn('THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.'); - shadowMap.enabled = value; - } - }, - shadowMapType: { - get: function () { - return shadowMap.type; - }, - set: function (value) { - THREE.warn('THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.'); - shadowMap.type = value; - } - }, - shadowMapCullFace: { - get: function () { - return shadowMap.cullFace; - }, - set: function (value) { - THREE.warn('THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.'); - shadowMap.cullFace = value; - } - }, - shadowMapDebug: { - get: function () { - return shadowMap.debug; - }, - set: function (value) { - THREE.warn('THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.'); - shadowMap.debug = value; - } - }, - shadowMapCascade: { - get: function () { - return shadowMap.cascade; - }, - set: function (value) { - THREE.warn('THREE.WebGLRenderer: .shadowMapCascade is now .shadowMap.cascade.'); - shadowMap.cascade = value; - } - } - }); + var a = array[ i + 0 ]; + var b = array[ i + 1 ]; + var c = array[ i + 2 ]; -}; + if ( checkEdge( edges, a, b ) ) indices.push( a, b ); + if ( checkEdge( edges, b, c ) ) indices.push( b, c ); + if ( checkEdge( edges, c, a ) ) indices.push( c, a ); -// File:src/renderers/WebGLRenderTarget.js + } -/** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - */ + } else { -THREE.WebGLRenderTarget = function (width, height, options) { + var array = attributes.position.array; - this.width = width; - this.height = height; + for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - options = options || {}; + var a = i + 0; + var b = i + 1; + var c = i + 2; - this.texture = options.texture; - if (!this.texture) { + indices.push( a, b, b, c, c, a ); - this.texture = { + } - wrapS: options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping, - wrapT: options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping, - magFilter: options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter, - minFilter: options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter, - anisotropy: options.anisotropy !== undefined ? options.anisotropy : 1, - offset: new THREE.Vector2(0, 0), - repeat: new THREE.Vector2(1, 1), - format: options.format !== undefined ? options.format : THREE.RGBAFormat, - type: options.type !== undefined ? options.type : THREE.UnsignedByteType, + } - clone: function () { + // console.timeEnd( 'wireframe' ); - var tmp = {}; - tmp.wrapS = this.wrapS; - tmp.wrapT = this.wrapT; + var TypeArray = position.count > 65535 ? Uint32Array : Uint16Array; + var attribute = new THREE.BufferAttribute( new TypeArray( indices ), 1 ); - tmp.magFilter = this.magFilter; - tmp.minFilter = this.minFilter; + updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); - tmp.anisotropy = this.anisotropy; + property.wireframe = attribute; - tmp.format = this.format; - tmp.type = this.type; + return attribute; - tmp.offset = this.offset.clone(); - tmp.repeat = this.repeat.clone(); + } - return tmp; + function checkEdge( edges, a, b ) { - } + if ( a > b ) { - }; + var tmp = a; + a = b; + b = tmp; - } + } + + var list = edges[ a ]; - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - this.depthTexture = options.depthTexture; + if ( list === undefined ) { - this.generateMipmaps = true; + edges[ a ] = [ b ]; + return true; - this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; + } else if ( list.indexOf( b ) === -1 ) { + + list.push( b ); + return true; + + } + + return false; + + } + + this.getAttributeBuffer = getAttributeBuffer; + this.getWireframeAttribute = getWireframeAttribute; + + this.update = update; }; -THREE.WebGLRenderTarget.prototype = { +// File:src/renderers/webgl/WebGLProgram.js - constructor: THREE.WebGLRenderTarget, +THREE.WebGLProgram = ( function () { - setSize: function (width, height) { + var programIdCount = 0; - if (this.width !== width || this.height !== height) { + function generateDefines( defines ) { - this.width = width; - this.height = height; + var chunks = []; - this.dispose(); + for ( var name in defines ) { - } - }, + var value = defines[ name ]; - clone: function () { + if ( value === false ) continue; - var tmp = new THREE.WebGLRenderTarget(this.width, this.height); + chunks.push( '#define ' + name + ' ' + value ); - tmp.texture = this.texture.clone(); - if (this.depthTexture) tmp.depthTexture = this.depthTexture.clone(); + } - tmp.depthBuffer = this.depthBuffer; - tmp.stencilBuffer = this.stencilBuffer; + return chunks.join( '\n' ); - tmp.generateMipmaps = this.generateMipmaps; + } - tmp.shareDepthFrom = this.shareDepthFrom; + function fetchUniformLocations( gl, program, identifiers ) { - return tmp; + var uniforms = {}; - }, + var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); - dispose: function () { + for ( var i = 0; i < n; i ++ ) { - this.dispatchEvent({type: 'dispose'}); + var info = gl.getActiveUniform( program, i ); + var name = info.name; + var location = gl.getUniformLocation( program, name ); - } + // console.log("THREE.WebGLProgram: ACTIVE UNIFORM:", name); -}; + var suffixPos = name.lastIndexOf( '[0]' ); + if ( suffixPos !== - 1 && suffixPos === name.length - 3 ) { -THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype); + uniforms[ name.substr( 0, suffixPos ) ] = location; -// File:src/renderers/WebGLRenderTargetCube.js + } -/** - * @author alteredq / http://alteredqualia.com - */ + uniforms[ name ] = location; -THREE.WebGLRenderTargetCube = function (width, height, options) { + } - THREE.WebGLRenderTarget.call(this, width, height, options); + return uniforms; - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + } -}; + function fetchAttributeLocations( gl, program, identifiers ) { -THREE.WebGLRenderTargetCube.prototype = Object.create(THREE.WebGLRenderTarget.prototype); -THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; + var attributes = {}; -// File:src/renderers/webgl/WebGLExtensions.js + var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var i = 0; i < n; i ++ ) { -THREE.WebGLExtensions = function (gl) { + var info = gl.getActiveAttrib( program, i ); + var name = info.name; - var extensions = {}; + // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i ); - this.get = function (name) { + attributes[ name ] = gl.getAttribLocation( program, name ); - if (extensions[name] !== undefined) { + } - return extensions[name]; + return attributes; - } + } - var extension; + function filterEmptyLine( string ) { - switch (name) { + return string !== ''; - 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; + } - 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; + return function WebGLProgram( renderer, code, material, parameters ) { - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'); - break; + var gl = renderer.context; - default: - extension = gl.getExtension(name); + var defines = material.defines; - } + var vertexShader = material.__webglShader.vertexShader; + var fragmentShader = material.__webglShader.fragmentShader; - if (extension === null) { + var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - THREE.warn('THREE.WebGLRenderer: ' + name + ' extension not supported.'); + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { - } + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - extensions[name] = extension; + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { - return extension; + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - }; + } -}; + var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; + var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; -// File:src/renderers/webgl/WebGLGeometries.js + if ( parameters.envMap ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + switch ( material.envMap.mapping ) { -THREE.WebGLGeometries = function (gl, info) { + case THREE.CubeReflectionMapping: + case THREE.CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; - var geometries = {}; + case THREE.EquirectangularReflectionMapping: + case THREE.EquirectangularRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; + break; - this.get = function (object) { + case THREE.SphericalReflectionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; + break; - var geometry = object.geometry; + } - if (geometries[geometry.id] !== undefined) { + switch ( material.envMap.mapping ) { - return geometries[geometry.id]; + case THREE.CubeRefractionMapping: + case THREE.EquirectangularRefractionMapping: + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; - } + } - geometry.addEventListener('dispose', onGeometryDispose); + switch ( material.combine ) { - if (geometry instanceof THREE.BufferGeometry) { + case THREE.MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; - geometries[geometry.id] = geometry; + case THREE.MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; - } else { + case THREE.AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; - geometries[geometry.id] = new THREE.BufferGeometry().setFromObject(object); + } - } + } - info.memory.geometries++; + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - return geometries[geometry.id]; + // console.log( 'building new program ' ); - }; + // - function onGeometryDispose(event) { + var customDefines = generateDefines( defines ); - var geometry = event.target; + // - geometry.removeEventListener('dispose', onGeometryDispose); + var program = gl.createProgram(); - geometry = geometries[geometry.id]; + var prefixVertex, prefixFragment; - for (var name in geometry.attributes) { + if ( material instanceof THREE.RawShaderMaterial ) { - var attribute = geometry.attributes[name]; + prefixVertex = ''; + prefixFragment = ''; - if (attribute.buffer !== undefined) { + } else { - gl.deleteBuffer(attribute.buffer); + prefixVertex = [ - delete attribute.buffer; + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - } + '#define SHADER_NAME ' + material.__webglShader.name, - } + customDefines, - info.memory.geometries--; + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - } + renderer.gammaInput ? '#define GAMMA_INPUT' : '', + renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, -}; + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, -// File:src/renderers/webgl/WebGLObjects.js + '#define MAX_SHADOWS ' + parameters.maxShadows, -/** - * @author mrdoob / http://mrdoob.com/ - */ + '#define MAX_BONES ' + parameters.maxBones, -THREE.WebGLObjects = function (gl, info) { + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', - var objects = {}; - var objectsImmediate = []; + parameters.flatShading ? '#define FLAT_SHADED' : '', - var geometries = new THREE.WebGLGeometries(gl, info); + parameters.skinning ? '#define USE_SKINNING' : '', + parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', - var geometryGroups = {}; - var geometryGroupCounter = 0; + parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', + parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - // + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.pointLightShadows > 0 ? '#define POINT_LIGHT_SHADOWS' : '', - function onObjectRemoved(event) { + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - var object = event.target; + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - object.traverse(function (child) { - child.removeEventListener('remove', onObjectRemoved); - removeObject(child); + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', - }); + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', - } + '#ifdef USE_COLOR', - function removeObject(object) { + ' attribute vec3 color;', - if (object instanceof THREE.Mesh || - object instanceof THREE.PointCloud || - object instanceof THREE.Line) { + '#endif', - delete objects[object.id]; + '#ifdef USE_MORPHTARGETS', - } else if (object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback) { + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', - removeInstances(objectsImmediate, object); + ' #ifdef USE_MORPHNORMALS', - } + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', - delete object.__webglInit; - delete object._modelViewMatrix; - delete object._normalMatrix; + ' #else', - delete object.__webglActive; + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', - } + ' #endif', - function removeInstances(objlist, object) { + '#endif', - for (var o = objlist.length - 1; o >= 0; o--) { + '#ifdef USE_SKINNING', - if (objlist[o].object === object) { + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', - objlist.splice(o, 1); + '#endif', - } + '\n' - } + ].filter( filterEmptyLine ).join( '\n' ); - } + prefixFragment = [ - // + parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ? '#extension GL_OES_standard_derivatives : enable' : '', + parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', - this.objects = objects; - this.objectsImmediate = objectsImmediate; + 'precision ' + parameters.precision + ' float;', + 'precision ' + parameters.precision + ' int;', - this.geometries = geometries; + '#define SHADER_NAME ' + material.__webglShader.name, - this.init = function (object) { + customDefines, - if (object.__webglInit === undefined) { + '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, + '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, + '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, + '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, - object.__webglInit = true; - object._modelViewMatrix = new THREE.Matrix4(); - object._normalMatrix = new THREE.Matrix3(); + '#define MAX_SHADOWS ' + parameters.maxShadows, - object.addEventListener('removed', onObjectRemoved); + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', - } + renderer.gammaInput ? '#define GAMMA_INPUT' : '', + renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, - if (object.__webglActive === undefined) { + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', - object.__webglActive = true; + 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.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + 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' : '', - if (object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud) { + parameters.flatShading ? '#define FLAT_SHADED' : '', - objects[object.id] = { - id: object.id, - object: object, - material: null, - z: 0 - }; + parameters.metal ? '#define METAL' : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - } else if (object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback) { + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', + parameters.pointLightShadows > 0 ? '#define POINT_LIGHT_SHADOWS' : '', - objectsImmediate.push({ - id: null, - object: object, - opaque: null, - transparent: null, - z: 0 - }); + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - } + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', - } + '\n' - }; + ].filter( filterEmptyLine ).join( '\n' ); - this.update = function (object) { + } - var geometry = geometries.get(object); + var vertexGlsl = prefixVertex + vertexShader; + var fragmentGlsl = prefixFragment + fragmentShader; - if (object.geometry instanceof THREE.DynamicGeometry) { + var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); + var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); - geometry.updateFromObject(object); + gl.attachShader( program, glVertexShader ); + gl.attachShader( program, glFragmentShader ); - } + // Force a particular attribute to index 0. - geometry.updateFromMaterial(object.material); + if ( material.index0AttributeName !== undefined ) { - // + gl.bindAttribLocation( program, 0, material.index0AttributeName ); - if (geometry instanceof THREE.BufferGeometry) { + } else if ( parameters.morphTargets === true ) { - var attributes = geometry.attributes; - var attributesKeys = geometry.attributesKeys; + // programs with morphTargets displace position out of attribute 0 + gl.bindAttribLocation( program, 0, 'position' ); - for (var i = 0, l = attributesKeys.length; i < l; i++) { + } - var key = attributesKeys[i]; - var attribute = attributes[key]; - var bufferType = ( key === 'index' ) ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER; + gl.linkProgram( program ); - var data = ( attribute instanceof THREE.InterleavedBufferAttribute ) ? attribute.data : attribute; + var programLog = gl.getProgramInfoLog( program ); + var vertexLog = gl.getShaderInfoLog( glVertexShader ); + var fragmentLog = gl.getShaderInfoLog( glFragmentShader ); - if (data.buffer === undefined) { + var runnable = true; + var haveDiagnostics = true; - data.buffer = gl.createBuffer(); - gl.bindBuffer(bufferType, data.buffer); + if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - var usage = gl.STATIC_DRAW; + runnable = false; - if (data instanceof THREE.DynamicBufferAttribute - || ( data instanceof THREE.InstancedBufferAttribute && data.dynamic === true ) - || ( data instanceof THREE.InterleavedBuffer && data.dynamic === true )) { + console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); - usage = gl.DYNAMIC_DRAW; + } else if ( programLog !== '' ) { - } + console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); - gl.bufferData(bufferType, data.array, usage); + } else if ( vertexLog === '' || fragmentLog === '' ) { - data.needsUpdate = false; + haveDiagnostics = false; - } else if (data.needsUpdate === true) { + } - gl.bindBuffer(bufferType, data.buffer); + if ( haveDiagnostics ) { - if (data.updateRange === undefined || data.updateRange.count === -1) { // Not using update ranges + this.diagnostics = { - gl.bufferSubData(bufferType, 0, data.array); + runnable: runnable, + material: material, - } else if (data.updateRange.count === 0) { + programLog: programLog, - THREE.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.'); + vertexShader: { - } else { + log: vertexLog, + prefix: prefixVertex - gl.bufferSubData(bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, - data.array.subarray(data.updateRange.offset, data.updateRange.offset + data.updateRange.count)); + }, - data.updateRange.count = 0; // reset range + fragmentShader: { - } + log: fragmentLog, + prefix: prefixFragment - data.needsUpdate = false; + } - } + }; - } + } - } + // clean up - }; + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); -}; + // set up caching for uniform locations -// File:src/renderers/webgl/WebGLProgram.js + var cachedUniforms; -THREE.WebGLProgram = (function () { + this.getUniforms = function() { - var programIdCount = 0; + if ( cachedUniforms === undefined ) { - function generateDefines(defines) { + cachedUniforms = fetchUniformLocations( gl, program ); - var value, chunk, chunks = []; + } - for (var d in defines) { + return cachedUniforms; - value = defines[d]; - if (value === false) continue; + }; - chunk = '#define ' + d + ' ' + value; - chunks.push(chunk); + // set up caching for attribute locations - } + var cachedAttributes; - return chunks.join('\n'); + this.getAttributes = function() { - } + if ( cachedAttributes === undefined ) { - function cacheUniformLocations(gl, program, identifiers) { + cachedAttributes = fetchAttributeLocations( gl, program ); - var uniforms = {}; + } - for (var i = 0, l = identifiers.length; i < l; i++) { + return cachedAttributes; - var id = identifiers[i]; - uniforms[id] = gl.getUniformLocation(program, id); + }; - } + // free resource - return uniforms; + this.destroy = function() { - } + gl.deleteProgram( program ); + this.program = undefined; - function cacheAttributeLocations(gl, program, identifiers) { + }; - var attributes = {}; + // DEPRECATED - for (var i = 0, l = identifiers.length; i < l; i++) { + Object.defineProperties( this, { - var id = identifiers[i]; - attributes[id] = gl.getAttribLocation(program, id); + uniforms: { + get: function() { - } + console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); + return this.getUniforms(); - return attributes; + } + }, - } + attributes: { + get: function() { - function programArrayToString(previousValue, currentValue, index, array) { + console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); + return this.getAttributes(); - if (currentValue !== '' && currentValue !== undefined && currentValue !== null) { + } + } - return previousValue + currentValue + '\n'; + } ); - } - return previousValue; - } + // - return function (renderer, code, material, parameters) { + this.id = programIdCount ++; + this.code = code; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; - var gl = renderer.context; + return this; - var defines = material.defines; - var uniforms = material.__webglShader.uniforms; - var attributes = material.attributes; + }; - var vertexShader = material.__webglShader.vertexShader; - var fragmentShader = material.__webglShader.fragmentShader; +} )(); - var index0AttributeName = material.index0AttributeName; +// File:src/renderers/webgl/WebGLPrograms.js - if (index0AttributeName === undefined && parameters.morphTargets === true) { +THREE.WebGLPrograms = function ( renderer, capabilities ) { - // programs with morphTargets displace position out of attribute 0 + var programs = []; - index0AttributeName = 'position'; + var shaderIDs = { + MeshDepthMaterial: 'depth', + MeshNormalMaterial: 'normal', + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + LineBasicMaterial: 'basic', + LineDashedMaterial: 'dashed', + PointsMaterial: 'points' + }; - } + var parameterNames = [ + "precision", "supportsVertexTextures", "map", "envMap", "envMapMode", + "lightMap", "aoMap", "emissiveMap", "bumpMap", "normalMap", "specularMap", + "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", + "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", + "maxBones", "useVertexTexture", "morphTargets", "morphNormals", + "maxMorphTargets", "maxMorphNormals", "maxDirLights", "maxPointLights", + "maxSpotLights", "maxHemiLights", "maxShadows", "shadowMapEnabled", "pointLightShadows", + "shadowMapType", "shadowMapDebug", "alphaTest", "metal", "doubleSided", + "flipSided" + ]; - var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - if (parameters.shadowMapType === THREE.PCFShadowMap) { + function allocateBones ( object ) { - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; + if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { - } else if (parameters.shadowMapType === THREE.PCFSoftShadowMap) { + return 1024; - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; + } else { - } + // default for when object is not specified + // ( for example when prebuilding shader to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) - var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + var nVertexUniforms = capabilities.maxVertexUniforms; + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - if (parameters.envMap) { + var maxBones = nVertexMatrices; - switch (material.envMap.mapping) { + if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { - case THREE.CubeReflectionMapping: - case THREE.CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; + maxBones = Math.min( object.skeleton.bones.length, maxBones ); - case THREE.EquirectangularReflectionMapping: - case THREE.EquirectangularRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; - break; + if ( maxBones < object.skeleton.bones.length ) { - case THREE.SphericalReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; - break; + console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); - } + } - switch (material.envMap.mapping) { + } - case THREE.CubeRefractionMapping: - case THREE.EquirectangularRefractionMapping: - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; + return maxBones; - } + } - switch (material.combine) { + } - case THREE.MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; + function allocateLights( lights ) { - case THREE.MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; + var dirLights = 0; + var pointLights = 0; + var spotLights = 0; + var hemiLights = 0; - case THREE.AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - } + var light = lights[ l ]; - } + if ( light.onlyShadow || light.visible === false ) continue; - var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; + if ( light instanceof THREE.DirectionalLight ) dirLights ++; + if ( light instanceof THREE.PointLight ) pointLights ++; + if ( light instanceof THREE.SpotLight ) spotLights ++; + if ( light instanceof THREE.HemisphereLight ) hemiLights ++; - // THREE.log( 'building new program ' ); + } - // + return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights }; - var customDefines = generateDefines(defines); + } - // + function allocateShadows( lights ) { - var program = gl.createProgram(); + var maxShadows = 0; + var pointLightShadows = 0; - var prefix_vertex, prefix_fragment; + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - if (material instanceof THREE.RawShaderMaterial) { + var light = lights[ l ]; - prefix_vertex = ''; - prefix_fragment = ''; + if ( ! light.castShadow ) continue; - } else { + if ( light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) maxShadows ++; + if ( light instanceof THREE.PointLight ) { - prefix_vertex = [ + maxShadows ++; + pointLightShadows ++; - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', + } - customDefines, + } - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', + return { 'maxShadows': maxShadows, 'pointLightShadows': pointLightShadows }; - renderer.gammaInput ? '#define GAMMA_INPUT' : '', - renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', - '#define GAMMA_FACTOR ' + gammaFactorDefine, + } - '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, - '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, - '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, - '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, + this.getParameters = function ( material, lights, fog, object ) { - '#define MAX_SHADOWS ' + parameters.maxShadows, + var shaderID = shaderIDs[ material.type ]; + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) - '#define MAX_BONES ' + parameters.maxBones, + var maxLightCount = allocateLights( lights ); + var allocatedShadows = allocateShadows( lights ); + var maxBones = allocateBones( object ); + var precision = renderer.getPrecision(); - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - 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' : '', + if ( material.precision !== null ) { - parameters.flatShading ? '#define FLAT_SHADED' : '', + precision = capabilities.getMaxPrecision( material.precision ); - parameters.skinning ? '#define USE_SKINNING' : '', - parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', + if ( precision !== material.precision ) { - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals ? '#define USE_MORPHNORMALS' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', + console.warn( 'THREE.WebGLRenderer.initMaterial:', material.precision, 'not supported, using', precision, 'instead.' ); - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', - parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', + } - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + } - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - //renderer.glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', + var parameters = { + shaderID: shaderID, - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', + precision: precision, + supportsVertexTextures: capabilities.vertexTextures, - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', + map: !! material.map, + envMap: !! material.envMap, + envMapMode: material.envMap && material.envMap.mapping, + lightMap: !! material.lightMap, + aoMap: !! material.aoMap, + emissiveMap: !! material.emissiveMap, + bumpMap: !! material.bumpMap, + normalMap: !! material.normalMap, + displacementMap: !! material.displacementMap, + specularMap: !! material.specularMap, + alphaMap: !! material.alphaMap, - '#ifdef USE_COLOR', + combine: material.combine, - ' attribute vec3 color;', + vertexColors: material.vertexColors, - '#endif', + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, - '#ifdef USE_MORPHTARGETS', + flatShading: material.shading === THREE.FlatShading, - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, - ' #ifdef USE_MORPHNORMALS', + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture, - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: renderer.maxMorphTargets, + maxMorphNormals: renderer.maxMorphNormals, - ' #else', + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', + maxShadows: allocatedShadows.maxShadows, + pointLightShadows: allocatedShadows.pointLightShadows, + shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && allocatedShadows.maxShadows > 0, + shadowMapType: renderer.shadowMap.type, + shadowMapDebug: renderer.shadowMap.debug, - ' #endif', + alphaTest: material.alphaTest, + metal: material.metal, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide - '#endif', + }; - '#ifdef USE_SKINNING', + return parameters; - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', + }; - '#endif', + this.getProgramCode = function ( material, parameters ) { - '' + var chunks = []; - ].reduce(programArrayToString, ''); + if ( parameters.shaderID ) { - prefix_fragment = [ + chunks.push( parameters.shaderID ); - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', + } else { - ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', + chunks.push( material.fragmentShader ); + chunks.push( material.vertexShader ); - customDefines, + } - '#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 ( material.defines !== undefined ) { - '#define MAX_SHADOWS ' + parameters.maxShadows, + for ( var name in material.defines ) { - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', + chunks.push( name ); + chunks.push( material.defines[ name ] ); - renderer.gammaInput ? '#define GAMMA_INPUT' : '', - renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', - '#define GAMMA_FACTOR ' + gammaFactorDefine, + } - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', + } - 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.aoMap ? '#define USE_AOMAP' : '', - 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' : '', + for ( var i = 0; i < parameterNames.length; i ++ ) { - parameters.flatShading ? '#define FLAT_SHADED' : '', + var parameterName = parameterNames[ i ]; + chunks.push( parameterName ); + chunks.push( parameters[ parameterName ] ); - parameters.metal ? '#define METAL' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', + } - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', - parameters.shadowMapCascade ? '#define SHADOWMAP_CASCADE' : '', + return chunks.join(); - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - //renderer.glExtensionFragDepth ? '#define USE_LOGDEPTHBUF_EXT' : '', + }; - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - '' + this.acquireProgram = function ( material, parameters, code ) { - ].reduce(programArrayToString, ''); + var program; - } + // Check if code has been already compiled + for ( var p = 0, pl = programs.length; p < pl; p ++ ) { - var glVertexShader = new THREE.WebGLShader(gl, gl.VERTEX_SHADER, prefix_vertex + vertexShader); - var glFragmentShader = new THREE.WebGLShader(gl, gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader); + var programInfo = programs[ p ]; - gl.attachShader(program, glVertexShader); - gl.attachShader(program, glFragmentShader); + if ( programInfo.code === code ) { - if (index0AttributeName !== undefined) { + program = programInfo; + ++ program.usedTimes; - // 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 + break; - gl.bindAttribLocation(program, 0, index0AttributeName); + } - } + } - gl.linkProgram(program); + if ( program === undefined ) { - var programLogInfo = gl.getProgramInfoLog(program); - var vertexErrorLogInfo = gl.getShaderInfoLog(glVertexShader); - var fragmentErrorLogInfo = gl.getShaderInfoLog(glFragmentShader); + program = new THREE.WebGLProgram( renderer, code, material, parameters ); + programs.push( 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, vertexErrorLogInfo, fragmentErrorLogInfo); + return program; - } + }; - if (programLogInfo !== '') { + this.releaseProgram = function( program ) { - THREE.warn('THREE.WebGLProgram: gl.getProgramInfoLog()', programLogInfo); + if ( -- program.usedTimes === 0 ) { - } + // Remove from unordered set + var i = programs.indexOf( program ); + programs[ i ] = programs[ programs.length - 1 ]; + programs.pop(); - // clean up + // Free WebGL resources + program.destroy(); - gl.deleteShader(glVertexShader); - gl.deleteShader(glFragmentShader); + } - // cache uniform locations + }; - var identifiers = [ + // Exposed for resource monitoring & error feedback via renderer.info: + this.programs = programs; - 'viewMatrix', - 'modelViewMatrix', - 'projectionMatrix', - 'normalMatrix', - 'modelMatrix', - 'cameraPosition', - 'morphTargetInfluences', - 'bindMatrix', - 'bindMatrixInverse' +}; - ]; +// File:src/renderers/webgl/WebGLProperties.js - if (parameters.useVertexTexture) { +/** +* @author fordacious / fordacious.github.io +*/ - identifiers.push('boneTexture', 'boneTextureWidth', 'boneTextureHeight'); +THREE.WebGLProperties = function () { - } else { + var properties = {}; - identifiers.push('boneGlobalMatrices'); + this.get = function ( object ) { - } + var uuid = object.uuid; + var map = properties[ uuid ]; - if (parameters.logarithmicDepthBuffer) { + if ( map === undefined ) { - identifiers.push('logDepthBufFC'); + map = {}; + properties[ uuid ] = map; - } + } - for (var u in uniforms) { + return map; - identifiers.push(u); + }; - } + this.delete = function ( object ) { - this.uniforms = cacheUniformLocations(gl, program, identifiers); + delete properties[ object.uuid ]; - // cache attributes locations + }; - identifiers = [ + this.clear = function () { - 'position', - 'normal', - 'uv', - 'uv2', - 'tangent', - 'color', - 'skinIndex', - 'skinWeight', - 'lineDistance' + properties = {}; - ]; + }; - for (var i = 0; i < parameters.maxMorphTargets; i++) { +}; - identifiers.push('morphTarget' + i); +// File:src/renderers/webgl/WebGLShader.js - } +THREE.WebGLShader = ( function () { - for (var i = 0; i < parameters.maxMorphNormals; i++) { + var addLineNumbers = function ( string ) { - identifiers.push('morphNormal' + i); + var lines = string.split( '\n' ); - } + for ( var i = 0; i < lines.length; i ++ ) { - for (var a in attributes) { + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - identifiers.push(a); + } - } + return lines.join( '\n' ); - this.attributes = cacheAttributeLocations(gl, program, identifiers); - this.attributesKeys = Object.keys(this.attributes); + }; - // + return function WebGLShader( gl, type, string ) { - this.id = programIdCount++; - this.code = code; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; + var shader = gl.createShader( type ); - return this; + gl.shaderSource( shader, string ); + gl.compileShader( shader ); - }; + if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { -})(); + console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); -// File:src/renderers/webgl/WebGLShader.js + } -THREE.WebGLShader = (function () { + if ( gl.getShaderInfoLog( shader ) !== '' ) { - var addLineNumbers = function (string) { + console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); - var lines = string.split('\n'); + } - for (var i = 0; i < lines.length; i++) { + // --enable-privileged-webgl-extension + // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - lines[i] = ( i + 1 ) + ': ' + lines[i]; + return shader; - } + }; - return lines.join('\n'); +} )(); - }; +// File:src/renderers/webgl/WebGLShadowMap.js - return function (gl, type, string) { +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - var shader = gl.createShader(type); +THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { - gl.shaderSource(shader, string); - gl.compileShader(shader); + var _gl = _renderer.context, + _state = _renderer.state, + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), - if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === false) { + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), - THREE.error('THREE.WebGLShader: Shader couldn\'t compile.'); + _lookTarget = new THREE.Vector3(), + _lightPositionWorld = new THREE.Vector3(), - } + _renderList = [], - if (gl.getShaderInfoLog(shader) !== '') { + _MorphingFlag = 1, + _SkinningFlag = 2, - THREE.warn('THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog(shader), addLineNumbers(string)); + _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, - } + _depthMaterials = new Array( _NumberOfMaterialVariants ), + _distanceMaterials = new Array( _NumberOfMaterialVariants ); - // --enable-privileged-webgl-extension - // THREE.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + var cubeDirections = [ + new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( - 1, 0, 0 ), new THREE.Vector3( 0, 0, 1 ), + new THREE.Vector3( 0, 0, - 1 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, - 1, 0 ) + ]; - return shader; + var cubeUps = [ + new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), + new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 0, 0, - 1 ) + ]; - }; + var cube2DViewPorts = [ + new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), + new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4() + ]; -})(); + var _vector4 = new THREE.Vector4(); -// File:src/renderers/webgl/WebGLShadowMap.js + // init -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); -THREE.WebGLShadowMap = function (_renderer, _lights, _objects) { + var distanceShader = THREE.ShaderLib[ "distanceRGBA" ]; + var distanceUniforms = THREE.UniformsUtils.clone( distanceShader.uniforms ); - var _gl = _renderer.context, - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(), + for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { - _min = new THREE.Vector3(), - _max = new THREE.Vector3(), + var useMorphing = ( i & _MorphingFlag ) !== 0; + var useSkinning = ( i & _SkinningFlag ) !== 0; - _webglObjects = _objects.objects, - _webglObjectsImmediate = _objects.objectsImmediate, - _matrixPosition = new THREE.Vector3(), + var depthMaterial = new THREE.ShaderMaterial( { + uniforms: depthUniforms, + vertexShader: depthShader.vertexShader, + fragmentShader: depthShader.fragmentShader, + morphTargets: useMorphing, + skinning: useSkinning + } ); - _renderList = []; + depthMaterial._shadowPass = true; - // init + _depthMaterials[ i ] = depthMaterial; - var depthShader = THREE.ShaderLib["depthRGBA"]; - var depthUniforms = THREE.UniformsUtils.clone(depthShader.uniforms); + var distanceMaterial = new THREE.ShaderMaterial( { + uniforms: distanceUniforms, + vertexShader: distanceShader.vertexShader, + fragmentShader: distanceShader.fragmentShader, + morphTargets: useMorphing, + skinning: useSkinning + } ); - var _depthMaterial = new THREE.ShaderMaterial({ - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader - }); + distanceMaterial._shadowPass = true; - var _depthMaterialMorph = new THREE.ShaderMaterial({ - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - morphTargets: true - }); + _distanceMaterials[ i ] = distanceMaterial; - var _depthMaterialSkin = new THREE.ShaderMaterial({ - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - skinning: true - }); + } - var _depthMaterialMorphSkin = new THREE.ShaderMaterial({ - uniforms: depthUniforms, - vertexShader: depthShader.vertexShader, - fragmentShader: depthShader.fragmentShader, - morphTargets: true, - skinning: true - }); + // - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; + var scope = this; - // + this.enabled = false; - var scope = this; + this.autoUpdate = true; + this.needsUpdate = false; - this.enabled = false; - this.type = THREE.PCFShadowMap; - this.cullFace = THREE.CullFaceFront; - this.debug = false; - this.cascade = false; + this.type = THREE.PCFShadowMap; + this.cullFace = THREE.CullFaceFront; - this.render = function (scene, camera) { + this.render = function ( scene ) { - if (scope.enabled === false) return; + var faceCount, isPointLight; - var i, il, j, jl, n, + if ( scope.enabled === false ) return; + if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - shadowMap, shadowMatrix, shadowCamera, - buffer, material, - webglObject, object, light, + // set GL state for depth map - lights = [], - k = 0, + _gl.clearColor( 1, 1, 1, 1 ); + _state.disable( _gl.BLEND ); - fog = null; + _state.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); - // set GL state for depth map + if ( scope.cullFace === THREE.CullFaceFront ) { - _gl.clearColor(1, 1, 1, 1); - _gl.disable(_gl.BLEND); + _gl.cullFace( _gl.FRONT ); - _gl.enable(_gl.CULL_FACE); - _gl.frontFace(_gl.CCW); + } else { - if (scope.cullFace === THREE.CullFaceFront) { + _gl.cullFace( _gl.BACK ); - _gl.cullFace(_gl.FRONT); + } - } else { + _state.setDepthTest( true ); - _gl.cullFace(_gl.BACK); + // render depth map - } + for ( var i = 0, il = _lights.length; i < il; i ++ ) { - _renderer.state.setDepthTest(true); + var light = _lights[ i ]; - // preprocess lights - // - skip lights that are not casting shadows - // - create virtual lights for cascaded shadow maps + if ( light instanceof THREE.PointLight ) { - for (i = 0, il = _lights.length; i < il; i++) { + faceCount = 6; + isPointLight = true; - light = _lights[i]; + var vpWidth = light.shadowMapWidth / 4.0; + var vpHeight = light.shadowMapHeight / 2.0; - if (!light.castShadow) continue; + // These viewports map a cube-map onto a 2D texture with the + // following orientation: + // + // xzXZ + // y Y + // + // X - Positive x direction + // x - Negative x direction + // Y - Positive y direction + // y - Negative y direction + // Z - Positive z direction + // z - Negative z direction - if (( light instanceof THREE.DirectionalLight ) && light.shadowCascade) { + // positive X + cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); + // negative X + cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); + // positive Z + cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); + // negative Z + cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); + // positive Y + cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); + // negative Y + cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); - for (n = 0; n < light.shadowCascadeCount; n++) { + } else { - var virtualLight; + faceCount = 1; + isPointLight = false; - if (!light.shadowCascadeArray[n]) { + } - virtualLight = createVirtualLight(light, n); - virtualLight.originalCamera = camera; + if ( ! light.castShadow ) continue; - var gyro = new THREE.Gyroscope(); - gyro.position.copy(light.shadowCascadeOffset); + if ( ! light.shadowMap ) { - gyro.add(virtualLight); - gyro.add(virtualLight.target); + var shadowFilter = THREE.LinearFilter; - camera.add(gyro); + if ( scope.type === THREE.PCFSoftShadowMap ) { - light.shadowCascadeArray[n] = virtualLight; + shadowFilter = THREE.NearestFilter; - //THREE.log( "Created virtualLight", virtualLight ); + } - } else { + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; - virtualLight = light.shadowCascadeArray[n]; + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); - } + light.shadowMatrix = new THREE.Matrix4(); - updateVirtualLight(light, n); + } - lights[k] = virtualLight; - k++; + if ( ! light.shadowCamera ) { - } + if ( light instanceof THREE.SpotLight ) { - } else { + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); - lights[k] = light; - k++; + } else if ( light instanceof THREE.DirectionalLight ) { - } + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); - } + } else { - // render depth map + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, 1.0, light.shadowCameraNear, light.shadowCameraFar ); - for (i = 0, il = lights.length; i < il; i++) { + } - light = lights[i]; + scene.add( light.shadowCamera ); - if (!light.shadowMap) { + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - var shadowFilter = THREE.LinearFilter; + } - if (scope.type === THREE.PCFSoftShadowMap) { + if ( light.shadowCameraVisible && ! light.cameraHelper ) { - shadowFilter = THREE.NearestFilter; + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + scene.add( light.cameraHelper ); - } + } - var pars = {minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat}; + var shadowMap = light.shadowMap; + var shadowMatrix = light.shadowMatrix; + var shadowCamera = light.shadowCamera; - light.shadowMap = new THREE.WebGLRenderTarget(light.shadowMapWidth, light.shadowMapHeight, pars); - light.shadowMapSize = new THREE.Vector2(light.shadowMapWidth, light.shadowMapHeight); + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld ); - light.shadowMatrix = new THREE.Matrix4(); + // save the existing viewport so it can be restored later + _renderer.getViewport( _vector4 ); - } + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); - if (!light.shadowCamera) { + // render shadow map for each cube face (if omni-directional) or + // run a single pass if not - if (light instanceof THREE.SpotLight) { + for ( var face = 0; face < faceCount; face ++ ) { - light.shadowCamera = new THREE.PerspectiveCamera(light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar); + if ( isPointLight ) { - } else if (light instanceof THREE.DirectionalLight) { + _lookTarget.copy( shadowCamera.position ); + _lookTarget.add( cubeDirections[ face ] ); + shadowCamera.up.copy( cubeUps[ face ] ); + shadowCamera.lookAt( _lookTarget ); + var vpDimensions = cube2DViewPorts[ face ]; + _renderer.setViewport( vpDimensions.x, vpDimensions.y, vpDimensions.z, vpDimensions.w ); - light.shadowCamera = new THREE.OrthographicCamera(light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar); + } else { - } else { + _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget ); - THREE.error("THREE.ShadowMapPlugin: Unsupported light type for shadow", light); - continue; + } - } + shadowCamera.updateMatrixWorld(); + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); - scene.add(light.shadowCamera); + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); - if (scene.autoUpdate === true) scene.updateMatrixWorld(); + // compute shadow matrix - } + 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 + ); - if (light.shadowCameraVisible && !light.cameraHelper) { + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - light.cameraHelper = new THREE.CameraHelper(light.shadowCamera); - scene.add(light.cameraHelper); + // update camera matrices and frustum - } + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - if (light.isVirtual && virtualLight.originalCamera == camera) { + // set object matrices & frustum culling - updateShadowCamera(camera, light); + _renderList.length = 0; - } + projectObject( scene, shadowCamera ); - shadowMap = light.shadowMap; - shadowMatrix = light.shadowMatrix; - shadowCamera = light.shadowCamera; + // render shadow map + // render regular objects - // + for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { - shadowCamera.position.setFromMatrixPosition(light.matrixWorld); - _matrixPosition.setFromMatrixPosition(light.target.matrixWorld); - shadowCamera.lookAt(_matrixPosition); - shadowCamera.updateMatrixWorld(); + var object = _renderList[ j ]; + var geometry = _objects.update( object ); + var material = object.material; - shadowCamera.matrixWorldInverse.getInverse(shadowCamera.matrixWorld); + if ( material instanceof THREE.MeshFaceMaterial ) { - // + var groups = geometry.groups; + var materials = material.materials; - if (light.cameraHelper) light.cameraHelper.visible = light.shadowCameraVisible; - if (light.shadowCameraVisible) light.cameraHelper.update(); + for ( var k = 0, kl = groups.length; k < kl; k ++ ) { - // compute shadow matrix + var group = groups[ k ]; + var groupMaterial = materials[ group.materialIndex ]; - 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 - ); + if ( groupMaterial.visible === true ) { - shadowMatrix.multiply(shadowCamera.projectionMatrix); - shadowMatrix.multiply(shadowCamera.matrixWorldInverse); + var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, group ); - // update camera matrices and frustum + } - _projScreenMatrix.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse); - _frustum.setFromMatrix(_projScreenMatrix); + } - // render shadow map + } else { - _renderer.setRenderTarget(shadowMap); - _renderer.clear(); + var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); + _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, null ); - // set object matrices & frustum culling + } - _renderList.length = 0; + } - projectObject(scene, scene, shadowCamera); + } + } - // render regular objects + // restore GL state - var objectMaterial, useMorphing, useSkinning; + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); - for (j = 0, jl = _renderList.length; j < jl; j++) { + _renderer.setClearColor( clearColor, clearAlpha ); + _state.enable( _gl.BLEND ); - webglObject = _renderList[j]; + if ( scope.cullFace === THREE.CullFaceFront ) { - object = webglObject.object; - buffer = webglObject.buffer; + _gl.cullFace( _gl.BACK ); - // culling is overriden globally for all objects - // while rendering depth map + } - // 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) + _renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w ); - objectMaterial = getObjectMaterial(object); + _renderer.resetGLState(); - useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + scope.needsUpdate = false; - if (object.customDepthMaterial) { + }; - material = object.customDepthMaterial; + function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) { - } else if (useSkinning) { + var geometry = object.geometry; - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + var newMaterial = null; - } else if (useMorphing) { + var materialVariants = _depthMaterials; + var customMaterial = object.customDepthMaterial; - material = _depthMaterialMorph; + if ( isPointLight ) { - } else { + materialVariants = _distanceMaterials; + customMaterial = object.customDistanceMaterial; - material = _depthMaterial; + } - } + if ( ! customMaterial ) { - _renderer.setMaterialFaces(objectMaterial); + var useMorphing = geometry.morphTargets !== undefined && + geometry.morphTargets.length > 0 && material.morphTargets; - if (buffer instanceof THREE.BufferGeometry) { + var useSkinning = object instanceof THREE.SkinnedMesh && material.skinning; - _renderer.renderBufferDirect(shadowCamera, _lights, fog, material, buffer, object); + var variantIndex = 0; - } else { + if ( useMorphing ) variantIndex |= _MorphingFlag; + if ( useSkinning ) variantIndex |= _SkinningFlag; - _renderer.renderBuffer(shadowCamera, _lights, fog, material, buffer, object); + newMaterial = materialVariants[ variantIndex ]; - } + } else { - } + newMaterial = customMaterial; - // set matrices and render immediate objects + } - for (j = 0, jl = _webglObjectsImmediate.length; j < jl; j++) { + newMaterial.visible = material.visible; + newMaterial.wireframe = material.wireframe; + newMaterial.wireframeLinewidth = material.wireframeLinewidth; - webglObject = _webglObjectsImmediate[j]; - object = webglObject.object; + if ( isPointLight && newMaterial.uniforms.lightPos !== undefined ) { - if (object.visible && object.castShadow) { + newMaterial.uniforms.lightPos.value.copy( lightPositionWorld ); - object._modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld); + } - _renderer.renderImmediateObject(shadowCamera, _lights, fog, _depthMaterial, object); + return newMaterial; - } + } - } + function projectObject( object, camera ) { - } + if ( object.visible === false ) return; - // restore GL state + if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); + if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { - _gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearAlpha); - _gl.enable(_gl.BLEND); + var material = object.material; - if (scope.cullFace === THREE.CullFaceFront) { + if ( material.visible === true ) { - _gl.cullFace(_gl.BACK); + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + _renderList.push( object ); - } + } - _renderer.resetGLState(); + } - }; + } - function projectObject(scene, object, shadowCamera) { + var children = object.children; - if (object.visible) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - var webglObjects = _webglObjects[object.id]; + projectObject( children[ i ], camera ); - if (webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject(object) === true)) { + } - for (var i = 0, l = webglObjects.length; i < l; i++) { + } - var webglObject = webglObjects[i]; +}; - object._modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld); - _renderList.push(webglObject); +// File:src/renderers/webgl/WebGLState.js - } +/** +* @author mrdoob / http://mrdoob.com/ +*/ - } +THREE.WebGLState = function ( gl, extensions, paramThreeToGL ) { - for (var i = 0, l = object.children.length; i < l; i++) { + var _this = this; - projectObject(scene, object.children[i], shadowCamera); + var newAttributes = new Uint8Array( 16 ); + var enabledAttributes = new Uint8Array( 16 ); + var attributeDivisors = new Uint8Array( 16 ); - } + var capabilities = {}; - } + var compressedTextureFormats = null; - } + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; - function createVirtualLight(light, cascade) { + var currentDepthFunc = null; + var currentDepthWrite = null; - var virtualLight = new THREE.DirectionalLight(); + var currentColorWrite = null; - virtualLight.isVirtual = true; + var currentFlipSided = null; - virtualLight.onlyShadow = true; - virtualLight.castShadow = true; + var currentLineWidth = null; - virtualLight.shadowCameraNear = light.shadowCameraNear; - virtualLight.shadowCameraFar = light.shadowCameraFar; + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; - virtualLight.shadowCameraLeft = light.shadowCameraLeft; - virtualLight.shadowCameraRight = light.shadowCameraRight; - virtualLight.shadowCameraBottom = light.shadowCameraBottom; - virtualLight.shadowCameraTop = light.shadowCameraTop; + var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); - virtualLight.shadowCameraVisible = light.shadowCameraVisible; + var currentTextureSlot = undefined; + var currentBoundTextures = {}; - virtualLight.shadowDarkness = light.shadowDarkness; + this.init = function () { - virtualLight.shadowBias = light.shadowCascadeBias[cascade]; - virtualLight.shadowMapWidth = light.shadowCascadeWidth[cascade]; - virtualLight.shadowMapHeight = light.shadowCascadeHeight[cascade]; + gl.clearColor( 0, 0, 0, 1 ); + gl.clearDepth( 1 ); + gl.clearStencil( 0 ); - virtualLight.pointsWorld = []; - virtualLight.pointsFrustum = []; + this.enable( gl.DEPTH_TEST ); + gl.depthFunc( gl.LEQUAL ); - var pointsWorld = virtualLight.pointsWorld, - pointsFrustum = virtualLight.pointsFrustum; + gl.frontFace( gl.CCW ); + gl.cullFace( gl.BACK ); + this.enable( gl.CULL_FACE ); - for (var i = 0; i < 8; i++) { + this.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA ); - pointsWorld[i] = new THREE.Vector3(); - pointsFrustum[i] = new THREE.Vector3(); + }; - } + this.initAttributes = function () { - var nearZ = light.shadowCascadeNearZ[cascade]; - var farZ = light.shadowCascadeFarZ[cascade]; + for ( var i = 0, l = newAttributes.length; i < l; 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); + newAttributes[ i ] = 0; - pointsFrustum[4].set(-1, -1, farZ); - pointsFrustum[5].set(1, -1, farZ); - pointsFrustum[6].set(-1, 1, farZ); - pointsFrustum[7].set(1, 1, farZ); + } - return virtualLight; + }; - } + this.enableAttribute = function ( attribute ) { - // Synchronize virtual light with the original light + newAttributes[ attribute ] = 1; - function updateVirtualLight(light, cascade) { + if ( enabledAttributes[ attribute ] === 0 ) { - var virtualLight = light.shadowCascadeArray[cascade]; + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - virtualLight.position.copy(light.position); - virtualLight.target.position.copy(light.target.position); - virtualLight.lookAt(virtualLight.target); + } - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - virtualLight.shadowDarkness = light.shadowDarkness; + if ( attributeDivisors[ attribute ] !== 0 ) { - virtualLight.shadowBias = light.shadowCascadeBias[cascade]; + var extension = extensions.get( 'ANGLE_instanced_arrays' ); - var nearZ = light.shadowCascadeNearZ[cascade]; - var farZ = light.shadowCascadeFarZ[cascade]; + extension.vertexAttribDivisorANGLE( attribute, 0 ); + attributeDivisors[ attribute ] = 0; - 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; + this.enableAttributeAndDivisor = function ( attribute, meshPerAttribute, extension ) { - } + newAttributes[ attribute ] = 1; - // Fit shadow camera's ortho frustum to camera frustum + if ( enabledAttributes[ attribute ] === 0 ) { - function updateShadowCamera(camera, light) { + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - var shadowCamera = light.shadowCamera, - pointsFrustum = light.pointsFrustum, - pointsWorld = light.pointsWorld; + } - _min.set(Infinity, Infinity, Infinity); - _max.set(-Infinity, -Infinity, -Infinity); + if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - for (var i = 0; i < 8; i++) { + extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); + attributeDivisors[ attribute ] = meshPerAttribute; - var p = pointsWorld[i]; + } - p.copy(pointsFrustum[i]); - p.unproject(camera); + }; - p.applyMatrix4(shadowCamera.matrixWorldInverse); + this.disableUnusedAttributes = function () { - if (p.x < _min.x) _min.x = p.x; - if (p.x > _max.x) _max.x = p.x; + for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { - if (p.y < _min.y) _min.y = p.y; - if (p.y > _max.y) _max.y = p.y; + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - if (p.z < _min.z) _min.z = p.z; - if (p.z > _max.z) _max.z = p.z; + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; - } + } - shadowCamera.left = _min.x; - shadowCamera.right = _max.x; - shadowCamera.top = _max.y; - shadowCamera.bottom = _min.y; + } - // can't really fit near/far - //shadowCamera.near = _min.z; - //shadowCamera.far = _max.z; + }; - shadowCamera.updateProjectionMatrix(); + this.enable = function ( id ) { - } + if ( capabilities[ id ] !== true ) { - // 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 + gl.enable( id ); + capabilities[ id ] = true; - function getObjectMaterial(object) { + } - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[0] - : object.material; + }; - } + this.disable = function ( id ) { -}; + if ( capabilities[ id ] !== false ) { -// File:src/renderers/webgl/WebGLState.js + gl.disable( id ); + capabilities[ id ] = false; -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -THREE.WebGLState = function (gl, paramThreeToGL) { + }; - var _this = this; + this.getCompressedTextureFormats = function () { - var newAttributes = new Uint8Array(16); - var enabledAttributes = new Uint8Array(16); + if ( compressedTextureFormats === null ) { - var currentBlending = null; - var currentBlendEquation = null; - var currentBlendSrc = null; - var currentBlendDst = null; - var currentBlendEquationAlpha = null; - var currentBlendSrcAlpha = null; - var currentBlendDstAlpha = null; + compressedTextureFormats = []; - var currentDepthFunc = null; - var currentDepthTest = null; - var currentDepthWrite = null; + if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || + extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { - var currentColorWrite = null; + var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); - var currentDoubleSided = null; - var currentFlipSided = null; + for ( var i = 0; i < formats.length; i ++ ) { - var currentLineWidth = null; + compressedTextureFormats.push( formats[ i ] ); - var currentPolygonOffset = null; - var currentPolygonOffsetFactor = null; - var currentPolygonOffsetUnits = null; + } - var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); + } - var currentTextureSlot = undefined; - var currentBoundTextures = {}; + } - this.initAttributes = function () { + return compressedTextureFormats; - for (var i = 0, l = newAttributes.length; i < l; i++) { + }; - newAttributes[i] = 0; + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - } + if ( blending !== currentBlending ) { - }; + if ( blending === THREE.NoBlending ) { - this.enableAttribute = function (attribute) { + this.disable( gl.BLEND ); - newAttributes[attribute] = 1; + } else if ( blending === THREE.AdditiveBlending ) { - if (enabledAttributes[attribute] === 0) { + this.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); - gl.enableVertexAttribArray(attribute); - enabledAttributes[attribute] = 1; + } else if ( blending === THREE.SubtractiveBlending ) { - } + // TODO: Find blendFuncSeparate() combination - }; + this.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); - this.disableUnusedAttributes = function () { + } else if ( blending === THREE.MultiplyBlending ) { - for (var i = 0, l = enabledAttributes.length; i < l; i++) { + // TODO: Find blendFuncSeparate() combination - if (enabledAttributes[i] !== newAttributes[i]) { + this.enable( gl.BLEND ); + gl.blendEquation( gl.FUNC_ADD ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); - gl.disableVertexAttribArray(i); - enabledAttributes[i] = 0; + } else if ( blending === THREE.CustomBlending ) { - } + this.enable( gl.BLEND ); - } + } else { - }; + this.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 ); - this.setBlending = function (blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha) { + } - if (blending !== currentBlending) { + currentBlending = blending; - if (blending === THREE.NoBlending) { + } - gl.disable(gl.BLEND); + if ( blending === THREE.CustomBlending ) { - } else if (blending === THREE.AdditiveBlending) { + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - gl.enable(gl.BLEND); - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE); + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - } else if (blending === THREE.SubtractiveBlending) { + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - // TODO: Find blendFuncSeparate() combination - gl.enable(gl.BLEND); - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR); + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; - } else if (blending === THREE.MultiplyBlending) { + } - // TODO: Find blendFuncSeparate() combination - gl.enable(gl.BLEND); - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.ZERO, gl.SRC_COLOR); + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - } else if (blending === THREE.CustomBlending) { + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - gl.enable(gl.BLEND); + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; - } else { + } - 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); + } else { - } + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - currentBlending = blending; + } - } + }; - if (blending === THREE.CustomBlending) { + this.setDepthFunc = function ( depthFunc ) { - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; + if ( currentDepthFunc !== depthFunc ) { - if (blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha) { + if ( depthFunc ) { - gl.blendEquationSeparate(paramThreeToGL(blendEquation), paramThreeToGL(blendEquationAlpha)); + switch ( depthFunc ) { - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; + case THREE.NeverDepth: - } + gl.depthFunc( gl.NEVER ); + break; - if (blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha) { + case THREE.AlwaysDepth: - gl.blendFuncSeparate(paramThreeToGL(blendSrc), paramThreeToGL(blendDst), paramThreeToGL(blendSrcAlpha), paramThreeToGL(blendDstAlpha)); + gl.depthFunc( gl.ALWAYS ); + break; - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; + case THREE.LessDepth: - } + gl.depthFunc( gl.LESS ); + break; - } else { + case THREE.LessEqualDepth: - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; + gl.depthFunc( gl.LEQUAL ); + break; - } + case THREE.EqualDepth: - }; + gl.depthFunc( gl.EQUAL ); + break; - this.setDepthFunc = function (depthFunc) { + case THREE.GreaterEqualDepth: - if (currentDepthFunc !== depthFunc) { + gl.depthFunc( gl.GEQUAL ); + break; - if (depthFunc) { + case THREE.GreaterDepth: - switch (depthFunc) { + gl.depthFunc( gl.GREATER ); + break; - case THREE.NeverDepth: + case THREE.NotEqualDepth: - gl.depthFunc(gl.NEVER); - break; + gl.depthFunc( gl.NOTEQUAL ); + break; - case THREE.AlwaysDepth: + default: - gl.depthFunc(gl.ALWAYS); - break; + gl.depthFunc( gl.LEQUAL ); - case THREE.LessDepth: + } - gl.depthFunc(gl.LESS); - break; + } else { - case THREE.LessEqualDepth: + gl.depthFunc( gl.LEQUAL ); - gl.depthFunc(gl.LEQUAL); - break; + } - case THREE.EqualDepth: + currentDepthFunc = depthFunc; - gl.depthFunc(gl.EQUAL); - break; + } - case THREE.GreaterEqualDepth: + }; - gl.depthFunc(gl.GEQUAL); - break; + this.setDepthTest = function ( depthTest ) { - case THREE.GreaterDepth: + if ( depthTest ) { - gl.depthFunc(gl.GREATER); - break; + this.enable( gl.DEPTH_TEST ); - case THREE.NotEqualDepth: + } else { - gl.depthFunc(gl.NOTEQUAL); - break; + this.disable( gl.DEPTH_TEST ); - default: + } - gl.depthFunc(gl.LEQUAL); - } + }; - } else { + this.setDepthWrite = function ( depthWrite ) { - gl.depthFunc(gl.LEQUAL); + if ( currentDepthWrite !== depthWrite ) { - } + gl.depthMask( depthWrite ); + currentDepthWrite = depthWrite; - currentDepthFunc = depthFunc; + } - } + }; - }; + this.setColorWrite = function ( colorWrite ) { - this.setDepthTest = function (depthTest) { + if ( currentColorWrite !== colorWrite ) { - if (currentDepthTest !== depthTest) { + gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); + currentColorWrite = colorWrite; - if (depthTest) { + } - gl.enable(gl.DEPTH_TEST); + }; - } else { + this.setFlipSided = function ( flipSided ) { - gl.disable(gl.DEPTH_TEST); + if ( currentFlipSided !== flipSided ) { - } + if ( flipSided ) { - currentDepthTest = depthTest; + gl.frontFace( gl.CW ); - } + } else { - }; + gl.frontFace( gl.CCW ); - this.setDepthWrite = function (depthWrite) { + } - if (currentDepthWrite !== depthWrite) { + currentFlipSided = flipSided; - gl.depthMask(depthWrite); - currentDepthWrite = depthWrite; + } - } + }; - }; + this.setLineWidth = function ( width ) { - this.setColorWrite = function (colorWrite) { + if ( width !== currentLineWidth ) { - if (currentColorWrite !== colorWrite) { + gl.lineWidth( width ); - gl.colorMask(colorWrite, colorWrite, colorWrite, colorWrite); - currentColorWrite = colorWrite; + currentLineWidth = width; - } + } - }; + }; - this.setDoubleSided = function (doubleSided) { + this.setPolygonOffset = function ( polygonOffset, factor, units ) { - if (currentDoubleSided !== doubleSided) { + if ( polygonOffset ) { - if (doubleSided) { + this.enable( gl.POLYGON_OFFSET_FILL ); - gl.disable(gl.CULL_FACE); + } else { - } else { + this.disable( gl.POLYGON_OFFSET_FILL ); - gl.enable(gl.CULL_FACE); + } - } + if ( polygonOffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { - currentDoubleSided = doubleSided; + gl.polygonOffset( factor, units ); - } + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; - }; + } - this.setFlipSided = function (flipSided) { + }; - if (currentFlipSided !== flipSided) { + this.setScissorTest = function ( scissorTest ) { - if (flipSided) { + if ( scissorTest ) { - gl.frontFace(gl.CW); + this.enable( gl.SCISSOR_TEST ); - } else { + } else { - gl.frontFace(gl.CCW); + this.disable( gl.SCISSOR_TEST ); - } + } - currentFlipSided = flipSided; + }; - } + // texture - }; + this.activeTexture = function ( webglSlot ) { - this.setLineWidth = function (width) { + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; - if (width !== currentLineWidth) { + if ( currentTextureSlot !== webglSlot ) { - gl.lineWidth(width); + gl.activeTexture( webglSlot ); + currentTextureSlot = webglSlot; - currentLineWidth = width; + } - } + } - }; + this.bindTexture = function ( webglType, webglTexture ) { - this.setPolygonOffset = function (polygonoffset, factor, units) { + if ( currentTextureSlot === undefined ) { - if (currentPolygonOffset !== polygonoffset) { + _this.activeTexture(); - if (polygonoffset) { + } - gl.enable(gl.POLYGON_OFFSET_FILL); + var boundTexture = currentBoundTextures[ currentTextureSlot ]; - } else { + if ( boundTexture === undefined ) { - gl.disable(gl.POLYGON_OFFSET_FILL); + boundTexture = { type: undefined, texture: undefined }; + currentBoundTextures[ currentTextureSlot ] = boundTexture; - } + } - currentPolygonOffset = polygonoffset; + if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - } + gl.bindTexture( webglType, webglTexture ); - if (polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units )) { + boundTexture.type = webglType; + boundTexture.texture = webglTexture; - gl.polygonOffset(factor, units); + } - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; + }; - } + this.compressedTexImage2D = function () { - }; + try { - this.activeTexture = function (webglSlot) { + gl.compressedTexImage2D.apply( gl, arguments ); - if (webglSlot === undefined) webglSlot = gl.TEXTURE0 + maxTextures - 1; + } catch ( error ) { - if (currentTextureSlot !== webglSlot) { + console.error( error ); - gl.activeTexture(webglSlot); - currentTextureSlot = webglSlot; + } - } + }; - } + this.texImage2D = function () { - this.bindTexture = function (webglType, webglTexture) { + try { - if (currentTextureSlot === undefined) { + gl.texImage2D.apply( gl, arguments ); - _this.activeTexture(); + } catch ( error ) { - } + console.error( error ); - var boundTexture = currentBoundTextures[currentTextureSlot]; + } - if (boundTexture === undefined) { + }; - boundTexture = {type: undefined, texture: undefined}; - currentBoundTextures[currentTextureSlot] = boundTexture; + // - } + this.reset = function () { - if (boundTexture.type !== webglType || boundTexture.texture !== webglTexture) { + for ( var i = 0; i < enabledAttributes.length; i ++ ) { - gl.bindTexture(webglType, webglTexture); + if ( enabledAttributes[ i ] === 1 ) { - boundTexture.type = webglType; - boundTexture.texture = webglTexture; + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; - } + } - } + } - this.reset = function () { + capabilities = {}; - for (var i = 0; i < enabledAttributes.length; i++) { + compressedTextureFormats = null; - enabledAttributes[i] = 0; + currentBlending = null; - } + currentDepthWrite = null; + currentColorWrite = null; - currentBlending = null; - currentDepthTest = null; - currentDepthWrite = null; - currentColorWrite = null; - currentDoubleSided = null; - currentFlipSided = null; + currentFlipSided = null; - }; + }; }; @@ -25238,470 +27626,473 @@ THREE.WebGLState = function (gl, paramThreeToGL) { * @author alteredq / http://alteredqualia.com/ */ -THREE.LensFlarePlugin = function (renderer, flares) { +THREE.LensFlarePlugin = function ( renderer, flares ) { - var gl = renderer.context; + var gl = renderer.context; + var state = renderer.state; - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; - var hasVertexTexture; + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; + var hasVertexTexture; - var tempTexture, occlusionTexture; + var tempTexture, occlusionTexture; - var init = function () { + var init = function () { - var vertices = new Float32Array([ - -1, -1, 0, 0, - 1, -1, 1, 0, - 1, 1, 1, 1, - -1, 1, 0, 1 - ]); + var vertices = new Float32Array( [ + - 1, - 1, 0, 0, + 1, - 1, 1, 0, + 1, 1, 1, 1, + - 1, 1, 0, 1 + ] ); - var faces = new Uint16Array([ - 0, 1, 2, - 0, 2, 3 - ]); + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - // buffers + // buffers - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - // textures + // textures - tempTexture = gl.createTexture(); - occlusionTexture = gl.createTexture(); + tempTexture = gl.createTexture(); + occlusionTexture = gl.createTexture(); - renderer.state.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); + state.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 ); - renderer.state.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); + state.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; + hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0; - var shader; + var shader; - if (hasVertexTexture) { + if ( hasVertexTexture ) { - shader = { + shader = { - vertexShader: [ + vertexShader: [ - "uniform lowp int renderType;", + "uniform lowp int renderType;", - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - "uniform sampler2D occlusionMap;", + "uniform sampler2D occlusionMap;", - "attribute vec2 position;", - "attribute vec2 uv;", + "attribute vec2 position;", + "attribute vec2 uv;", - "varying vec2 vUV;", - "varying float vVisibility;", + "varying vec2 vUV;", + "varying float vVisibility;", - "void main() {", + "void main() {", - "vUV = uv;", + "vUV = uv;", - "vec2 pos = position;", + "vec2 pos = position;", - "if( renderType == 2 ) {", + "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 ) );", + "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;", + "vVisibility = visibility.r / 9.0;", + "vVisibility *= 1.0 - visibility.g / 9.0;", + "vVisibility *= visibility.b / 9.0;", + "vVisibility *= 1.0 - visibility.a / 9.0;", - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - "}", + "}", - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - "}" + "}" - ].join("\n"), + ].join( "\n" ), - fragmentShader: [ + fragmentShader: [ - "uniform lowp int renderType;", + "uniform lowp int renderType;", - "uniform sampler2D map;", - "uniform float opacity;", - "uniform vec3 color;", + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", - "varying vec2 vUV;", - "varying float vVisibility;", + "varying vec2 vUV;", + "varying float vVisibility;", - "void main() {", + "void main() {", - // pink square + // pink square - "if( renderType == 0 ) {", + "if( renderType == 0 ) {", - "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", - // restore + // restore - "} else if( renderType == 1 ) {", + "} else if( renderType == 1 ) {", - "gl_FragColor = texture2D( map, vUV );", + "gl_FragColor = texture2D( map, vUV );", - // flare + // flare - "} else {", + "} else {", - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * vVisibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - "}", + "}", - "}" + "}" - ].join("\n") + ].join( "\n" ) - }; + }; - } else { + } else { - shader = { + shader = { - vertexShader: [ + vertexShader: [ - "uniform lowp int renderType;", + "uniform lowp int renderType;", - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", - "attribute vec2 position;", - "attribute vec2 uv;", + "attribute vec2 position;", + "attribute vec2 uv;", - "varying vec2 vUV;", + "varying vec2 vUV;", - "void main() {", + "void main() {", - "vUV = uv;", + "vUV = uv;", - "vec2 pos = position;", + "vec2 pos = position;", - "if( renderType == 2 ) {", + "if( renderType == 2 ) {", - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - "}", + "}", - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - "}" + "}" - ].join("\n"), + ].join( "\n" ), - fragmentShader: [ + fragmentShader: [ - "precision mediump float;", + "precision mediump float;", - "uniform lowp int renderType;", + "uniform lowp int renderType;", - "uniform sampler2D map;", - "uniform sampler2D occlusionMap;", - "uniform float opacity;", - "uniform vec3 color;", + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", - "varying vec2 vUV;", + "varying vec2 vUV;", - "void main() {", + "void main() {", - // pink square + // pink square - "if( renderType == 0 ) {", + "if( renderType == 0 ) {", - "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", - // restore + // restore - "} else if( renderType == 1 ) {", + "} else if( renderType == 1 ) {", - "gl_FragColor = texture2D( map, vUV );", + "gl_FragColor = texture2D( map, vUV );", - // flare + // flare - "} else {", + "} else {", - "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 );", + "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;", + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", - "}", + "}", - "}" + "}" - ].join("\n") + ].join( "\n" ) - }; + }; - } + } - program = createProgram(shader); + program = createProgram( shader ); - attributes = { - vertex: gl.getAttribLocation(program, "position"), - uv: gl.getAttribLocation(program, "uv") - }; + attributes = { + vertex: gl.getAttribLocation ( program, "position" ), + uv: gl.getAttribLocation ( program, "uv" ) + }; - 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") - }; + 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" ) + }; - }; + }; - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - */ + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + */ - this.render = function (scene, camera, viewportWidth, viewportHeight) { + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { - if (flares.length === 0) return; + if ( flares.length === 0 ) return; - var tempPosition = new THREE.Vector3(); + var tempPosition = new THREE.Vector3(); - var invAspect = viewportHeight / viewportWidth, - halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; - var size = 16 / viewportHeight, - scale = new THREE.Vector2(size * invAspect, size); + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); - var screenPosition = new THREE.Vector3(1, 1, 0), - screenPositionPixels = new THREE.Vector2(1, 1); + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); - if (program === undefined) { + if ( program === undefined ) { - init(); + init(); - } + } - gl.useProgram(program); + gl.useProgram( program ); - renderer.state.initAttributes(); - renderer.state.enableAttribute(attributes.vertex); - renderer.state.enableAttribute(attributes.uv); - renderer.state.disableUnusedAttributes(); + state.initAttributes(); + state.enableAttribute( attributes.vertex ); + state.enableAttribute( attributes.uv ); + state.disableUnusedAttributes(); - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/unforms + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/uniforms - gl.uniform1i(uniforms.occlusionMap, 0); - gl.uniform1i(uniforms.map, 1); + gl.uniform1i( uniforms.occlusionMap, 0 ); + gl.uniform1i( uniforms.map, 1 ); - 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); + 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 ); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.disable(gl.CULL_FACE); - gl.depthMask(false); + state.disable( gl.CULL_FACE ); + gl.depthMask( false ); - for (var i = 0, l = flares.length; i < l; i++) { + for ( var i = 0, l = flares.length; i < l; i ++ ) { - size = 16 / viewportHeight; - scale.set(size * invAspect, size); + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); - // calc object screen position + // calc object screen position - var flare = flares[i]; + var flare = flares[ i ]; - tempPosition.set(flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14]); + tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); - tempPosition.applyMatrix4(camera.matrixWorldInverse); - tempPosition.applyProjection(camera.projectionMatrix); + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); - // setup arrays for gl programs + // setup arrays for gl programs - screenPosition.copy(tempPosition); + screenPosition.copy( tempPosition ); - screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; - screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; - // screen cull + // screen cull - if (hasVertexTexture || ( - screenPositionPixels.x > 0 && - screenPositionPixels.x < viewportWidth && - screenPositionPixels.y > 0 && - screenPositionPixels.y < viewportHeight )) { + if ( hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { - // save current RGB to temp texture + // save current RGB to temp texture - renderer.state.activeTexture(gl.TEXTURE1); - renderer.state.bindTexture(gl.TEXTURE_2D, tempTexture); - gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0); + state.activeTexture( gl.TEXTURE0 ); + state.bindTexture( gl.TEXTURE_2D, null ); + state.activeTexture( gl.TEXTURE1 ); + state.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - // render pink quad + // 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); + gl.uniform1i( uniforms.renderType, 0 ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - gl.disable(gl.BLEND); - gl.enable(gl.DEPTH_TEST); + state.disable( gl.BLEND ); + state.enable( gl.DEPTH_TEST ); - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - // copy result to occlusionMap + // copy result to occlusionMap - renderer.state.activeTexture(gl.TEXTURE0); - renderer.state.bindTexture(gl.TEXTURE_2D, occlusionTexture); - gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0); + state.activeTexture( gl.TEXTURE0 ); + state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); + gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - // restore graphics + // restore graphics - gl.uniform1i(uniforms.renderType, 1); - gl.disable(gl.DEPTH_TEST); + gl.uniform1i( uniforms.renderType, 1 ); + state.disable( gl.DEPTH_TEST ); - renderer.state.activeTexture(gl.TEXTURE1); - renderer.state.bindTexture(gl.TEXTURE_2D, tempTexture); - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + state.activeTexture( gl.TEXTURE1 ); + state.bindTexture( gl.TEXTURE_2D, tempTexture ); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - // update object positions + // update object positions - flare.positionScreen.copy(screenPosition); + flare.positionScreen.copy( screenPosition ); - if (flare.customUpdateCallback) { + if ( flare.customUpdateCallback ) { - flare.customUpdateCallback(flare); + flare.customUpdateCallback( flare ); - } else { + } else { - flare.updateLensFlares(); + flare.updateLensFlares(); - } + } - // render flares + // render flares - gl.uniform1i(uniforms.renderType, 2); - gl.enable(gl.BLEND); + gl.uniform1i( uniforms.renderType, 2 ); + state.enable( gl.BLEND ); - for (var j = 0, jl = flare.lensFlares.length; j < jl; j++) { + for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - var sprite = flare.lensFlares[j]; + var sprite = flare.lensFlares[ j ]; - if (sprite.opacity > 0.001 && sprite.scale > 0.001) { + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; - size = sprite.size * sprite.scale / viewportHeight; + size = sprite.size * sprite.scale / viewportHeight; - scale.x = size * invAspect; - scale.y = size; + scale.x = size * invAspect; + scale.y = size; - gl.uniform3f(uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z); - gl.uniform2f(uniforms.scale, scale.x, scale.y); - gl.uniform1f(uniforms.rotation, sprite.rotation); + gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + gl.uniform2f( uniforms.scale, scale.x, scale.y ); + gl.uniform1f( uniforms.rotation, sprite.rotation ); - gl.uniform1f(uniforms.opacity, sprite.opacity); - gl.uniform3f(uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b); + gl.uniform1f( uniforms.opacity, sprite.opacity ); + gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); - renderer.state.setBlending(sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst); - renderer.setTexture(sprite.texture, 1); + state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + renderer.setTexture( sprite.texture, 1 ); - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - } + } - } + } - } + } - } + } - // restore gl + // restore gl - gl.enable(gl.CULL_FACE); - gl.enable(gl.DEPTH_TEST); - gl.depthMask(true); + state.enable( gl.CULL_FACE ); + state.enable( gl.DEPTH_TEST ); + gl.depthMask( true ); - renderer.resetGLState(); + renderer.resetGLState(); - }; + }; - function createProgram(shader) { + function createProgram ( shader ) { - var program = gl.createProgram(); + var program = gl.createProgram(); - var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - var vertexShader = gl.createShader(gl.VERTEX_SHADER); + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - var prefix = "precision " + renderer.getPrecision() + " float;\n"; + var prefix = "precision " + renderer.getPrecision() + " float;\n"; - gl.shaderSource(fragmentShader, prefix + shader.fragmentShader); - gl.shaderSource(vertexShader, prefix + shader.vertexShader); + gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - gl.compileShader(fragmentShader); - gl.compileShader(vertexShader); + gl.compileShader( fragmentShader ); + gl.compileShader( vertexShader ); - gl.attachShader(program, fragmentShader); - gl.attachShader(program, vertexShader); + gl.attachShader( program, fragmentShader ); + gl.attachShader( program, vertexShader ); - gl.linkProgram(program); + gl.linkProgram( program ); - return program; + return program; - } + } }; @@ -25712,365 +28103,366 @@ THREE.LensFlarePlugin = function (renderer, flares) { * @author alteredq / http://alteredqualia.com/ */ -THREE.SpritePlugin = function (renderer, sprites) { +THREE.SpritePlugin = function ( renderer, sprites ) { - var gl = renderer.context; + var gl = renderer.context; + var state = renderer.state; - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; + var vertexBuffer, elementBuffer; + var program, attributes, uniforms; - var texture; + var texture; - // decompose matrixWorld + // decompose matrixWorld - var spritePosition = new THREE.Vector3(); - var spriteRotation = new THREE.Quaternion(); - var spriteScale = new THREE.Vector3(); + var spritePosition = new THREE.Vector3(); + var spriteRotation = new THREE.Quaternion(); + var spriteScale = new THREE.Vector3(); - var init = function () { + var init = function () { - 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 - ]); + 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 + ] ); - var faces = new Uint16Array([ - 0, 1, 2, - 0, 2, 3 - ]); + var faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); + vertexBuffer = gl.createBuffer(); + elementBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); + gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - program = createProgram(); + program = createProgram(); - attributes = { - position: gl.getAttribLocation(program, 'position'), - uv: gl.getAttribLocation(program, 'uv') - }; + attributes = { + position: gl.getAttribLocation ( program, 'position' ), + uv: gl.getAttribLocation ( program, 'uv' ) + }; - uniforms = { - uvOffset: gl.getUniformLocation(program, 'uvOffset'), - uvScale: gl.getUniformLocation(program, 'uvScale'), + uniforms = { + uvOffset: gl.getUniformLocation( program, 'uvOffset' ), + uvScale: gl.getUniformLocation( program, 'uvScale' ), - rotation: gl.getUniformLocation(program, 'rotation'), - scale: gl.getUniformLocation(program, 'scale'), + rotation: gl.getUniformLocation( program, 'rotation' ), + scale: gl.getUniformLocation( program, 'scale' ), - color: gl.getUniformLocation(program, 'color'), - map: gl.getUniformLocation(program, 'map'), - opacity: gl.getUniformLocation(program, 'opacity'), + color: gl.getUniformLocation( program, 'color' ), + map: gl.getUniformLocation( program, 'map' ), + opacity: gl.getUniformLocation( program, 'opacity' ), - modelViewMatrix: gl.getUniformLocation(program, 'modelViewMatrix'), - projectionMatrix: gl.getUniformLocation(program, 'projectionMatrix'), + 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'), + 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' ), - alphaTest: gl.getUniformLocation(program, 'alphaTest') - }; + alphaTest: gl.getUniformLocation( program, 'alphaTest' ) + }; - var canvas = document.createElement('canvas'); - canvas.width = 8; - canvas.height = 8; + var canvas = document.createElement( 'canvas' ); + canvas.width = 8; + canvas.height = 8; - var context = canvas.getContext('2d'); - context.fillStyle = 'white'; - context.fillRect(0, 0, 8, 8); + var context = canvas.getContext( '2d' ); + context.fillStyle = 'white'; + context.fillRect( 0, 0, 8, 8 ); - texture = new THREE.Texture(canvas); - texture.needsUpdate = true; + texture = new THREE.Texture( canvas ); + texture.needsUpdate = true; - }; + }; - this.render = function (scene, camera) { + this.render = function ( scene, camera ) { - if (sprites.length === 0) return; + if ( sprites.length === 0 ) return; - // setup gl + // setup gl - if (program === undefined) { + if ( program === undefined ) { - init(); + init(); - } + } - gl.useProgram(program); + gl.useProgram( program ); - renderer.state.initAttributes(); - renderer.state.enableAttribute(attributes.position); - renderer.state.enableAttribute(attributes.uv); - renderer.state.disableUnusedAttributes(); + state.initAttributes(); + state.enableAttribute( attributes.position ); + state.enableAttribute( attributes.uv ); + state.disableUnusedAttributes(); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); + state.disable( gl.CULL_FACE ); + state.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); + 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 ); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.uniformMatrix4fv(uniforms.projectionMatrix, false, camera.projectionMatrix.elements); + gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - renderer.state.activeTexture(gl.TEXTURE0); - gl.uniform1i(uniforms.map, 0); + state.activeTexture( gl.TEXTURE0 ); + gl.uniform1i( uniforms.map, 0 ); - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; - if (fog) { + if ( fog ) { - gl.uniform3f(uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b); + gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); - if (fog instanceof THREE.Fog) { + if ( fog instanceof THREE.Fog ) { - gl.uniform1f(uniforms.fogNear, fog.near); - gl.uniform1f(uniforms.fogFar, fog.far); + gl.uniform1f( uniforms.fogNear, fog.near ); + gl.uniform1f( uniforms.fogFar, fog.far ); - gl.uniform1i(uniforms.fogType, 1); - oldFogType = 1; - sceneFogType = 1; + gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; - } else if (fog instanceof THREE.FogExp2) { + } else if ( fog instanceof THREE.FogExp2 ) { - gl.uniform1f(uniforms.fogDensity, fog.density); + gl.uniform1f( uniforms.fogDensity, fog.density ); - gl.uniform1i(uniforms.fogType, 2); - oldFogType = 2; - sceneFogType = 2; + gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; - } + } - } else { + } else { - gl.uniform1i(uniforms.fogType, 0); - oldFogType = 0; - sceneFogType = 0; + gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; - } + } - // update positions and sort + // update positions and sort - for (var i = 0, l = sprites.length; i < l; i++) { + for ( var i = 0, l = sprites.length; i < l; i ++ ) { - var sprite = sprites[i]; + var sprite = sprites[ i ]; - sprite._modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, sprite.matrixWorld); - sprite.z = -sprite._modelViewMatrix.elements[14]; + sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; - } + } - sprites.sort(painterSortStable); + sprites.sort( painterSortStable ); - // render all sprites + // render all sprites - var scale = []; + var scale = []; - for (var i = 0, l = sprites.length; i < l; i++) { + for ( var i = 0, l = sprites.length; i < l; i ++ ) { - var sprite = sprites[i]; - var material = sprite.material; + var sprite = sprites[ i ]; + var material = sprite.material; - gl.uniform1f(uniforms.alphaTest, material.alphaTest); - gl.uniformMatrix4fv(uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements); + gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); - sprite.matrixWorld.decompose(spritePosition, spriteRotation, spriteScale); + sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); - scale[0] = spriteScale.x; - scale[1] = spriteScale.y; + scale[ 0 ] = spriteScale.x; + scale[ 1 ] = spriteScale.y; - var fogType = 0; + var fogType = 0; - if (scene.fog && material.fog) { + if ( scene.fog && material.fog ) { - fogType = sceneFogType; + fogType = sceneFogType; - } + } - if (oldFogType !== fogType) { + if ( oldFogType !== fogType ) { - gl.uniform1i(uniforms.fogType, fogType); - oldFogType = fogType; + gl.uniform1i( uniforms.fogType, fogType ); + oldFogType = fogType; - } + } - if (material.map !== null) { + 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); + gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); + gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); - } else { + } else { - gl.uniform2f(uniforms.uvOffset, 0, 0); - gl.uniform2f(uniforms.uvScale, 1, 1); + gl.uniform2f( uniforms.uvOffset, 0, 0 ); + gl.uniform2f( uniforms.uvScale, 1, 1 ); - } + } - gl.uniform1f(uniforms.opacity, material.opacity); - gl.uniform3f(uniforms.color, material.color.r, material.color.g, material.color.b); + gl.uniform1f( uniforms.opacity, material.opacity ); + gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); - gl.uniform1f(uniforms.rotation, material.rotation); - gl.uniform2fv(uniforms.scale, scale); + 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); + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); - if (material.map && material.map.image && material.map.image.width) { + if ( material.map && material.map.image && material.map.image.width ) { - renderer.setTexture(material.map, 0); + renderer.setTexture( material.map, 0 ); - } else { + } else { - renderer.setTexture(texture, 0); + renderer.setTexture( texture, 0 ); - } + } - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - } + } - // restore gl + // restore gl - gl.enable(gl.CULL_FACE); + state.enable( gl.CULL_FACE ); - renderer.resetGLState(); + renderer.resetGLState(); - }; + }; - function createProgram() { + function createProgram () { - var program = gl.createProgram(); + var program = gl.createProgram(); - var vertexShader = gl.createShader(gl.VERTEX_SHADER); - var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + var vertexShader = gl.createShader( gl.VERTEX_SHADER ); + var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); - gl.shaderSource(vertexShader, [ + gl.shaderSource( vertexShader, [ - 'precision ' + renderer.getPrecision() + ' float;', + 'precision ' + renderer.getPrecision() + ' float;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform float rotation;', - 'uniform vec2 scale;', - 'uniform vec2 uvOffset;', - 'uniform vec2 uvScale;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform float rotation;', + 'uniform vec2 scale;', + 'uniform vec2 uvOffset;', + 'uniform vec2 uvScale;', - 'attribute vec2 position;', - 'attribute vec2 uv;', + 'attribute vec2 position;', + 'attribute vec2 uv;', - 'varying vec2 vUV;', + 'varying vec2 vUV;', - 'void main() {', + 'void main() {', - 'vUV = uvOffset + uv * uvScale;', + 'vUV = uvOffset + uv * uvScale;', - 'vec2 alignedPosition = position * scale;', + 'vec2 alignedPosition = position * scale;', - 'vec2 rotatedPosition;', - 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', - 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', + 'vec2 rotatedPosition;', + 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', + 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', - 'vec4 finalPosition;', + 'vec4 finalPosition;', - 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', - 'finalPosition.xy += rotatedPosition;', - 'finalPosition = projectionMatrix * finalPosition;', + 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', + 'finalPosition.xy += rotatedPosition;', + 'finalPosition = projectionMatrix * finalPosition;', - 'gl_Position = finalPosition;', + 'gl_Position = finalPosition;', - '}' + '}' - ].join('\n')); + ].join( '\n' ) ); - gl.shaderSource(fragmentShader, [ + gl.shaderSource( fragmentShader, [ - 'precision ' + renderer.getPrecision() + ' float;', + 'precision ' + renderer.getPrecision() + ' float;', - 'uniform vec3 color;', - 'uniform sampler2D map;', - 'uniform float opacity;', + '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;', + 'uniform int fogType;', + 'uniform vec3 fogColor;', + 'uniform float fogDensity;', + 'uniform float fogNear;', + 'uniform float fogFar;', + 'uniform float alphaTest;', - 'varying vec2 vUV;', + 'varying vec2 vUV;', - 'void main() {', + 'void main() {', - 'vec4 texture = texture2D( map, vUV );', + 'vec4 texture = texture2D( map, vUV );', - 'if ( texture.a < alphaTest ) discard;', + 'if ( texture.a < alphaTest ) discard;', - 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', + 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', - 'if ( fogType > 0 ) {', + 'if ( fogType > 0 ) {', - 'float depth = gl_FragCoord.z / gl_FragCoord.w;', - 'float fogFactor = 0.0;', + 'float depth = gl_FragCoord.z / gl_FragCoord.w;', + 'float fogFactor = 0.0;', - 'if ( fogType == 1 ) {', + 'if ( fogType == 1 ) {', - 'fogFactor = smoothstep( fogNear, fogFar, depth );', + 'fogFactor = smoothstep( fogNear, fogFar, depth );', - '} else {', + '} else {', - 'const float LOG2 = 1.442695;', - 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', - 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', + 'const float LOG2 = 1.442695;', + 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', + 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', - '}', + '}', - 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', + 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', - '}', + '}', - '}' + '}' - ].join('\n')); + ].join( '\n' ) ); - gl.compileShader(vertexShader); - gl.compileShader(fragmentShader); + gl.compileShader( vertexShader ); + gl.compileShader( fragmentShader ); - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); + gl.attachShader( program, vertexShader ); + gl.attachShader( program, fragmentShader ); - gl.linkProgram(program); + gl.linkProgram( program ); - return program; + return program; - } + } - function painterSortStable(a, b) { + function painterSortStable ( a, b ) { - if (a.z !== b.z) { + if ( a.z !== b.z ) { - return b.z - a.z; + return b.z - a.z; - } else { + } else { - return b.id - a.id; + return b.id - a.id; - } + } - } + } }; @@ -26082,31 +28474,31 @@ THREE.SpritePlugin = function (renderer, sprites) { THREE.GeometryUtils = { - merge: function (geometry1, geometry2, materialIndexOffset) { + merge: function ( geometry1, geometry2, materialIndexOffset ) { - THREE.warn('THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.'); + console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); - var matrix; + var matrix; - if (geometry2 instanceof THREE.Mesh) { + if ( geometry2 instanceof THREE.Mesh ) { - geometry2.matrixAutoUpdate && geometry2.updateMatrix(); + geometry2.matrixAutoUpdate && geometry2.updateMatrix(); - matrix = geometry2.matrix; - geometry2 = geometry2.geometry; + matrix = geometry2.matrix; + geometry2 = geometry2.geometry; - } + } - geometry1.merge(geometry2, matrix, materialIndexOffset); + geometry1.merge( geometry2, matrix, materialIndexOffset ); - }, + }, - center: function (geometry) { + center: function ( geometry ) { - THREE.warn('THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.'); - return geometry.center(); + console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + return geometry.center(); - } + } }; @@ -26120,217 +28512,213 @@ THREE.GeometryUtils = { THREE.ImageUtils = { - crossOrigin: undefined, - - loadTexture: function (url, mapping, onLoad, onError) { - - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; + crossOrigin: undefined, - var texture = new THREE.Texture(undefined, mapping); + loadTexture: function ( url, mapping, onLoad, onError ) { - loader.load(url, function (image) { + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; - texture.image = image; - texture.needsUpdate = true; + var texture = new THREE.Texture( undefined, mapping ); - if (onLoad) onLoad(texture); + loader.load( url, function ( image ) { - }, undefined, function (event) { + texture.image = image; + texture.needsUpdate = true; - if (onError) onError(event); + if ( onLoad ) onLoad( texture ); - }); + }, undefined, function ( event ) { - texture.sourceFile = url; + if ( onError ) onError( event ); - return texture; + } ); - }, + texture.sourceFile = url; - loadTextureCube: function (array, mapping, onLoad, onError) { + return texture; - var images = []; + }, - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; + loadTextureCube: function ( array, mapping, onLoad, onError ) { - var texture = new THREE.CubeTexture(images, mapping); + var images = []; - // no flipping needed for cube textures + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; - texture.flipY = false; + var texture = new THREE.CubeTexture( images, mapping ); - var loaded = 0; + var loaded = 0; - var loadTexture = function (i) { + var loadTexture = function ( i ) { - loader.load(array[i], function (image) { + loader.load( array[ i ], function ( image ) { - texture.images[i] = image; + texture.images[ i ] = image; - loaded += 1; + loaded += 1; - if (loaded === 6) { + if ( loaded === 6 ) { - texture.needsUpdate = true; + texture.needsUpdate = true; - if (onLoad) onLoad(texture); + if ( onLoad ) onLoad( texture ); - } + } - }, undefined, onError); + }, undefined, onError ); - }; + }; - for (var i = 0, il = array.length; i < il; ++i) { + for ( var i = 0, il = array.length; i < il; ++ i ) { - loadTexture(i); + loadTexture( i ); - } + } - return texture; + return texture; - }, + }, - loadCompressedTexture: function () { + loadCompressedTexture: function () { - THREE.error('THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.') + console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) - }, + }, - loadCompressedTextureCube: function () { + loadCompressedTextureCube: function () { - THREE.error('THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.') + console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) - }, + }, - getNormalMap: function (image, depth) { + getNormalMap: function ( image, depth ) { - // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ - var cross = function (a, b) { + var cross = function ( a, b ) { - 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]]; + 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 ] ]; - }; + }; - var subtract = function (a, b) { + var subtract = function ( a, b ) { - return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]; + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; - }; + }; - var normalize = function (a) { + var normalize = function ( a ) { - 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 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 ]; - }; + }; - depth = depth | 1; + depth = depth | 1; - var width = image.width; - var height = image.height; + var width = image.width; + var height = image.height; - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 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; + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; - for (var x = 0; x < width; x++) { + for ( var x = 0; x < width; x ++ ) { - for (var y = 0; y < height; y++) { + 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; + 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; - 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]); + 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 ] ); - var normals = []; - var num_points = points.length; + var normals = []; + var num_points = points.length; - for (var i = 0; i < num_points; i++) { + 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))); + 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 ) ) ); - } + } - var normal = [0, 0, 0]; + var normal = [ 0, 0, 0 ]; - for (var i = 0; i < normals.length; i++) { + for ( var i = 0; i < normals.length; i ++ ) { - normal[0] += normals[i][0]; - normal[1] += normals[i][1]; - normal[2] += normals[i][2]; + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; - } + } - normal[0] /= normals.length; - normal[1] /= normals.length; - normal[2] /= normals.length; + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; - var idx = ( y * width + x ) * 4; + 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; + 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; - } + } - } + } - context.putImageData(imageData, 0, 0); + context.putImageData( imageData, 0, 0 ); - return canvas; + return canvas; - }, + }, - generateDataTexture: function (width, height, color) { + generateDataTexture: function ( width, height, color ) { - var size = width * height; - var data = new Uint8Array(3 * size); + var size = width * height; + var data = new Uint8Array( 3 * size ); - var r = Math.floor(color.r * 255); - var g = Math.floor(color.g * 255); - var b = Math.floor(color.b * 255); + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); - for (var i = 0; i < size; i++) { + for ( var i = 0; i < size; i ++ ) { - data[i * 3] = r; - data[i * 3 + 1] = g; - data[i * 3 + 2] = b; + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; - } + } - var texture = new THREE.DataTexture(data, width, height, THREE.RGBFormat); - texture.needsUpdate = true; + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; - return texture; + return texture; - } + } }; @@ -26342,38 +28730,38 @@ THREE.ImageUtils = { THREE.SceneUtils = { - createMultiMaterialObject: function (geometry, materials) { + createMultiMaterialObject: function ( geometry, materials ) { - var group = new THREE.Object3D(); + var group = new THREE.Group(); - for (var i = 0, l = materials.length; i < l; i++) { + for ( var i = 0, l = materials.length; i < l; i ++ ) { - group.add(new THREE.Mesh(geometry, materials[i])); + group.add( new THREE.Mesh( geometry, materials[ i ] ) ); - } + } - return group; + return group; - }, + }, - detach: function (child, parent, scene) { + detach: function ( child, parent, scene ) { - child.applyMatrix(parent.matrixWorld); - parent.remove(child); - scene.add(child); + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); - }, + }, - attach: function (child, scene, parent) { + attach: function ( child, scene, parent ) { - var matrixWorldInverse = new THREE.Matrix4(); - matrixWorldInverse.getInverse(parent.matrixWorld); - child.applyMatrix(matrixWorldInverse); + var matrixWorldInverse = new THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); - scene.remove(child); - parent.add(child); + scene.remove( child ); + parent.add( child ); - } + } }; @@ -26387,262 +28775,264 @@ THREE.SceneUtils = { * * 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 * - * 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/ + * A Method to triangulate shapes with holes + * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ * */ THREE.FontUtils = { - faces: {}, + faces: {}, - // Just for now. face[weight][style] + // Just for now. face[weight][style] - face: 'helvetiker', - weight: 'normal', - style: 'normal', - size: 150, - divisions: 10, + face: 'helvetiker', + weight: 'normal', + style: 'normal', + size: 150, + divisions: 10, - getFace: function () { + getFace: function () { - try { + try { - return this.faces[this.face][this.weight][this.style]; + return this.faces[ this.face.toLowerCase() ][ this.weight ][ this.style ]; - } catch (e) { + } catch ( e ) { - throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." + throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." - } + } - }, + }, - loadFace: function (data) { + loadFace: function ( data ) { - var family = data.familyName.toLowerCase(); + var family = data.familyName.toLowerCase(); - var ThreeFont = this; + var ThreeFont = this; - ThreeFont.faces[family] = ThreeFont.faces[family] || {}; + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; - ThreeFont.faces[family][data.cssFontWeight] = ThreeFont.faces[family][data.cssFontWeight] || {}; - ThreeFont.faces[family][data.cssFontWeight][data.cssFontStyle] = data; + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - ThreeFont.faces[family][data.cssFontWeight][data.cssFontStyle] = data; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - return data; + return data; - }, + }, - drawText: function (text) { + drawText: function ( text ) { - // RenderText + // RenderText - var i, - face = this.getFace(), - scale = this.size / face.resolution, - offset = 0, - chars = String(text).split(''), - length = chars.length; + var i, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; - var fontPaths = []; + var fontPaths = []; - for (i = 0; i < length; i++) { + for ( i = 0; i < length; i ++ ) { - var path = new THREE.Path(); + var path = new THREE.Path(); - var ret = this.extractGlyphPoints(chars[i], face, scale, offset, path); - offset += ret.offset; + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; - fontPaths.push(ret.path); + fontPaths.push( ret.path ); - } + } - // get the width + // get the width - var width = offset / 2; - // - // for ( p = 0; p < allPts.length; p++ ) { - // - // allPts[ p ].x -= width; - // - // } + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } - //var extract = this.extractPoints( allPts, characterPts ); - //extract.contour = allPts; + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; - //extract.paths = fontPaths; - //extract.offset = width; + //extract.paths = fontPaths; + //extract.offset = width; - return {paths: fontPaths, offset: width}; + return { paths: fontPaths, offset: width }; - }, + }, - extractGlyphPoints: function (c, face, scale, offset, path) { - var pts = []; - var i, i2, divisions, - outline, action, length, - scaleX, scaleY, - x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, - laste, - glyph = face.glyphs[c] || face.glyphs['?']; + extractGlyphPoints: function ( c, face, scale, offset, path ) { - if (!glyph) return; + var pts = []; - if (glyph.o) { + 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[ '?' ]; - outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split(' ') ); - length = outline.length; + if ( ! glyph ) return; - scaleX = scale; - scaleY = scale; + if ( glyph.o ) { - for (i = 0; i < length;) { + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; - action = outline[i++]; + scaleX = scale; + scaleY = scale; - //THREE.log( action ); + for ( i = 0; i < length; ) { - switch (action) { + action = outline[ i ++ ]; - case 'm': + //console.log( action ); - // Move To + switch ( action ) { - x = outline[i++] * scaleX + offset; - y = outline[i++] * scaleY; + case 'm': - path.moveTo(x, y); - break; + // Move To - case 'l': + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; - // Line To + path.moveTo( x, y ); + break; - x = outline[i++] * scaleX + offset; - y = outline[i++] * scaleY; - path.lineTo(x, y); - break; + case 'l': - case 'q': + // Line To - // QuadraticCurveTo + x = outline[ i ++ ] * scaleX + offset; + y = outline[ i ++ ] * scaleY; + path.lineTo( x, y ); + break; - cpx = outline[i++] * scaleX + offset; - cpy = outline[i++] * scaleY; - cpx1 = outline[i++] * scaleX + offset; - cpy1 = outline[i++] * scaleY; + case 'q': - path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + // QuadraticCurveTo - laste = pts[pts.length - 1]; + cpx = outline[ i ++ ] * scaleX + offset; + cpy = outline[ i ++ ] * scaleY; + cpx1 = outline[ i ++ ] * scaleX + offset; + cpy1 = outline[ i ++ ] * scaleY; - if (laste) { + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - cpx0 = laste.x; - cpy0 = laste.y; + laste = pts[ pts.length - 1 ]; - for (i2 = 1, divisions = this.divisions; i2 <= divisions; i2++) { + if ( laste ) { - var t = i2 / divisions; - THREE.Shape.Utils.b2(t, cpx0, cpx1, cpx); - THREE.Shape.Utils.b2(t, cpy0, cpy1, cpy); - } + cpx0 = laste.x; + cpy0 = laste.y; - } + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - break; + var t = i2 / divisions; + THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - case 'b': + } - // Cubic Bezier Curve + } - cpx = outline[i++] * scaleX + offset; - cpy = outline[i++] * scaleY; - cpx1 = outline[i++] * scaleX + offset; - cpy1 = outline[i++] * scaleY; - cpx2 = outline[i++] * scaleX + offset; - cpy2 = outline[i++] * scaleY; + break; - path.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, cpx, cpy); + case 'b': - laste = pts[pts.length - 1]; + // Cubic Bezier Curve - if (laste) { + 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; - cpx0 = laste.x; - cpy0 = laste.y; + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - for (i2 = 1, divisions = this.divisions; i2 <= divisions; i2++) { + laste = pts[ pts.length - 1 ]; - var t = i2 / divisions; - THREE.Shape.Utils.b3(t, cpx0, cpx1, cpx2, cpx); - THREE.Shape.Utils.b3(t, cpy0, cpy1, cpy2, cpy); + if ( laste ) { - } + cpx0 = laste.x; + cpy0 = laste.y; - } + 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 ); - } + } - } - } + } + break; - return {offset: glyph.ha * scale, path: path}; - } + } + + } + + } + + + + return { offset: glyph.ha * scale, path: path }; + + } }; -THREE.FontUtils.generateShapes = function (text, parameters) { +THREE.FontUtils.generateShapes = function ( text, parameters ) { - // Parameters + // Parameters - parameters = parameters || {}; + parameters = parameters || {}; - var size = parameters.size !== undefined ? parameters.size : 100; - var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; - var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; - var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; - var style = parameters.style !== undefined ? parameters.style : 'normal'; + var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; + var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; + var style = parameters.style !== undefined ? parameters.style : 'normal'; - THREE.FontUtils.size = size; - THREE.FontUtils.divisions = curveSegments; + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; - THREE.FontUtils.face = font; - THREE.FontUtils.weight = weight; - THREE.FontUtils.style = style; + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; - // Get a Font data json object + // Get a Font data json object - var data = THREE.FontUtils.drawText(text); + var data = THREE.FontUtils.drawText( text ); - var paths = data.paths; - var shapes = []; + var paths = data.paths; + var shapes = []; - for (var p = 0, pl = paths.length; p < pl; p++) { + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - Array.prototype.push.apply(shapes, paths[p].toShapes()); + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - } + } - return shapes; + return shapes; }; @@ -26662,201 +29052,189 @@ THREE.FontUtils.generateShapes = function (text, parameters) { */ -(function (namespace) { +( function ( namespace ) { - var EPSILON = 0.0000000001; + var EPSILON = 0.0000000001; - // takes in an contour array and returns + // takes in an contour array and returns - var process = function (contour, indices) { + var process = function ( contour, indices ) { - var n = contour.length; + var n = contour.length; - if (n < 3) return null; + if ( n < 3 ) return null; - var result = [], - verts = [], - vertIndices = []; + var result = [], + verts = [], + vertIndices = []; - /* we want a counter-clockwise polygon in verts */ + /* we want a counter-clockwise polygon in verts */ - var u, v, w; + var u, v, w; - if (area(contour) > 0.0) { + if ( area( contour ) > 0.0 ) { - for (v = 0; v < n; v++) verts[v] = v; + for ( v = 0; v < n; v ++ ) verts[ v ] = v; - } else { + } else { - for (v = 0; v < n; v++) verts[v] = ( n - 1 ) - v; + for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; - } + } - var nv = n; + var nv = n; - /* remove nv - 2 vertices, creating 1 triangle every time */ + /* remove nv - 2 vertices, creating 1 triangle every time */ - var count = 2 * nv; - /* error detection */ + var count = 2 * nv; /* error detection */ - for (v = nv - 1; nv > 2;) { + for ( v = nv - 1; nv > 2; ) { - /* if we loop, it is probably a non-simple polygon */ + /* if we loop, it is probably a non-simple polygon */ - if (( count-- ) <= 0) { + if ( ( count -- ) <= 0 ) { - //** Triangulate: ERROR - probable bad polygon! + //** Triangulate: ERROR - probable bad polygon! - //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()'); + //throw ( "Warning, unable to triangulate polygon!" ); + //return null; + // Sometimes warning is fine, especially polygons are triangulated in reverse. + console.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); - if (indices) return vertIndices; - return result; + if ( indices ) return vertIndices; + return result; - } + } - /* three consecutive vertices in current polygon, */ + /* three consecutive vertices in current polygon, */ - 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 */ + u = v; if ( nv <= u ) u = 0; /* previous */ + v = u + 1; if ( nv <= v ) v = 0; /* new v */ + w = v + 1; if ( nv <= w ) w = 0; /* next */ - if (snip(contour, u, v, w, nv, verts)) { + if ( snip( contour, u, v, w, nv, verts ) ) { - var a, b, c, s, t; + var a, b, c, s, t; - /* true names of the vertices */ + /* true names of the vertices */ - a = verts[u]; - b = verts[v]; - c = verts[w]; + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; - /* output Triangle */ + /* output Triangle */ - result.push([contour[a], - contour[b], - contour[c]]); + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); - vertIndices.push([verts[u], verts[v], verts[w]]); + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); - /* remove v from the remaining polygon */ + /* remove v from the remaining polygon */ - for (s = v, t = v + 1; t < nv; s++, t++) { + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { - verts[s] = verts[t]; + verts[ s ] = verts[ t ]; - } + } - nv--; + nv --; - /* reset error detection counter */ + /* reset error detection counter */ - count = 2 * nv; + count = 2 * nv; - } + } - } + } - if (indices) return vertIndices; - return result; + if ( indices ) return vertIndices; + return result; - }; + }; - // calculate area of the contour polygon + // calculate area of the contour polygon - var area = function (contour) { + var area = function ( contour ) { - var n = contour.length; - var a = 0.0; + var n = contour.length; + var a = 0.0; - for (var p = n - 1, q = 0; q < n; p = q++) { + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { - a += contour[p].x * contour[q].y - contour[q].x * contour[p].y; + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - } + } - return a * 0.5; + return a * 0.5; - }; + }; - var snip = function (contour, u, v, w, n, verts) { + var snip = function ( contour, u, v, w, n, verts ) { - var p; - var ax, ay, bx, by; - var cx, cy, px, py; + var p; + var ax, ay, bx, by; + var cx, cy, px, py; - ax = contour[verts[u]].x; - ay = contour[verts[u]].y; + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; - bx = contour[verts[v]].x; - by = contour[verts[v]].y; + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; - cx = contour[verts[w]].x; - cy = contour[verts[w]].y; + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; - if (EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) )) return false; + 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 aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; - aX = cx - bx; - aY = cy - by; - bX = ax - cx; - bY = ay - cy; - cX = bx - ax; - cY = by - ay; + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; - for (p = 0; p < n; p++) { + for ( p = 0; p < n; p ++ ) { - px = contour[verts[p]].x; - py = contour[verts[p]].y; + px = contour[ verts[ p ] ].x; + py = contour[ verts[ p ] ].y; - if (( ( px === ax ) && ( py === ay ) ) || - ( ( px === bx ) && ( py === by ) ) || - ( ( px === cx ) && ( py === cy ) )) continue; + 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; + apx = px - ax; apy = py - ay; + bpx = px - bx; bpy = py - by; + cpx = px - cx; cpy = py - cy; - // see if p is inside triangle abc + // see if p is inside triangle abc - aCROSSbp = aX * bpy - aY * bpx; - cCROSSap = cX * apy - cY * apx; - bCROSScp = bX * cpy - bY * cpx; + aCROSSbp = aX * bpy - aY * bpx; + cCROSSap = cX * apy - cY * apx; + bCROSScp = bX * cpy - bY * cpx; - if (( aCROSSbp >= -EPSILON ) && ( bCROSScp >= -EPSILON ) && ( cCROSSap >= -EPSILON )) return false; + if ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false; - } + } - return true; + return true; - }; + }; - namespace.Triangulate = process; - namespace.Triangulate.area = area; + namespace.Triangulate = process; + namespace.Triangulate.area = area; - return namespace; + return namespace; -})(THREE.FontUtils); +} )( 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.typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; +if ( typeof self !== 'undefined' ) self._typeface_js = THREE.typeface_js; // File:src/extras/audio/Audio.js @@ -26864,138 +29242,235 @@ THREE.typeface_js = self._typeface_js; * @author mrdoob / http://mrdoob.com/ */ -THREE.Audio = function (listener) { +THREE.Audio = function ( listener ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'Audio'; + this.type = 'Audio'; - this.context = listener.context; - this.source = this.context.createBufferSource(); - this.source.onended = this.onEnded.bind(this); + this.context = listener.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.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - this.panner = this.context.createPanner(); - this.panner.connect(this.gain); + this.panner = this.context.createPanner(); + this.panner.connect( this.gain ); - this.autoplay = false; + this.autoplay = false; - this.startTime = 0; - this.isPlaying = false; + this.startTime = 0; + this.playbackRate = 1; + this.isPlaying = false; }; -THREE.Audio.prototype = Object.create(THREE.Object3D.prototype); +THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); THREE.Audio.prototype.constructor = THREE.Audio; -THREE.Audio.prototype.load = function (file) { +THREE.Audio.prototype.load = function ( file ) { - var scope = this; + var scope = this; - var request = new XMLHttpRequest(); - request.open('GET', file, true); - request.responseType = 'arraybuffer'; - request.onload = function (e) { + var request = new XMLHttpRequest(); + request.open( 'GET', file, true ); + request.responseType = 'arraybuffer'; + request.onload = function ( e ) { - scope.context.decodeAudioData(this.response, function (buffer) { + scope.context.decodeAudioData( this.response, function ( buffer ) { - scope.source.buffer = buffer; + scope.source.buffer = buffer; - if (scope.autoplay) scope.play(); + if ( scope.autoplay ) scope.play(); - }); + } ); - }; - request.send(); + }; + request.send(); - return this; + return this; }; THREE.Audio.prototype.play = function () { - if (this.isPlaying === true) { + if ( this.isPlaying === true ) { - THREE.warn('THREE.Audio: Audio is already playing.'); - return; + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; - } + } + + var source = this.context.createBufferSource(); - var source = this.context.createBufferSource(); + source.buffer = this.source.buffer; + source.loop = this.source.loop; + source.onended = this.source.onended; + source.start( 0, this.startTime ); + source.playbackRate.value = this.playbackRate; - source.buffer = this.source.buffer; - source.loop = this.source.loop; - source.onended = this.source.onended; - source.connect(this.panner); - source.start(0, this.startTime); + this.isPlaying = true; - this.isPlaying = true; + this.source = source; - this.source = source; + this.connect(); }; THREE.Audio.prototype.pause = function () { - this.source.stop(); - this.startTime = this.context.currentTime; + this.source.stop(); + this.startTime = this.context.currentTime; }; THREE.Audio.prototype.stop = function () { - this.source.stop(); - this.startTime = 0; + this.source.stop(); + this.startTime = 0; + +}; + +THREE.Audio.prototype.connect = function () { + + if ( this.filter !== undefined ) { + + this.source.connect( this.filter ); + this.filter.connect( this.panner ); + + } else { + + this.source.connect( this.panner ); + + } + +}; + +THREE.Audio.prototype.disconnect = function () { + + if ( this.filter !== undefined ) { + + this.source.disconnect( this.filter ); + this.filter.disconnect( this.panner ); + + } else { + + this.source.disconnect( this.panner ); + + } + +}; + +THREE.Audio.prototype.setFilter = function ( value ) { + + if ( this.isPlaying === true ) { + + this.disconnect(); + this.filter = value; + this.connect(); + + } else { + + this.filter = value; + + } + +}; + +THREE.Audio.prototype.getFilter = function () { + + return this.filter; + +}; + +THREE.Audio.prototype.setPlaybackRate = function ( value ) { + + this.playbackRate = value; + + if ( this.isPlaying === true ) { + + this.source.playbackRate.value = this.playbackRate; + + } + +}; + +THREE.Audio.prototype.getPlaybackRate = function () { + + return this.playbackRate; + +}; + +THREE.Audio.prototype.onEnded = function() { + + this.isPlaying = false; + +}; + +THREE.Audio.prototype.setLoop = function ( value ) { + + this.source.loop = value; + +}; + +THREE.Audio.prototype.getLoop = function () { + + return this.source.loop; + +}; + +THREE.Audio.prototype.setRefDistance = function ( value ) { + + this.panner.refDistance = value; }; -THREE.Audio.prototype.onEnded = function () { +THREE.Audio.prototype.getRefDistance = function () { - this.isPlaying = false; + return this.panner.refDistance; }; -THREE.Audio.prototype.setLoop = function (value) { +THREE.Audio.prototype.setRolloffFactor = function ( value ) { - this.source.loop = value; + this.panner.rolloffFactor = value; }; -THREE.Audio.prototype.setRefDistance = function (value) { +THREE.Audio.prototype.getRolloffFactor = function () { - this.panner.refDistance = value; + return this.panner.rolloffFactor; }; -THREE.Audio.prototype.setRolloffFactor = function (value) { +THREE.Audio.prototype.setVolume = function ( value ) { - this.panner.rolloffFactor = value; + this.gain.gain.value = value; }; -THREE.Audio.prototype.setVolume = function (value) { +THREE.Audio.prototype.getVolume = function () { - this.gain.gain.value = value; + return this.gain.gain.value; }; -THREE.Audio.prototype.updateMatrixWorld = (function () { +THREE.Audio.prototype.updateMatrixWorld = ( function () { - var position = new THREE.Vector3(); + var position = new THREE.Vector3(); - return function (force) { + return function updateMatrixWorld( force ) { - THREE.Object3D.prototype.updateMatrixWorld.call(this, force); + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); - position.setFromMatrixPosition(this.matrixWorld); + position.setFromMatrixPosition( this.matrixWorld ); - this.panner.setPosition(position.x, position.y, position.z); + this.panner.setPosition( position.x, position.y, position.z ); - }; + }; -})(); +} )(); // File:src/extras/audio/AudioListener.js @@ -27005,42 +29480,42 @@ THREE.Audio.prototype.updateMatrixWorld = (function () { THREE.AudioListener = function () { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.type = 'AudioListener'; + this.type = 'AudioListener'; - this.context = new ( window.AudioContext || window.webkitAudioContext )(); + this.context = new ( window.AudioContext || window.webkitAudioContext )(); }; -THREE.AudioListener.prototype = Object.create(THREE.Object3D.prototype); +THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype ); THREE.AudioListener.prototype.constructor = THREE.AudioListener; -THREE.AudioListener.prototype.updateMatrixWorld = (function () { +THREE.AudioListener.prototype.updateMatrixWorld = ( function () { - var position = new THREE.Vector3(); - var quaternion = new THREE.Quaternion(); - var scale = new THREE.Vector3(); + var position = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); + var scale = new THREE.Vector3(); - var orientation = new THREE.Vector3(); + var orientation = new THREE.Vector3(); - return function (force) { + return function updateMatrixWorld( force ) { - THREE.Object3D.prototype.updateMatrixWorld.call(this, force); + THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); - var listener = this.context.listener; - var up = this.up; + var listener = this.context.listener; + var up = this.up; - this.matrixWorld.decompose(position, quaternion, scale); + this.matrixWorld.decompose( position, quaternion, scale ); - orientation.set(0, 0, -1).applyQuaternion(quaternion); + orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - listener.setPosition(position.x, position.y, position.z); - listener.setOrientation(orientation.x, orientation.y, orientation.z, up.x, up.y, up.z); + listener.setPosition( position.x, position.y, position.z ); + listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); - }; + }; -})(); +} )(); // File:src/extras/core/Curve.js @@ -27077,7 +29552,7 @@ THREE.AudioListener.prototype.updateMatrixWorld = (function () { **/ /************************************************************** - * Abstract Curve base class + * Abstract Curve base class **************************************************************/ THREE.Curve = function () { @@ -27087,56 +29562,56 @@ THREE.Curve = function () { // Virtual base class method to overwrite and implement in subclasses // - t [0 .. 1] -THREE.Curve.prototype.getPoint = function (t) { +THREE.Curve.prototype.getPoint = function ( t ) { - THREE.warn("THREE.Curve: Warning, getPoint() not implemented!"); - return null; + console.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); + return null; }; // Get point at relative position in curve according to arc length // - u [0 .. 1] -THREE.Curve.prototype.getPointAt = function (u) { +THREE.Curve.prototype.getPointAt = function ( u ) { - var t = this.getUtoTmapping(u); - return this.getPoint(t); + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); }; // Get sequence of points using getPoint( t ) -THREE.Curve.prototype.getPoints = function (divisions) { +THREE.Curve.prototype.getPoints = function ( divisions ) { - if (!divisions) divisions = 5; + if ( ! divisions ) divisions = 5; - var d, pts = []; + var d, pts = []; - for (d = 0; d <= divisions; d++) { + for ( d = 0; d <= divisions; d ++ ) { - pts.push(this.getPoint(d / divisions)); + pts.push( this.getPoint( d / divisions ) ); - } + } - return pts; + return pts; }; // Get sequence of points using getPointAt( u ) -THREE.Curve.prototype.getSpacedPoints = function (divisions) { +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { - if (!divisions) divisions = 5; + if ( ! divisions ) divisions = 5; - var d, pts = []; + var d, pts = []; - for (d = 0; d <= divisions; d++) { + for ( d = 0; d <= divisions; d ++ ) { - pts.push(this.getPointAt(d / divisions)); + pts.push( this.getPointAt( d / divisions ) ); - } + } - return pts; + return pts; }; @@ -27144,133 +29619,135 @@ THREE.Curve.prototype.getSpacedPoints = function (divisions) { THREE.Curve.prototype.getLength = function () { - var lengths = this.getLengths(); - return lengths[lengths.length - 1]; + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; }; // Get list of cumulative segment lengths -THREE.Curve.prototype.getLengths = function (divisions) { +THREE.Curve.prototype.getLengths = function ( divisions ) { - if (!divisions) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; + if ( ! divisions ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200; - if (this.cacheArcLengths - && ( this.cacheArcLengths.length == divisions + 1 ) - && !this.needsUpdate) { + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length === divisions + 1 ) + && ! this.needsUpdate ) { - //THREE.log( "cached", this.cacheArcLengths ); - return this.cacheArcLengths; + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; - } + } - this.needsUpdate = false; + this.needsUpdate = false; - var cache = []; - var current, last = this.getPoint(0); - var p, sum = 0; + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - cache.push(0); + cache.push( 0 ); - for (p = 1; p <= divisions; p++) { + for ( p = 1; p <= divisions; p ++ ) { - current = this.getPoint(p / divisions); - sum += current.distanceTo(last); - cache.push(sum); - last = current; + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - } + } - this.cacheArcLengths = cache; + this.cacheArcLengths = cache; - return cache; // { sums: cache, sum:sum }; Sum is in the last element. + return cache; // { sums: cache, sum:sum }; Sum is in the last element. }; -THREE.Curve.prototype.updateArcLengths = function () { - this.needsUpdate = true; - this.getLengths(); +THREE.Curve.prototype.updateArcLengths = function() { + + this.needsUpdate = true; + this.getLengths(); + }; -// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant -THREE.Curve.prototype.getUtoTmapping = function (u, distance) { +THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { - var arcLengths = this.getLengths(); + var arcLengths = this.getLengths(); - var i = 0, il = arcLengths.length; + var i = 0, il = arcLengths.length; - var targetArcLength; // The targeted u distance value to get + var targetArcLength; // The targeted u distance value to get - if (distance) { + if ( distance ) { - targetArcLength = distance; + targetArcLength = distance; - } else { + } else { - targetArcLength = u * arcLengths[il - 1]; + targetArcLength = u * arcLengths[ il - 1 ]; - } + } - //var time = Date.now(); + //var time = Date.now(); - // binary search for the index with largest value smaller than target u distance + // binary search for the index with largest value smaller than target u distance - var low = 0, high = il - 1, comparison; + var low = 0, high = il - 1, comparison; - while (low <= high) { + while ( low <= high ) { - 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 + 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 - comparison = arcLengths[i] - targetArcLength; + comparison = arcLengths[ i ] - targetArcLength; - if (comparison < 0) { + if ( comparison < 0 ) { - low = i + 1; + low = i + 1; - } else if (comparison > 0) { + } else if ( comparison > 0 ) { - high = i - 1; + high = i - 1; - } else { + } else { - high = i; - break; + high = i; + break; - // DONE + // DONE - } + } - } + } - i = high; + i = high; - //THREE.log('b' , i, low, high, Date.now()- time); + //console.log('b' , i, low, high, Date.now()- time); - if (arcLengths[i] == targetArcLength) { + if ( arcLengths[ i ] === targetArcLength ) { - var t = i / ( il - 1 ); - return t; + var t = i / ( il - 1 ); + return t; - } + } - // we could get finer grain at lengths, or use simple interpolatation between two points + // we could get finer grain at lengths, or use simple interpolation between two points - var lengthBefore = arcLengths[i]; - var lengthAfter = arcLengths[i + 1]; + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - var segmentLength = lengthAfter - lengthBefore; + var segmentLength = lengthAfter - lengthBefore; - // determine where we are between the 'before' and 'after' points + // determine where we are between the 'before' and 'after' points - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - // add that fractional amount to t + // add that fractional amount to t - var t = ( i + segmentFraction ) / ( il - 1 ); + var t = ( i + segmentFraction ) / ( il - 1 ); - return t; + return t; }; @@ -27279,81 +29756,84 @@ THREE.Curve.prototype.getUtoTmapping = function (u, distance) { // 2 points a small delta apart will be used to find its gradient // which seems to give a reasonable approximation -THREE.Curve.prototype.getTangent = function (t) { +THREE.Curve.prototype.getTangent = function( t ) { - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - // Capping in case of danger + // Capping in case of danger - if (t1 < 0) t1 = 0; - if (t2 > 1) t2 = 1; + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - var pt1 = this.getPoint(t1); - var pt2 = this.getPoint(t2); + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - var vec = pt2.clone().sub(pt1); - return vec.normalize(); + var vec = pt2.clone().sub( pt1 ); + return vec.normalize(); }; -THREE.Curve.prototype.getTangentAt = function (u) { +THREE.Curve.prototype.getTangentAt = function ( u ) { - var t = this.getUtoTmapping(u); - return this.getTangent(t); + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); }; + + + /************************************************************** - * Utils + * Utils **************************************************************/ THREE.Curve.Utils = { - tangentQuadraticBezier: function (t, p0, p1, p2) { + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { - return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); - }, + }, - // Puay Bing, thanks for helping with this derivative! + // Puay Bing, thanks for helping with this derivative! - tangentCubicBezier: function (t, p0, p1, p2, p3) { + tangentCubicBezier: function ( t, p0, p1, p2, p3 ) { - 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; + 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; - }, + }, - tangentSpline: function (t, p0, p1, p2, p3) { + tangentSpline: function ( t, p0, p1, p2, p3 ) { - // To check if my formulas are correct + // 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 + 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 - return h00 + h10 + h01 + h11; + return h00 + h10 + h01 + h11; - }, + }, - // Catmull-Rom + // Catmull-Rom - interpolate: function (p0, p1, p2, p3, t) { + interpolate: function( p0, p1, p2, p3, t ) { - 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; + 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; - } + } }; @@ -27361,18 +29841,18 @@ THREE.Curve.Utils = { // TODO: Transformation for Curves? /************************************************************** - * 3D Curves + * 3D Curves **************************************************************/ // A Factory method for creating new curve subclasses -THREE.Curve.create = function (constructor, getPointFunc) { +THREE.Curve.create = function ( constructor, getPointFunc ) { - constructor.prototype = Object.create(THREE.Curve.prototype); - constructor.prototype.constructor = constructor; - constructor.prototype.getPoint = getPointFunc; + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.constructor = constructor; + constructor.prototype.getPoint = getPointFunc; - return constructor; + return constructor; }; @@ -27383,3203 +29863,2673 @@ THREE.Curve.create = function (constructor, getPointFunc) { * **/ -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - -THREE.CurvePath = function () { - - this.curves = []; - this.bends = []; - - this.autoClose = false; // Automatically closes the path -}; - -THREE.CurvePath.prototype = Object.create(THREE.Curve.prototype); -THREE.CurvePath.prototype.constructor = THREE.CurvePath; - -THREE.CurvePath.prototype.add = function (curve) { - - this.curves.push(curve); - -}; - -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)); - } - -}; - -// To get accurate point with reference to -// entire path distance at time t, -// following has to be done: - -// 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') - -THREE.CurvePath.prototype.getPoint = function (t) { - - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0, diff, curve; - - // To think about boundaries points. - - while (i < curveLengths.length) { - - if (curveLengths[i] >= d) { - - diff = curveLengths[i] - d; - curve = this.curves[i]; - - var u = 1 - diff / curve.getLength(); - - return curve.getPointAt(u); - - } - - i++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 maxX) maxX = p.x; - else if (p.x < minX) minX = p.x; - - if (p.y > maxY) maxY = p.y; - else if (p.y < minY) minY = p.y; - - if (v3) { - - if (p.z > maxZ) maxZ = p.z; - else if (p.z < minZ) minZ = p.z; - - } - - sum.add(p); - - } - - var ret = { - - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY - - }; - - if (v3) { - - ret.maxZ = maxZ; - ret.minZ = minZ; - - } - - return ret; - -}; - -/************************************************************** - * 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); - -}; - -// Generate geometry from equidistance sampling along the path - -THREE.CurvePath.prototype.createSpacedPointsGeometry = function (divisions) { - - var pts = this.getSpacedPoints(divisions, true); - return this.createGeometry(pts); - -}; - -THREE.CurvePath.prototype.createGeometry = function (points) { - - var geometry = new THREE.Geometry(); - - for (var i = 0; i < points.length; i++) { - - geometry.vertices.push(new THREE.Vector3(points[i].x, points[i].y, points[i].z || 0)); - - } - - return geometry; - -}; - - -/************************************************************** - * Bend / Wrap Helper Methods - **************************************************************/ - -// Wrap path / Bend modifiers? - -THREE.CurvePath.prototype.addWrapPath = function (bendpath) { - - this.bends.push(bendpath); - -}; - -THREE.CurvePath.prototype.getTransformedPoints = function (segments, bends) { - - var oldPts = this.getPoints(segments); // getPoints getSpacedPoints - var i, il; - - if (!bends) { - - bends = this.bends; - - } - - for (i = 0, il = bends.length; i < il; i++) { - - oldPts = this.getWrapPoints(oldPts, bends[i]); - - } - - return oldPts; - -}; - -THREE.CurvePath.prototype.getTransformedSpacedPoints = function (segments, bends) { - - var oldPts = this.getSpacedPoints(segments); - - var i, il; - - if (!bends) { - - bends = this.bends; - - } - - for (i = 0, il = bends.length; i < il; i++) { - - oldPts = this.getWrapPoints(oldPts, bends[i]); - - } - - return oldPts; - -}; - -// This returns getPoints() bend/wrapped around the contour of a path. -// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ -THREE.CurvePath.prototype.getWrapPoints = function (oldPts, path) { +THREE.CurvePath = function () { - var bounds = this.getBoundingBox(); + this.curves = []; + this.bends = []; - var i, il, p, oldX, oldY, xNorm; + this.autoClose = false; // Automatically closes the path - for (i = 0, il = oldPts.length; i < il; i++) { +}; - p = oldPts[i]; +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); +THREE.CurvePath.prototype.constructor = THREE.CurvePath; - oldX = p.x; - oldY = p.y; +THREE.CurvePath.prototype.add = function ( curve ) { - xNorm = oldX / bounds.maxX; + this.curves.push( curve ); - // 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 +}; - xNorm = path.getUtoTmapping(xNorm, oldX); +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 +}; - // check for out of bounds? +THREE.CurvePath.prototype.closePath = function() { - var pathPt = path.getPoint(xNorm); - var normal = path.getTangent(xNorm); - normal.set(-normal.y, normal.x).multiplyScalar(oldY); + // 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 ); - p.x = pathPt.x + normal.x; - p.y = pathPt.y + normal.y; + if ( ! startPoint.equals( endPoint ) ) { - } + this.curves.push( new THREE.LineCurve( endPoint, startPoint ) ); - return oldPts; + } }; +// To get accurate point with reference to +// entire path distance at time t, +// following has to be done: -// File:src/extras/core/Gyroscope.js +// 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') -/** - * @author alteredq / http://alteredqualia.com/ - */ +THREE.CurvePath.prototype.getPoint = function( t ) { -THREE.Gyroscope = function () { + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; - THREE.Object3D.call(this); + // To think about boundaries points. -}; + while ( i < curveLengths.length ) { -THREE.Gyroscope.prototype = Object.create(THREE.Object3D.prototype); -THREE.Gyroscope.prototype.constructor = THREE.Gyroscope; + if ( curveLengths[ i ] >= d ) { -THREE.Gyroscope.prototype.updateMatrixWorld = ( function () { + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; - var translationObject = new THREE.Vector3(); - var quaternionObject = new THREE.Quaternion(); - var scaleObject = new THREE.Vector3(); + var u = 1 - diff / curve.getLength(); - var translationWorld = new THREE.Vector3(); - var quaternionWorld = new THREE.Quaternion(); - var scaleWorld = new THREE.Vector3(); + return curve.getPointAt( u ); - return function (force) { + } - this.matrixAutoUpdate && this.updateMatrix(); + i ++; - // update matrixWorld + } - if (this.matrixWorldNeedsUpdate || force) { + return null; - if (this.parent) { + // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; - this.lineTo(vectors[v].x, vectors[v].y); + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; - } + if ( v3 ) { -}; + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; -// startPath() endPath()? + } -THREE.Path.prototype.moveTo = function (x, y) { + sum.add( p ); - var args = Array.prototype.slice.call(arguments); - this.actions.push({action: THREE.PathActions.MOVE_TO, args: args}); + } -}; + var ret = { -THREE.Path.prototype.lineTo = function (x, y) { + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY - var args = Array.prototype.slice.call(arguments); + }; - var lastargs = this.actions[this.actions.length - 1].args; + if ( v3 ) { - var x0 = lastargs[lastargs.length - 2]; - var y0 = lastargs[lastargs.length - 1]; + ret.maxZ = maxZ; + ret.minZ = minZ; - 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}); + return ret; }; -THREE.Path.prototype.quadraticCurveTo = function (aCPx, aCPy, aX, aY) { +/************************************************************** + * Create Geometries Helpers + **************************************************************/ + +/// Generate geometry from path points (for Line or Points objects) + +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { - var args = Array.prototype.slice.call(arguments); + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); - var lastargs = this.actions[this.actions.length - 1].args; +}; - var x0 = lastargs[lastargs.length - 2]; - var y0 = lastargs[lastargs.length - 1]; +// Generate geometry from equidistant sampling along the path - var curve = new THREE.QuadraticBezierCurve(new THREE.Vector2(x0, y0), - new THREE.Vector2(aCPx, aCPy), - new THREE.Vector2(aX, aY)); - this.curves.push(curve); +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { - this.actions.push({action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args}); + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); }; -THREE.Path.prototype.bezierCurveTo = function (aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { +THREE.CurvePath.prototype.createGeometry = function( points ) { - var args = Array.prototype.slice.call(arguments); + var geometry = new THREE.Geometry(); - var lastargs = this.actions[this.actions.length - 1].args; + for ( var i = 0; i < points.length; i ++ ) { - var x0 = lastargs[lastargs.length - 2]; - var y0 = lastargs[lastargs.length - 1]; + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0 ) ); - 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}); + return geometry; }; -THREE.Path.prototype.splineThru = function (pts /*Array of Vector*/) { - var args = Array.prototype.slice.call(arguments); - var lastargs = this.actions[this.actions.length - 1].args; +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ - 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); +// Wrap path / Bend modifiers? - var curve = new THREE.SplineCurve(npts); - this.curves.push(curve); +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { - this.actions.push({action: THREE.PathActions.CSPLINE_THRU, args: args}); + this.bends.push( bendpath ); }; -// FUTURE: Change the API or follow canvas API? +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { -THREE.Path.prototype.arc = function (aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; - var lastargs = this.actions[this.actions.length - 1].args; - var x0 = lastargs[lastargs.length - 2]; - var y0 = lastargs[lastargs.length - 1]; + if ( ! bends ) { - this.absarc(aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise); + bends = this.bends; -}; + } -THREE.Path.prototype.absarc = function (aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); -}; + for ( i = 0, il = bends.length; i < il; i ++ ) { -THREE.Path.prototype.ellipse = function (aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise) { + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - var lastargs = this.actions[this.actions.length - 1].args; - var x0 = lastargs[lastargs.length - 2]; - var y0 = lastargs[lastargs.length - 1]; + } - this.absellipse(aX + x0, aY + y0, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise); + return oldPts; }; +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { -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); - - var lastPoint = curve.getPoint(1); - args.push(lastPoint.x); - args.push(lastPoint.y); + var oldPts = this.getSpacedPoints( segments ); - this.actions.push({action: THREE.PathActions.ELLIPSE, args: args}); + var i, il; -}; + if ( ! bends ) { -THREE.Path.prototype.getSpacedPoints = function (divisions, closedPath) { + bends = this.bends; - if (!divisions) divisions = 40; + } - var points = []; + for ( i = 0, il = bends.length; i < il; i ++ ) { - for (var i = 0; i < divisions; i++) { + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - points.push(this.getPoint(i / divisions)); + } - //if( !this.getPoint( i / divisions ) ) throw "DIE"; + return oldPts; - } +}; - // if ( closedPath ) { - // - // points.push( points[ 0 ] ); - // - // } +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html - return points; +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { -}; + var bounds = this.getBoundingBox(); -/* Return an array of vectors based on contour of the path */ + var i, il, p, oldX, oldY, xNorm; -THREE.Path.prototype.getPoints = function (divisions, closedPath) { + for ( i = 0, il = oldPts.length; i < il; i ++ ) { - if (this.useSpacedPoints) { - THREE.log('tata'); - return this.getSpacedPoints(divisions, closedPath); - } + p = oldPts[ i ]; - divisions = divisions || 12; + oldX = p.x; + oldY = p.y; - var points = []; + xNorm = oldX / bounds.maxX; - var i, il, item, action, args; - var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, - laste, j, - t, tx, ty; + // 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 - for (i = 0, il = this.actions.length; i < il; i++) { + xNorm = path.getUtoTmapping( xNorm, oldX ); - item = this.actions[i]; + // check for out of bounds? - action = item.action; - args = item.args; + var pathPt = path.getPoint( xNorm ); + var normal = path.getTangent( xNorm ); + normal.set( - normal.y, normal.x ).multiplyScalar( oldY ); - switch (action) { + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; - case THREE.PathActions.MOVE_TO: + } - points.push(new THREE.Vector2(args[0], args[1])); + return oldPts; - break; +}; - case THREE.PathActions.LINE_TO: +// File:src/extras/core/Path.js - points.push(new THREE.Vector2(args[0], args[1])); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ - break; +THREE.Path = function ( points ) { - case THREE.PathActions.QUADRATIC_CURVE_TO: + THREE.CurvePath.call( this ); - cpx = args[2]; - cpy = args[3]; + this.actions = []; - cpx1 = args[0]; - cpy1 = args[1]; + if ( points ) { - if (points.length > 0) { + this.fromPoints( points ); - laste = points[points.length - 1]; + } - cpx0 = laste.x; - cpy0 = laste.y; +}; - } else { +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); +THREE.Path.prototype.constructor = THREE.Path; - laste = this.actions[i - 1].args; +THREE.PathActions = { - cpx0 = laste[laste.length - 2]; - cpy0 = laste[laste.length - 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 - for (j = 1; j <= divisions; j++) { +// Create path using straight lines to connect all points +// - vectors: array of Vector2 - t = j / divisions; +THREE.Path.prototype.fromPoints = function ( vectors ) { - tx = THREE.Shape.Utils.b2(t, cpx0, cpx1, cpx); - ty = THREE.Shape.Utils.b2(t, cpy0, cpy1, cpy); + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - points.push(new THREE.Vector2(tx, ty)); + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { - } + this.lineTo( vectors[ v ].x, vectors[ v ].y ); - break; + } - case THREE.PathActions.BEZIER_CURVE_TO: +}; - cpx = args[4]; - cpy = args[5]; +// startPath() endPath()? - cpx1 = args[0]; - cpy1 = args[1]; +THREE.Path.prototype.moveTo = function ( x, y ) { - cpx2 = args[2]; - cpy2 = args[3]; + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); - if (points.length > 0) { +}; - laste = points[points.length - 1]; +THREE.Path.prototype.lineTo = function ( x, y ) { - cpx0 = laste.x; - cpy0 = laste.y; + var args = Array.prototype.slice.call( arguments ); - } else { + var lastargs = this.actions[ this.actions.length - 1 ].args; - laste = this.actions[i - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - cpx0 = laste[laste.length - 2]; - cpy0 = laste[laste.length - 1]; + 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 } ); +}; - for (j = 1; j <= divisions; j++) { +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { - t = j / divisions; + var args = Array.prototype.slice.call( arguments ); - tx = THREE.Shape.Utils.b3(t, cpx0, cpx1, cpx2, cpx); - ty = THREE.Shape.Utils.b3(t, cpy0, cpy1, cpy2, cpy); + var lastargs = this.actions[ this.actions.length - 1 ].args; - points.push(new THREE.Vector2(tx, ty)); + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - } + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); - break; + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); - case THREE.PathActions.CSPLINE_THRU: +}; - laste = this.actions[i - 1].args; +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { - var last = new THREE.Vector2(laste[laste.length - 2], laste[laste.length - 1]); - var spts = [last]; + var args = Array.prototype.slice.call( arguments ); - var n = divisions * args[0].length; + var lastargs = this.actions[ this.actions.length - 1 ].args; - spts = spts.concat(args[0]); + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - var spline = new THREE.SplineCurve(spts); + 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 ); - for (j = 1; j <= n; j++) { + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); - points.push(spline.getPointAt(j / n)); +}; - } +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { - break; + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; - case THREE.PathActions.ARC: + 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 aX = args[0], aY = args[1], - aRadius = args[2], - aStartAngle = args[3], aEndAngle = args[4], - aClockwise = !!args[5]; + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); - for (j = 1; j <= tdivisions; j++) { +}; - t = j / tdivisions; +// FUTURE: Change the API or follow canvas API? - if (!aClockwise) { +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { - t = 1 - t; + 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 ); - angle = aStartAngle + t * deltaAngle; + }; - tx = aX + aRadius * Math.cos(angle); - ty = aY + aRadius * Math.sin(angle); + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { - //THREE.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - points.push(new THREE.Vector2(tx, ty)); + }; - } +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise, aRotation ) { - //THREE.log(points); + var lastargs = this.actions[ this.actions.length - 1 ].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; - break; + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise, aRotation ); - case THREE.PathActions.ELLIPSE: + }; - var aX = args[0], aY = args[1], - xRadius = args[2], - yRadius = args[3], - aStartAngle = args[4], aEndAngle = args[5], - aClockwise = !!args[6]; +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise, aRotation ) { - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; + var args = [ + aX, aY, + xRadius, yRadius, + aStartAngle, aEndAngle, + aClockwise, + aRotation || 0 // aRotation is optional. + ]; + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise, aRotation ); + this.curves.push( curve ); - for (j = 1; j <= tdivisions; j++) { + var lastPoint = curve.getPoint( 1 ); + args.push( lastPoint.x ); + args.push( lastPoint.y ); - t = j / tdivisions; + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); - if (!aClockwise) { + }; - t = 1 - t; +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { - } + if ( ! divisions ) divisions = 40; - angle = aStartAngle + t * deltaAngle; + var points = []; - tx = aX + xRadius * Math.cos(angle); - ty = aY + yRadius * Math.sin(angle); + for ( var i = 0; i < divisions; i ++ ) { - //THREE.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + points.push( this.getPoint( i / divisions ) ); - points.push(new THREE.Vector2(tx, ty)); + //if( !this.getPoint( i / divisions ) ) throw "DIE"; - } + } - //THREE.log(points); + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } - break; + return points; - } // end switch +}; - } +/* Return an array of vectors based on contour of the path */ +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { - // 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) { + if ( this.useSpacedPoints ) { - points.push(points[0]); + return this.getSpacedPoints( divisions, closedPath ); - } + } - return points; + divisions = divisions || 12; -}; + var points = []; -// -// 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 i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; -THREE.Path.prototype.toShapes = function (isCCW, noHoles) { + for ( i = 0, il = this.actions.length; i < il; i ++ ) { - function extractSubpaths(inActions) { + item = this.actions[ i ]; - var i, il, item, action, args; + action = item.action; + args = item.args; - var subPaths = [], lastPath = new THREE.Path(); + switch ( action ) { - for (i = 0, il = inActions.length; i < il; i++) { + case THREE.PathActions.MOVE_TO: - item = inActions[i]; + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - args = item.args; - action = item.action; + break; - if (action == THREE.PathActions.MOVE_TO) { + case THREE.PathActions.LINE_TO: - if (lastPath.actions.length != 0) { + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - subPaths.push(lastPath); - lastPath = new THREE.Path(); + break; - } + case THREE.PathActions.QUADRATIC_CURVE_TO: - } + cpx = args[ 2 ]; + cpy = args[ 3 ]; - lastPath[action].apply(lastPath, args); + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; - } + if ( points.length > 0 ) { - if (lastPath.actions.length != 0) { + laste = points[ points.length - 1 ]; - subPaths.push(lastPath); + cpx0 = laste.x; + cpy0 = laste.y; - } + } else { - // THREE.log(subPaths); + laste = this.actions[ i - 1 ].args; - return subPaths; - } + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - function toShapesNoHoles(inSubpaths) { + } - var shapes = []; + for ( j = 1; j <= divisions; j ++ ) { - for (var i = 0, il = inSubpaths.length; i < il; i++) { + t = j / divisions; - var tmpPath = inSubpaths[i]; + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - var tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; + points.push( new THREE.Vector2( tx, ty ) ); - shapes.push(tmpShape); - } + } - //THREE.log("shape", shapes); + break; - return shapes; - } + case THREE.PathActions.BEZIER_CURVE_TO: - function isPointInsidePolygon(inPt, inPolygon) { - var EPSILON = 0.0000000001; - - var polyLen = inPolygon.length; - - // 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]; - - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; - - 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; - } + cpx = args[ 4 ]; + cpy = args[ 5 ]; + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; - var subPaths = extractSubpaths(this.actions); - if (subPaths.length == 0) return []; + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; - if (noHoles === true) return toShapesNoHoles(subPaths); + if ( points.length > 0 ) { + laste = points[ points.length - 1 ]; - var solid, tmpPath, tmpShape, shapes = []; + cpx0 = laste.x; + cpy0 = laste.y; - if (subPaths.length == 1) { + } else { - tmpPath = subPaths[0]; - tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - shapes.push(tmpShape); - return shapes; + laste = this.actions[ i - 1 ].args; - } + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; - var holesFirst = !THREE.Shape.Utils.isClockWise(subPaths[0].getPoints()); - holesFirst = isCCW ? !holesFirst : holesFirst; + } - // THREE.log("Holes first", holesFirst); - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; + for ( j = 1; j <= divisions; j ++ ) { - newShapes[mainIdx] = undefined; - newShapeHoles[mainIdx] = []; + t = j / divisions; - var i, il; + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - for (i = 0, il = subPaths.length; i < il; i++) { + points.push( new THREE.Vector2( tx, ty ) ); - tmpPath = subPaths[i]; - tmpPoints = tmpPath.getPoints(); - solid = THREE.Shape.Utils.isClockWise(tmpPoints); - solid = isCCW ? !solid : solid; + } - if (solid) { + break; - if ((!holesFirst ) && ( newShapes[mainIdx] )) mainIdx++; + case THREE.PathActions.CSPLINE_THRU: - newShapes[mainIdx] = {s: new THREE.Shape(), p: tmpPoints}; - newShapes[mainIdx].s.actions = tmpPath.actions; - newShapes[mainIdx].s.curves = tmpPath.curves; + laste = this.actions[ i - 1 ].args; - if (holesFirst) mainIdx++; - newShapeHoles[mainIdx] = []; + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; - //THREE.log('cw', i); + var n = divisions * args[ 0 ].length; - } else { + spts = spts.concat( args[ 0 ] ); - newShapeHoles[mainIdx].push({h: tmpPath, p: tmpPoints[0]}); + var spline = new THREE.SplineCurve( spts ); - //THREE.log('ccw', i); + for ( j = 1; j <= n; j ++ ) { - } + points.push( spline.getPointAt( j / n ) ); - } + } - // only Holes? -> probably all Shapes with wrong orientation - if (!newShapes[0]) return toShapesNoHoles(subPaths); - - - if (newShapes.length > 1) { - var ambigious = false; - var toChange = []; - - 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); - } - } - } - // THREE.log("ambigious: ", ambigious); - if (toChange.length > 0) { - // THREE.log("to change: ", toChange); - if (!ambigious) newShapeHoles = betterShapeHoles; - } - } + break; - 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); - } - } + case THREE.PathActions.ARC: - //THREE.log("shape", shapes); + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !! args[ 5 ]; - return shapes; + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; -}; + for ( j = 1; j <= tdivisions; j ++ ) { -// File:src/extras/core/Shape.js + t = j / tdivisions; -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + if ( ! aClockwise ) { -// 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. + t = 1 - t; -THREE.Shape = function () { + } - THREE.Path.apply(this, arguments); - this.holes = []; + angle = aStartAngle + t * deltaAngle; -}; + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); -THREE.Shape.prototype = Object.create(THREE.Path.prototype); -THREE.Shape.prototype.constructor = THREE.Shape; + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); -// Convenience method to return ExtrudeGeometry + points.push( new THREE.Vector2( tx, ty ) ); -THREE.Shape.prototype.extrude = function (options) { + } - var extruded = new THREE.ExtrudeGeometry(this, options); - return extruded; + //console.log(points); -}; + break; -// Convenience method to return ShapeGeometry + case THREE.PathActions.ELLIPSE: -THREE.Shape.prototype.makeGeometry = function (options) { + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !! args[ 6 ], + aRotation = args[ 7 ]; - var geometry = new THREE.ShapeGeometry(this, options); - return geometry; -}; + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; -// Get points of holes + var cos, sin; + if ( aRotation !== 0 ) { + + cos = Math.cos( aRotation ); + sin = Math.sin( aRotation ); -THREE.Shape.prototype.getPointsHoles = function (divisions) { + } - var i, il = this.holes.length, holesPts = []; + for ( j = 1; j <= tdivisions; j ++ ) { - for (i = 0; i < il; i++) { + t = j / tdivisions; - holesPts[i] = this.holes[i].getTransformedPoints(divisions, this.bends); + if ( ! aClockwise ) { - } + t = 1 - t; - return holesPts; + } -}; + angle = aStartAngle + t * deltaAngle; -// Get points of holes (spaced by regular distance) + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); -THREE.Shape.prototype.getSpacedPointsHoles = function (divisions) { + if ( aRotation !== 0 ) { - var i, il = this.holes.length, holesPts = []; + var x = tx, y = ty; - for (i = 0; i < il; i++) { + // Rotate the point about the center of the ellipse. + tx = ( x - aX ) * cos - ( y - aY ) * sin + aX; + ty = ( x - aX ) * sin + ( y - aY ) * cos + aY; - holesPts[i] = this.holes[i].getTransformedSpacedPoints(divisions, this.bends); + } - } + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - return holesPts; + points.push( new THREE.Vector2( tx, ty ) ); -}; + } + //console.log(points); -// Get points of shape and holes (keypoints based on segments parameter) + break; -THREE.Shape.prototype.extractAllPoints = function (divisions) { + } // end switch - return { + } - shape: this.getTransformedPoints(divisions), - holes: this.getPointsHoles(divisions) - }; -}; + // 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 ) { -THREE.Shape.prototype.extractPoints = function (divisions) { + points.push( points[ 0 ] ); - if (this.useSpacedPoints) { - return this.extractAllSpacedPoints(divisions); - } + } - return this.extractAllPoints(divisions); + return points; }; // -// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { -// -// return { +// Breaks path into shapes // -// shape: this.transform( bend, divisions ), -// holes: this.getPointsHoles( divisions, bend ) +// 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 // -// }; - -// Get points of shape and holes (spaced by regular distance) -THREE.Shape.prototype.extractAllSpacedPoints = function (divisions) { +THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { - return { + function extractSubpaths( inActions ) { - shape: this.getTransformedSpacedPoints(divisions), - holes: this.getSpacedPointsHoles(divisions) + var i, il, item, action, args; - }; + var subPaths = [], lastPath = new THREE.Path(); -}; - -/************************************************************** - * Utils - **************************************************************/ + for ( i = 0, il = inActions.length; i < il; i ++ ) { -THREE.Shape.Utils = { - - triangulateShape: function (contour, holes) { - - 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 ) ); - } - } - } - - function intersect_segments_2D(inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs) { - var EPSILON = 0.0000000001; - - var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; - var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; - - var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; - var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; - - var limit = seg1dy * seg2dx - seg1dx * seg2dy; - var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; - - if (Math.abs(limit) > EPSILON) { // not parallel - - 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 []; - } - - // 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; - } - } - 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]; - } - } - } - - function isPointInsideAngle(inVertex, inLegFromPt, inLegToPt, inOtherPt) { - // The order of legs is important - - 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; - - // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. - var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; - var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - - if (Math.abs(from2toAngle) > EPSILON) { // angle != 180 deg. - - var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; - // THREE.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - - 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. - // THREE.log( "from2to: 180 deg., from2other: " + from2otherAngle ); - return ( from2otherAngle > 0 ); - } - } - - - function removeHoles(contour, holes) { - - var shape = contour.concat(); // work on this shape - var hole; - - function isCutLineInsideAngles(inShapeIdx, inHoleIdx) { - // Check if hole point lies within angle around shape point - var lastShapeIdx = shape.length - 1; - - var prevShapeIdx = inShapeIdx - 1; - if (prevShapeIdx < 0) prevShapeIdx = lastShapeIdx; - - var nextShapeIdx = inShapeIdx + 1; - if (nextShapeIdx > lastShapeIdx) nextShapeIdx = 0; - - var insideAngle = isPointInsideAngle(shape[inShapeIdx], shape[prevShapeIdx], shape[nextShapeIdx], hole[inHoleIdx]); - if (!insideAngle) { - // THREE.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); - return false; - } - - // Check if shape point lies within angle around hole point - var lastHoleIdx = hole.length - 1; - - var prevHoleIdx = inHoleIdx - 1; - if (prevHoleIdx < 0) prevHoleIdx = lastHoleIdx; - - var nextHoleIdx = inHoleIdx + 1; - if (nextHoleIdx > lastHoleIdx) nextHoleIdx = 0; - - insideAngle = isPointInsideAngle(hole[inHoleIdx], hole[prevHoleIdx], hole[nextHoleIdx], shape[inShapeIdx]); - if (!insideAngle) { - // THREE.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); - return false; - } - - return true; - } - - 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; - } - - return false; - } - - 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; - } + item = inActions[ i ]; - var holeIndex, shapeIndex, - shapePt, holePt, - holeIdx, cutKey, failedCuts = [], - tmpShape1, tmpShape2, - tmpHole1, tmpHole2; + args = item.args; + action = item.action; - for (var h = 0, hl = holes.length; h < hl; h++) { + if ( action === THREE.PathActions.MOVE_TO ) { - indepHoles.push(h); + if ( lastPath.actions.length !== 0 ) { - } + subPaths.push( lastPath ); + lastPath = new THREE.Path(); - var minShapeIndex = 0; - var counter = indepHoles.length * 2; - while (indepHoles.length > 0) { - counter--; - if (counter < 0) { - THREE.log("Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!"); - break; - } + } - // search for shape-vertex and hole-vertex, - // which can be connected without intersections - for (shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex++) { + } - shapePt = shape[shapeIndex]; - holeIndex = -1; + lastPath[ action ].apply( lastPath, args ); - // search for hole which can be reached without intersections - for (var h = 0; h < indepHoles.length; h++) { - holeIdx = indepHoles[h]; + } - // prevent multiple checks - cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; - if (failedCuts[cutKey] !== undefined) continue; + if ( lastPath.actions.length !== 0 ) { - 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; + subPaths.push( lastPath ); - holeIndex = h2; - indepHoles.splice(h, 1); + } - tmpShape1 = shape.slice(0, shapeIndex + 1); - tmpShape2 = shape.slice(shapeIndex); - tmpHole1 = hole.slice(holeIndex); - tmpHole2 = hole.slice(0, holeIndex + 1); + // console.log(subPaths); - shape = tmpShape1.concat(tmpHole1).concat(tmpHole2).concat(tmpShape2); + return subPaths; - minShapeIndex = shapeIndex; + } - // Debug only, to show the selected cuts - // glob_CutLines.push( [ shapePt, holePt ] ); + function toShapesNoHoles( inSubpaths ) { - break; - } - if (holeIndex >= 0) break; // hole-vertex found + var shapes = []; - failedCuts[cutKey] = true; // remember failure - } - if (holeIndex >= 0) break; // hole-vertex found - } - } + for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) { - return shape; - /* shape with no holes */ - } + var tmpPath = inSubpaths[ i ]; + var tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; - var i, il, f, face, - key, index, - allPointsMap = {}; + shapes.push( tmpShape ); - // 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. + } - var allpoints = contour.concat(); + //console.log("shape", shapes); - for (var h = 0, hl = holes.length; h < hl; h++) { + return shapes; - Array.prototype.push.apply(allpoints, holes[h]); + } - } + function isPointInsidePolygon( inPt, inPolygon ) { - //THREE.log( "allpoints",allpoints, allpoints.length ); + var EPSILON = 0.0000000001; - // prepare all points map + var polyLen = inPolygon.length; - for (i = 0, il = allpoints.length; i < il; i++) { + // 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 ++ ) { - key = allpoints[i].x + ":" + allpoints[i].y; + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; - if (allPointsMap[key] !== undefined) { + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; - THREE.warn("THREE.Shape: Duplicate point", key); + if ( Math.abs( edgeDy ) > EPSILON ) { - } + // not parallel + if ( edgeDy < 0 ) { - allPointsMap[key] = i; + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - } + } + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - // remove holes by cutting paths to holes and adding them to the shape - var shapeWithoutHoles = removeHoles(contour, holes); + if ( inPt.y === edgeLowPt.y ) { - var triangles = THREE.FontUtils.Triangulate(shapeWithoutHoles, false); // True returns indices for points of spooled shape - //THREE.log( "triangles",triangles, triangles.length ); + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! - // check all face vertices against all points map + } else { - for (i = 0, il = triangles.length; i < il; i++) { + 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 - face = triangles[i]; + } - for (f = 0; f < 3; f++) { + } else { - key = face[f].x + ":" + face[f].y; + // parallel or collinear + if ( inPt.y !== edgeLowPt.y ) continue; // parallel + // edge 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; - index = allPointsMap[key]; + } - if (index !== undefined) { + } - face[f] = index; + return inside; - } + } - } - } + var subPaths = extractSubpaths( this.actions ); + if ( subPaths.length === 0 ) return []; - return triangles.concat(); + if ( noHoles === true ) return toShapesNoHoles( subPaths ); - }, - isClockWise: function (pts) { + var solid, tmpPath, tmpShape, shapes = []; - return THREE.FontUtils.Triangulate.area(pts) < 0; + if ( subPaths.length === 1 ) { - }, + tmpPath = subPaths[ 0 ]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - // Bezier Curves formulas obtained from - // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + } - // Quad Bezier Functions + var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - b2p0: function (t, p) { + // console.log("Holes first", holesFirst); - var k = 1 - t; - return k * k * p; + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; - }, + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; - b2p1: function (t, p) { + var i, il; - return 2 * ( 1 - t ) * t * p; + 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; - b2p2: function (t, p) { + if ( solid ) { - return t * t * p; + 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; - b2: function (t, p0, p1, p2) { + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; - return this.b2p0(t, p0) + this.b2p1(t, p1) + this.b2p2(t, p2); + //console.log('cw', i); - }, + } else { - // Cubic Bezier Functions + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - b3p0: function (t, p) { + //console.log('ccw', i); - var k = 1 - t; - return k * k * k * p; + } - }, + } - b3p1: function (t, p) { + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - var k = 1 - t; - return 3 * k * k * t * p; - }, + if ( newShapes.length > 1 ) { - b3p2: function (t, p) { + var ambiguous = false; + var toChange = []; - var k = 1 - t; - return 3 * k * t * t * p; + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - }, + betterShapeHoles[ sIdx ] = []; - b3p3: function (t, p) { + } + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - return t * t * t * p; + 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 ++ ) { - b3: function (t, p0, p1, p2, p3) { + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - return this.b3p0(t, p0) + this.b3p1(t, p1) + this.b3p2(t, p2) + this.b3p3(t, p3); + if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); + if ( hole_unassigned ) { - } + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); -}; + } else { + ambiguous = true; -// File:src/extras/curves/LineCurve.js + } -/************************************************************** - * Line - **************************************************************/ + } -THREE.LineCurve = function (v1, v2) { + } + if ( hole_unassigned ) { - this.v1 = v1; - this.v2 = v2; + betterShapeHoles[ sIdx ].push( ho ); -}; + } -THREE.LineCurve.prototype = Object.create(THREE.Curve.prototype); -THREE.LineCurve.prototype.constructor = THREE.LineCurve; + } -THREE.LineCurve.prototype.getPoint = function (t) { + } + // console.log("ambiguous: ", ambiguous); + if ( toChange.length > 0 ) { - var point = this.v2.clone().sub(this.v1); - point.multiplyScalar(t).add(this.v1); + // console.log("to change: ", toChange); + if ( ! ambiguous ) newShapeHoles = betterShapeHoles; - return point; + } -}; + } -// Line curve is linear, so we can overwrite default getPointAt + var tmpHoles, j, jl; + for ( i = 0, il = newShapes.length; i < il; i ++ ) { -THREE.LineCurve.prototype.getPointAt = function (u) { + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; + for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - return this.getPoint(u); + tmpShape.holes.push( tmpHoles[ j ].h ); -}; + } -THREE.LineCurve.prototype.getTangent = function (t) { + } - var tangent = this.v2.clone().sub(this.v1); + //console.log("shape", shapes); - return tangent.normalize(); + return shapes; }; -// File:src/extras/curves/QuadraticBezierCurve.js +// File:src/extras/core/Shape.js -/************************************************************** - * Quadratic Bezier curve - **************************************************************/ +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ +// 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.QuadraticBezierCurve = function (v0, v1, v2) { +THREE.Shape = function () { - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + THREE.Path.apply( this, arguments ); + this.holes = []; }; -THREE.QuadraticBezierCurve.prototype = Object.create(THREE.Curve.prototype); -THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; - - -THREE.QuadraticBezierCurve.prototype.getPoint = function (t) { +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); +THREE.Shape.prototype.constructor = THREE.Shape; - var vector = new THREE.Vector2(); +// Convenience method to return ExtrudeGeometry - 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); +THREE.Shape.prototype.extrude = function ( options ) { - return vector; + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; }; +// Convenience method to return ShapeGeometry -THREE.QuadraticBezierCurve.prototype.getTangent = function (t) { - - var vector = new THREE.Vector2(); - - 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); - - // returns unit vector +THREE.Shape.prototype.makeGeometry = function ( options ) { - return vector.normalize(); + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; }; -// File:src/extras/curves/CubicBezierCurve.js - -/************************************************************** - * Cubic Bezier curve - **************************************************************/ +// Get points of holes -THREE.CubicBezierCurve = function (v0, v1, v2, v3) { +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + var i, il = this.holes.length, holesPts = []; -}; + for ( i = 0; i < il; i ++ ) { -THREE.CubicBezierCurve.prototype = Object.create(THREE.Curve.prototype); -THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); -THREE.CubicBezierCurve.prototype.getPoint = function (t) { + } - var tx, ty; + return holesPts; - 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); +// Get points of holes (spaced by regular distance) -}; +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { -THREE.CubicBezierCurve.prototype.getTangent = function (t) { + var i, il = this.holes.length, holesPts = []; - var tx, ty; + for ( i = 0; i < il; i ++ ) { - 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); + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); - var tangent = new THREE.Vector2(tx, ty); - tangent.normalize(); + } - return tangent; + return holesPts; }; -// File:src/extras/curves/SplineCurve.js - -/************************************************************** - * Spline curve - **************************************************************/ -THREE.SplineCurve = function (points /* array of Vector2 */) { +// Get points of shape and holes (keypoints based on segments parameter) - this.points = ( points == undefined ) ? [] : points; +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { -}; + return { -THREE.SplineCurve.prototype = Object.create(THREE.Curve.prototype); -THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) -THREE.SplineCurve.prototype.getPoint = function (t) { + }; - var points = this.points; - var point = ( points.length - 1 ) * t; +}; - var intPoint = Math.floor(point); - var weight = point - intPoint; +THREE.Shape.prototype.extractPoints = function ( divisions ) { - 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]; + if ( this.useSpacedPoints ) { - var vector = new THREE.Vector2(); + return this.extractAllSpacedPoints( divisions ); - 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); + } - return vector; + return this.extractAllPoints( divisions ); }; -// File:src/extras/curves/EllipseCurve.js - -/************************************************************** - * Ellipse curve - **************************************************************/ +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; -THREE.EllipseCurve = function (aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise) { +// Get points of shape and holes (spaced by regular distance) - this.aX = aX; - this.aY = aY; +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { - this.xRadius = xRadius; - this.yRadius = yRadius; + return { - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) - this.aClockwise = aClockwise; + }; }; -THREE.EllipseCurve.prototype = Object.create(THREE.Curve.prototype); -THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; +/************************************************************** + * Utils + **************************************************************/ -THREE.EllipseCurve.prototype.getPoint = function (t) { +THREE.Shape.Utils = { - var deltaAngle = this.aEndAngle - this.aStartAngle; + triangulateShape: function ( contour, holes ) { - if (deltaAngle < 0) deltaAngle += Math.PI * 2; - if (deltaAngle > Math.PI * 2) deltaAngle -= Math.PI * 2; + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { - var angle; + // inOtherPt needs to be collinear to the inSegment + if ( inSegPt1.x !== inSegPt2.x ) { - if (this.aClockwise === true) { + if ( inSegPt1.x < inSegPt2.x ) { - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); - } else { + } else { - angle = this.aStartAngle + t * deltaAngle; + return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); - } + } - var vector = new THREE.Vector2(); + } else { - vector.x = this.aX + this.xRadius * Math.cos(angle); - vector.y = this.aY + this.yRadius * Math.sin(angle); + if ( inSegPt1.y < inSegPt2.y ) { - return vector; + return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); -}; + } else { -// File:src/extras/curves/ArcCurve.js + return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); -/************************************************************** - * Arc curve - **************************************************************/ + } -THREE.ArcCurve = function (aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) { + } - THREE.EllipseCurve.call(this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); -}; + } -THREE.ArcCurve.prototype = Object.create(THREE.EllipseCurve.prototype); -THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; + function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { -// File:src/extras/curves/LineCurve3.js + var EPSILON = 0.0000000001; -/************************************************************** - * Line3D - **************************************************************/ + var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; + var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; -THREE.LineCurve3 = THREE.Curve.create( - function (v1, v2) { + var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; + var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; - this.v1 = v1; - this.v2 = v2; + var limit = seg1dy * seg2dx - seg1dx * seg2dy; + var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; - }, + if ( Math.abs( limit ) > EPSILON ) { - function (t) { + // not parallel - var vector = new THREE.Vector3(); + var perpSeg2; + if ( limit > 0 ) { - vector.subVectors(this.v2, this.v1); // diff - vector.multiplyScalar(t); - vector.add(this.v1); + if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; - return vector; + } else { - } -); + if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; -// File:src/extras/curves/QuadraticBezierCurve3.js + } -/************************************************************** - * Quadratic Bezier 3D curve - **************************************************************/ + // i.e. to reduce rounding errors + // intersection at endpoint of segment#1? + if ( perpSeg2 === 0 ) { -THREE.QuadraticBezierCurve3 = THREE.Curve.create( - function (v0, v1, v2) { + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; + return [ inSeg1Pt1 ]; - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + } + if ( perpSeg2 === limit ) { - }, + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; + return [ inSeg1Pt2 ]; - function (t) { + } + // intersection at endpoint of segment#2? + if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 === limit ) return [ inSeg2Pt2 ]; - var vector = new THREE.Vector3(); + // return real intersection point + var factorSeg1 = perpSeg2 / limit; + return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, + y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; - 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); + } else { - return vector; + // parallel or collinear + if ( ( perpSeg1 !== 0 ) || + ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return []; - } -); + // they are collinear or degenerate + var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point? + var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point? + // both segments are points + if ( seg1Pt && seg2Pt ) { -// File:src/extras/curves/CubicBezierCurve3.js + if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) || + ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points + return [ inSeg1Pt1 ]; // they are the same point -/************************************************************** - * Cubic Bezier 3D curve - **************************************************************/ + } + // segment#1 is a single point + if ( seg1Pt ) { -THREE.CubicBezierCurve3 = THREE.Curve.create( - function (v0, v1, v2, v3) { + if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 + return [ inSeg1Pt1 ]; - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + } + // 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 ]; - function (t) { + } - var vector = new THREE.Vector3(); + // they are collinear segments, which might overlap + var seg1min, seg1max, seg1minVal, seg1maxVal; + var seg2min, seg2max, seg2minVal, seg2maxVal; + if ( seg1dx !== 0 ) { - 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); + // the segments are NOT on a vertical line + if ( inSeg1Pt1.x < inSeg1Pt2.x ) { - return vector; + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; - } -); + } else { -// File:src/extras/curves/SplineCurve3.js + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; -/************************************************************** - * Spline 3D curve - **************************************************************/ + } + if ( inSeg2Pt1.x < inSeg2Pt2.x ) { + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; -THREE.SplineCurve3 = THREE.Curve.create( - function (points /* array of Vector3 */) { + } else { - this.points = ( points == undefined ) ? [] : points; + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; - }, + } - function (t) { + } else { - var points = this.points; - var point = ( points.length - 1 ) * t; + // the segments are on a vertical line + if ( inSeg1Pt1.y < inSeg1Pt2.y ) { - var intPoint = Math.floor(point); - var weight = point - intPoint; + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; - 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]; + } else { - var vector = new THREE.Vector3(); + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; - 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); + } + if ( inSeg2Pt1.y < inSeg2Pt2.y ) { - return vector; + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; - } -); + } else { -// File:src/extras/curves/ClosedSplineCurve3.js + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; -/************************************************************** - * Closed Spline 3D curve - **************************************************************/ + } + } + if ( seg1minVal <= seg2minVal ) { -THREE.ClosedSplineCurve3 = THREE.Curve.create( - function (points /* array of Vector3 */) { + if ( seg1maxVal < seg2minVal ) return []; + if ( seg1maxVal === seg2minVal ) { - this.points = ( points == undefined ) ? [] : points; + if ( inExcludeAdjacentSegs ) return []; + return [ seg2min ]; - }, + } + if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; + return [ seg2min, seg2max ]; - function (t) { + } else { - var points = this.points; - var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 + if ( seg1minVal > seg2maxVal ) return []; + if ( seg1minVal === seg2maxVal ) { - var intPoint = Math.floor(point); - var weight = point - intPoint; + if ( inExcludeAdjacentSegs ) return []; + return [ seg1min ]; - intPoint += intPoint > 0 ? 0 : ( Math.floor(Math.abs(intPoint) / points.length) + 1 ) * points.length; + } + if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; + return [ seg1min, seg2max ]; - 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]; + } - 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; + function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { - } -); + // The order of legs is important -// File:src/extras/animation/AnimationHandler.js + var EPSILON = 0.0000000001; -/** - * @author mikael emtinger / http://gomo.se/ - */ + // 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; -THREE.AnimationHandler = { + // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. + var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; + var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - LINEAR: 0, - CATMULLROM: 1, - CATMULLROM_FORWARD: 2, + if ( Math.abs( from2toAngle ) > EPSILON ) { - // + // angle != 180 deg. - 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.'); - }, + var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; + // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - // + if ( from2toAngle > 0 ) { - animations: [], + // main angle < 180 deg. + return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); - init: function (data) { + } else { - if (data.initialized === true) return data; + // main angle > 180 deg. + return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); - // loop through all keys + } - for (var h = 0; h < data.hierarchy.length; h++) { + } else { - for (var k = 0; k < data.hierarchy[h].keys.length; k++) { + // angle == 180 deg. + // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); + return ( from2otherAngle > 0 ); - // remove minus times + } - if (data.hierarchy[h].keys[k].time < 0) { + } - data.hierarchy[h].keys[k].time = 0; - } + function removeHoles( contour, holes ) { - // create quaternions + var shape = contour.concat(); // work on this shape + var hole; - if (data.hierarchy[h].keys[k].rot !== undefined && !( data.hierarchy[h].keys[k].rot instanceof THREE.Quaternion )) { + function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { - var quat = data.hierarchy[h].keys[k].rot; - data.hierarchy[h].keys[k].rot = new THREE.Quaternion().fromArray(quat); + // Check if hole point lies within angle around shape point + var lastShapeIdx = shape.length - 1; - } + var prevShapeIdx = inShapeIdx - 1; + if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; - } + var nextShapeIdx = inShapeIdx + 1; + if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; - // prepare morph target keys + var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] ); + if ( ! insideAngle ) { - if (data.hierarchy[h].keys.length && data.hierarchy[h].keys[0].morphTargets !== undefined) { + // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); + return false; - // get all used + } - var usedMorphTargets = {}; + // Check if shape point lies within angle around hole point + var lastHoleIdx = hole.length - 1; - for (var k = 0; k < data.hierarchy[h].keys.length; k++) { + var prevHoleIdx = inHoleIdx - 1; + if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; - for (var m = 0; m < data.hierarchy[h].keys[k].morphTargets.length; m++) { + var nextHoleIdx = inHoleIdx + 1; + if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; - var morphTargetName = data.hierarchy[h].keys[k].morphTargets[m]; - usedMorphTargets[morphTargetName] = -1; + 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; - } + } - data.hierarchy[h].usedMorphTargets = usedMorphTargets; + return true; + } - // set all used on all frames + function intersectsShapeEdge( inShapePt, inHolePt ) { - for (var k = 0; k < data.hierarchy[h].keys.length; k++) { + // checks for intersections with shape edges + var sIdx, nextIdx, intersection; + for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { - var influences = {}; + nextIdx = sIdx + 1; nextIdx %= shape.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true ); + if ( intersection.length > 0 ) return true; - for (var morphTargetName in usedMorphTargets) { + } - for (var m = 0; m < data.hierarchy[h].keys[k].morphTargets.length; m++) { + return false; - if (data.hierarchy[h].keys[k].morphTargets[m] === morphTargetName) { + } - influences[morphTargetName] = data.hierarchy[h].keys[k].morphTargetsInfluences[m]; - break; + 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 ++ ) { - if (m === data.hierarchy[h].keys[k].morphTargets.length) { + chkHole = holes[ indepHoles[ ihIdx ]]; + for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { - influences[morphTargetName] = 0; + 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; - data.hierarchy[h].keys[k].morphTargetsInfluences = influences; + } - } + var holeIndex, shapeIndex, + shapePt, holePt, + holeIdx, cutKey, failedCuts = [], + tmpShape1, tmpShape2, + tmpHole1, tmpHole2; - } + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + indepHoles.push( h ); - // remove all keys that are on the same time + } - for (var k = 1; k < data.hierarchy[h].keys.length; k++) { + var minShapeIndex = 0; + var counter = indepHoles.length * 2; + while ( indepHoles.length > 0 ) { - if (data.hierarchy[h].keys[k].time === data.hierarchy[h].keys[k - 1].time) { + counter --; + if ( counter < 0 ) { - data.hierarchy[h].keys.splice(k, 1); - k--; + console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); + break; - } + } - } + // search for shape-vertex and hole-vertex, + // which can be connected without intersections + for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { + shapePt = shape[ shapeIndex ]; + holeIndex = - 1; - // set index + // search for hole which can be reached without intersections + for ( var h = 0; h < indepHoles.length; h ++ ) { - for (var k = 0; k < data.hierarchy[h].keys.length; k++) { + holeIdx = indepHoles[ h ]; - data.hierarchy[h].keys[k].index = k; + // prevent multiple checks + cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; + if ( failedCuts[ cutKey ] !== undefined ) continue; - } + 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; - data.initialized = true; + holeIndex = h2; + indepHoles.splice( h, 1 ); - return data; + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); - }, + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); - parse: function (root) { + minShapeIndex = shapeIndex; - var parseRecurseHierarchy = function (root, hierarchy) { + // Debug only, to show the selected cuts + // glob_CutLines.push( [ shapePt, holePt ] ); - hierarchy.push(root); + break; - for (var c = 0; c < root.children.length; c++) - parseRecurseHierarchy(root.children[c], hierarchy); + } + if ( holeIndex >= 0 ) break; // hole-vertex found - }; + failedCuts[ cutKey ] = true; // remember failure - // setup hierarchy + } + if ( holeIndex >= 0 ) break; // hole-vertex found - var hierarchy = []; + } - if (root instanceof THREE.SkinnedMesh) { + } - for (var b = 0; b < root.skeleton.bones.length; b++) { + return shape; /* shape with no holes */ - hierarchy.push(root.skeleton.bones[b]); + } - } - } else { + var i, il, f, face, + key, index, + allPointsMap = {}; - parseRecurseHierarchy(root, hierarchy); + // 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. - } + var allpoints = contour.concat(); - return hierarchy; + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - }, + Array.prototype.push.apply( allpoints, holes[ h ] ); - play: function (animation) { + } - if (this.animations.indexOf(animation) === -1) { + //console.log( "allpoints",allpoints, allpoints.length ); - this.animations.push(animation); + // prepare all points map - } + for ( i = 0, il = allpoints.length; i < il; i ++ ) { - }, + key = allpoints[ i ].x + ":" + allpoints[ i ].y; - stop: function (animation) { + if ( allPointsMap[ key ] !== undefined ) { - var index = this.animations.indexOf(animation); + console.warn( "THREE.Shape: Duplicate point", key ); - if (index !== -1) { + } - this.animations.splice(index, 1); + allPointsMap[ key ] = i; - } + } - }, + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); - update: function (deltaTimeMS) { + var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape + //console.log( "triangles",triangles, triangles.length ); - for (var i = 0; i < this.animations.length; i++) { + // check all face vertices against all points map - this.animations[i].resetBlendWeights(); + for ( i = 0, il = triangles.length; i < il; i ++ ) { - } + face = triangles[ i ]; - for (var i = 0; i < this.animations.length; i++) { + for ( f = 0; f < 3; f ++ ) { - this.animations[i].update(deltaTimeMS); + key = face[ f ].x + ":" + face[ f ].y; - } + index = allPointsMap[ key ]; - } + if ( index !== undefined ) { -}; + face[ f ] = index; -// File:src/extras/animation/Animation.js + } -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } -THREE.Animation = function (root, data) { + } - this.root = root; - this.data = THREE.AnimationHandler.init(data); - this.hierarchy = THREE.AnimationHandler.parse(root); + return triangles.concat(); - this.currentTime = 0; - this.timeScale = 1; + }, - this.isPlaying = false; - this.loop = true; - this.weight = 0; + isClockWise: function ( pts ) { - this.interpolationType = THREE.AnimationHandler.LINEAR; + return THREE.FontUtils.Triangulate.area( pts ) < 0; -}; + }, -THREE.Animation.prototype = { + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve - constructor: THREE.Animation, + // Quad Bezier Functions - keyTypes: ["pos", "rot", "scl"], + b2p0: function ( t, p ) { - play: function (startTime, weight) { + var k = 1 - t; + return k * k * p; - this.currentTime = startTime !== undefined ? startTime : 0; - this.weight = weight !== undefined ? weight : 1; + }, - this.isPlaying = true; + b2p1: function ( t, p ) { - this.reset(); + return 2 * ( 1 - t ) * t * p; - THREE.AnimationHandler.play(this); + }, - }, + b2p2: function ( t, p ) { - stop: function () { + return t * t * p; - this.isPlaying = false; + }, - THREE.AnimationHandler.stop(this); + b2: function ( t, p0, p1, p2 ) { - }, + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); - reset: function () { + }, - for (var h = 0, hl = this.hierarchy.length; h < hl; h++) { + // Cubic Bezier Functions - var object = this.hierarchy[h]; + b3p0: function ( t, p ) { - if (object.animationCache === undefined) { + var k = 1 - t; + return k * k * k * p; - object.animationCache = { - animations: {}, - blending: { - positionWeight: 0.0, - quaternionWeight: 0.0, - scaleWeight: 0.0 - } - }; - } + }, - var name = this.data.name; - var animations = object.animationCache.animations; - var animationCache = animations[name]; + b3p1: function ( t, p ) { - if (animationCache === undefined) { + var k = 1 - t; + return 3 * k * k * t * p; - animationCache = { - prevKey: {pos: 0, rot: 0, scl: 0}, - nextKey: {pos: 0, rot: 0, scl: 0}, - originalMatrix: object.matrix - }; + }, - animations[name] = animationCache; + b3p2: function ( t, p ) { - } + var k = 1 - t; + return 3 * k * t * t * p; - // Get keys to match our current time + }, - for (var t = 0; t < 3; t++) { + b3p3: function ( t, p ) { - var type = this.keyTypes[t]; + return t * t * t * p; - var prevKey = this.data.hierarchy[h].keys[0]; - var nextKey = this.getNextKeyWith(type, h, 1); + }, - while (nextKey.time < this.currentTime && nextKey.index > prevKey.index) { + b3: function ( t, p0, p1, p2, p3 ) { - prevKey = nextKey; - nextKey = this.getNextKeyWith(type, h, nextKey.index + 1); + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); - } + } - animationCache.prevKey[type] = prevKey; - animationCache.nextKey[type] = nextKey; +}; - } +// File:src/extras/curves/LineCurve.js - } +/************************************************************** + * Line + **************************************************************/ - }, +THREE.LineCurve = function ( v1, v2 ) { - resetBlendWeights: function () { + this.v1 = v1; + this.v2 = v2; - for (var h = 0, hl = this.hierarchy.length; h < hl; h++) { +}; - var object = this.hierarchy[h]; - var animationCache = object.animationCache; +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.LineCurve.prototype.constructor = THREE.LineCurve; - if (animationCache !== undefined) { +THREE.LineCurve.prototype.getPoint = function ( t ) { - var blending = animationCache.blending; + var point = this.v2.clone().sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - blending.positionWeight = 0.0; - blending.quaternionWeight = 0.0; - blending.scaleWeight = 0.0; + return point; - } +}; - } +// Line curve is linear, so we can overwrite default getPointAt - }, +THREE.LineCurve.prototype.getPointAt = function ( u ) { - update: (function () { + return this.getPoint( u ); - var points = []; - var target = new THREE.Vector3(); - var newVector = new THREE.Vector3(); - var newQuat = new THREE.Quaternion(); +}; - // Catmull-Rom spline +THREE.LineCurve.prototype.getTangent = function( t ) { - var interpolateCatmullRom = function (points, scale) { + var tangent = this.v2.clone().sub( this.v1 ); - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; + return tangent.normalize(); - 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; +// File:src/extras/curves/QuadraticBezierCurve.js - pa = points[c[0]]; - pb = points[c[1]]; - pc = points[c[2]]; - pd = points[c[3]]; +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ - w2 = weight * weight; - w3 = weight * w2; - 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); +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { - return v3; + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - }; +}; - var interpolate = function (p0, p1, p2, p3, t, t2, t3) { +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( -3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { - }; + var vector = new THREE.Vector2(); - return function (delta) { + 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 ); - if (this.isPlaying === false) return; + return vector; - this.currentTime += delta * this.timeScale; +}; - if (this.weight === 0) - return; - // +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { - var duration = this.data.length; + var vector = new THREE.Vector2(); - if (this.currentTime > duration || this.currentTime < 0) { + 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 ); - if (this.loop) { + // returns unit vector - this.currentTime %= duration; + return vector.normalize(); - if (this.currentTime < 0) - this.currentTime += duration; +}; - this.reset(); +// File:src/extras/curves/CubicBezierCurve.js - } else { +/************************************************************** + * Cubic Bezier curve + **************************************************************/ - this.stop(); +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - } + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - } +}; - for (var h = 0, hl = this.hierarchy.length; h < hl; h++) { +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; - var object = this.hierarchy[h]; - var animationCache = object.animationCache.animations[this.data.name]; - var blending = object.animationCache.blending; +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { - // loop through pos/rot/scl + var tx, ty; - for (var t = 0; t < 3; t++) { + 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 ); - // get keys + return new THREE.Vector2( tx, ty ); - var type = this.keyTypes[t]; - var prevKey = animationCache.prevKey[type]; - var nextKey = animationCache.nextKey[type]; +}; - if (( this.timeScale > 0 && nextKey.time <= this.currentTime ) || - ( this.timeScale < 0 && prevKey.time >= this.currentTime )) { +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { - prevKey = this.data.hierarchy[h].keys[0]; - nextKey = this.getNextKeyWith(type, h, 1); + var tx, ty; - while (nextKey.time < this.currentTime && nextKey.index > prevKey.index) { + 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 ); - prevKey = nextKey; - nextKey = this.getNextKeyWith(type, h, nextKey.index + 1); + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); - } + return tangent; - animationCache.prevKey[type] = prevKey; - animationCache.nextKey[type] = nextKey; +}; - } +// File:src/extras/curves/SplineCurve.js - var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); +/************************************************************** + * Spline curve + **************************************************************/ - var prevXYZ = prevKey[type]; - var nextXYZ = nextKey[type]; +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - if (scale < 0) scale = 0; - if (scale > 1) scale = 1; + this.points = ( points == undefined ) ? [] : points; - // interpolate +}; - if (type === "pos") { +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; - if (this.interpolationType === THREE.AnimationHandler.LINEAR) { +THREE.SplineCurve.prototype.getPoint = function ( t ) { - 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; + var points = this.points; + var point = ( points.length - 1 ) * t; - // blend - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - object.position.lerp(newVector, proportionalWeight); - blending.positionWeight += this.weight; + var intPoint = Math.floor( point ); + var weight = point - intPoint; - } else if (this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD) { + 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 ]; - 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"]; + var vector = new THREE.Vector2(); - scale = scale * 0.33 + 0.33; + 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 ); - var currentPoint = interpolateCatmullRom(points, scale); - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - blending.positionWeight += this.weight; + return vector; - // blend +}; - var vector = object.position; +// File:src/extras/curves/EllipseCurve.js - 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; +/************************************************************** + * Ellipse curve + **************************************************************/ - if (this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD) { +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - var forwardPoint = interpolateCatmullRom(points, scale * 1.01); + this.aX = aX; + this.aY = aY; - target.set(forwardPoint[0], forwardPoint[1], forwardPoint[2]); - target.sub(vector); - target.y = 0; - target.normalize(); + this.xRadius = xRadius; + this.yRadius = yRadius; - var angle = Math.atan2(target.x, target.z); - object.rotation.set(0, angle, 0); + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; - } + this.aClockwise = aClockwise; + + this.aRotation = aRotation || 0; - } +}; - } else if (type === "rot") { +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); +THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; - THREE.Quaternion.slerp(prevXYZ, nextXYZ, newQuat, scale); +THREE.EllipseCurve.prototype.getPoint = function ( t ) { - // Avoid paying the cost of an additional slerp if we don't have to - if (blending.quaternionWeight === 0) { + var deltaAngle = this.aEndAngle - this.aStartAngle; - object.quaternion.copy(newQuat); - blending.quaternionWeight = this.weight; + if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; + if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; - } else { + var angle; - var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); - THREE.Quaternion.slerp(object.quaternion, newQuat, object.quaternion, proportionalWeight); - blending.quaternionWeight += this.weight; + if ( this.aClockwise === true ) { - } + angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); - } else if (type === "scl") { + } else { - 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; + angle = this.aStartAngle + t * deltaAngle; - var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); - object.scale.lerp(newVector, proportionalWeight); - blending.scaleWeight += this.weight; + } + + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); - } + if ( this.aRotation !== 0 ) { - } + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); - } + var tx = x, ty = y; - return true; + // Rotate the point about the center of the ellipse. + x = ( tx - this.aX ) * cos - ( ty - this.aY ) * sin + this.aX; + y = ( tx - this.aX ) * sin + ( ty - this.aY ) * cos + this.aY; - }; + } - })(), + return new THREE.Vector2( x, y ); - getNextKeyWith: function (type, h, key) { +}; - var keys = this.data.hierarchy[h].keys; +// File:src/extras/curves/ArcCurve.js - if (this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD) { +/************************************************************** + * Arc curve + **************************************************************/ - key = key < keys.length - 1 ? key : keys.length - 1; +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - } else { + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - key = key % keys.length; +}; - } +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; - for (; key < keys.length; key++) { +// File:src/extras/curves/LineCurve3.js - if (keys[key][type] !== undefined) { +/************************************************************** + * Line3D + **************************************************************/ - return keys[key]; +THREE.LineCurve3 = THREE.Curve.create( - } + function ( v1, v2 ) { - } + this.v1 = v1; + this.v2 = v2; - return this.data.hierarchy[h].keys[0]; + }, - }, + function ( t ) { - getPrevKeyWith: function (type, h, key) { + var vector = new THREE.Vector3(); - var keys = this.data.hierarchy[h].keys; + vector.subVectors( this.v2, this.v1 ); // diff + vector.multiplyScalar( t ); + vector.add( this.v1 ); - if (this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD) { + return vector; - key = key > 0 ? key : 0; + } - } else { +); - key = key >= 0 ? key : key + keys.length; +// File:src/extras/curves/QuadraticBezierCurve3.js - } +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ +THREE.QuadraticBezierCurve3 = THREE.Curve.create( - for (; key >= 0; key--) { + function ( v0, v1, v2 ) { - if (keys[key][type] !== undefined) { + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - return keys[key]; + }, - } + function ( t ) { - } + var vector = new THREE.Vector3(); - return this.data.hierarchy[h].keys[keys.length - 1]; + 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 ); - } + return vector; -}; + } -// File:src/extras/animation/KeyFrameAnimation.js +); -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author khang duong - * @author erik kitson - */ +// File:src/extras/curves/CubicBezierCurve3.js -THREE.KeyFrameAnimation = function (data) { +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ - 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; +THREE.CubicBezierCurve3 = THREE.Curve.create( - // initialize to first keyframes + function ( v0, v1, v2, v3 ) { - for (var h = 0, hl = this.hierarchy.length; h < hl; h++) { + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - obj = this.hierarchy[h]; + }, - if (keys.length && sids) { + function ( t ) { - for (var s = 0; s < sids.length; s++) { + var vector = new THREE.Vector3(); - var sid = sids[s], - next = this.getNextKeyWith(sid, h, 0); + 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 ); - if (next) { + return vector; - next.apply(sid); + } - } +); - } +// File:src/extras/curves/SplineCurve3.js - obj.matrixAutoUpdate = false; - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; +/************************************************************** + * Spline 3D curve + **************************************************************/ - } - } +THREE.SplineCurve3 = THREE.Curve.create( -}; + function ( points /* array of Vector3 */ ) { -THREE.KeyFrameAnimation.prototype = { + console.warn( 'THREE.SplineCurve3 will be deprecated. Please use THREE.CatmullRomCurve3' ); + this.points = ( points == undefined ) ? [] : points; - constructor: THREE.KeyFrameAnimation, + }, - play: function (startTime) { + function ( t ) { - this.currentTime = startTime !== undefined ? startTime : 0; + var points = this.points; + var point = ( points.length - 1 ) * t; - if (this.isPlaying === false) { + var intPoint = Math.floor( point ); + var weight = point - intPoint; - this.isPlaying = true; + 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 ]; - // reset key cache + var vector = new THREE.Vector3(); - var h, hl = this.hierarchy.length, - object, - node; + 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 ); - for (h = 0; h < hl; h++) { + return vector; - object = this.hierarchy[h]; - node = this.data.hierarchy[h]; + } - if (node.animationCache === undefined) { +); - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object.matrix; +// File:src/extras/curves/CatmullRomCurve3.js - } +/** + * @author zz85 https://github.com/zz85 + * + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ - var keys = this.data.hierarchy[h].keys; +THREE.CatmullRomCurve3 = ( function() { - if (keys.length) { + var + tmp = new THREE.Vector3(), + px = new CubicPoly(), + py = new CubicPoly(), + pz = new CubicPoly(); - node.animationCache.prevKey = keys[0]; - node.animationCache.nextKey = keys[1]; + /* + Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM - this.startTime = Math.min(keys[0].time, this.startTime); - this.endTime = Math.max(keys[keys.length - 1].time, this.endTime); + This CubicPoly class could be used for reusing some variables and calculations, + but for three.js curve use, it could be possible inlined and flatten into a single function call + which can be placed in CurveUtils. + */ - } + function CubicPoly() { - } + } - this.update(0); + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + CubicPoly.prototype.init = function( x0, x1, t0, t1 ) { - } + this.c0 = x0; + this.c1 = t0; + this.c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + this.c3 = 2 * x0 - 2 * x1 + t0 + t1; - this.isPaused = false; + }; - THREE.AnimationHandler.play(this); + CubicPoly.prototype.initNonuniformCatmullRom = function( x0, x1, x2, x3, dt0, dt1, dt2 ) { - }, + // compute tangents when parameterized in [t1,t2] + var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - stop: function () { + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - this.isPlaying = false; - this.isPaused = false; + // initCubicPoly + this.init( x1, x2, t1, t2 ); - THREE.AnimationHandler.stop(this); + }; - // reset JIT matrix and remove cache + // standard Catmull-Rom spline: interpolate between x1 and x2 with previous/following points x1/x4 + CubicPoly.prototype.initCatmullRom = function( x0, x1, x2, x3, tension ) { - for (var h = 0; h < this.data.hierarchy.length; h++) { + this.init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - var obj = this.hierarchy[h]; - var node = this.data.hierarchy[h]; + }; - if (node.animationCache !== undefined) { + CubicPoly.prototype.calc = function( t ) { - var original = node.animationCache.originalMatrix; + var t2 = t * t; + var t3 = t2 * t; + return this.c0 + this.c1 * t + this.c2 * t2 + this.c3 * t3; - original.copy(obj.matrix); - obj.matrix = original; + }; - delete node.animationCache; + // Subclass Three.js curve + return THREE.Curve.create( - } + function ( p /* array of Vector3 */ ) { - } + this.points = p || []; - }, + }, - update: function (delta) { + function ( t ) { - if (this.isPlaying === false) return; + var points = this.points, + point, intPoint, weight, l; - this.currentTime += delta * this.timeScale; + l = points.length; - // + if ( l < 2 ) console.log( 'duh, you need at least 2 points' ); - var duration = this.data.length; + point = ( l - 1 ) * t; + intPoint = Math.floor( point ); + weight = point - intPoint; - if (this.loop === true && this.currentTime > duration) { + if ( weight === 0 && intPoint === l - 1 ) { - this.currentTime %= duration; + intPoint = l - 2; + weight = 1; - } + } - this.currentTime = Math.min(this.currentTime, duration); + var p0, p1, p2, p3; - for (var h = 0, hl = this.hierarchy.length; h < hl; h++) { + if ( intPoint === 0 ) { - var object = this.hierarchy[h]; - var node = this.data.hierarchy[h]; + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - var keys = node.keys, - animationCache = node.animationCache; + } else { + p0 = points[ intPoint - 1 ]; - if (keys.length) { + } - var prevKey = animationCache.prevKey; - var nextKey = animationCache.nextKey; + p1 = points[ intPoint ]; + p2 = points[ intPoint + 1 ]; - if (nextKey.time <= this.currentTime) { + if ( intPoint + 2 < l ) { - while (nextKey.time < this.currentTime && nextKey.index > prevKey.index) { + p3 = points[ intPoint + 2 ] - prevKey = nextKey; - nextKey = keys[prevKey.index + 1]; + } else { - } + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 2 ] ); + p3 = tmp; - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; + } - } + if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) { - if (nextKey.time >= this.currentTime) { + // init Centripetal / Chordal Catmull-Rom + var pow = this.type === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - prevKey.interpolate(nextKey, this.currentTime); + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; - } else { + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - prevKey.interpolate(nextKey, nextKey.time); + } else if ( this.type === 'catmullrom' ) { - } + var tension = this.tension !== undefined ? this.tension : 0.5; + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension ); - this.data.hierarchy[h].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; + } - } + var v = new THREE.Vector3( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); - } + return v; - }, + } - getNextKeyWith: function (sid, h, key) { + ); - var keys = this.data.hierarchy[h].keys; - key = key % keys.length; +} )(); - for (; key < keys.length; key++) { +// File:src/extras/curves/ClosedSplineCurve3.js - if (keys[key].hasTarget(sid)) { +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ - return keys[key]; - } +THREE.ClosedSplineCurve3 = THREE.Curve.create( - } + function ( points /* array of Vector3 */ ) { - return keys[0]; + this.points = ( points == undefined ) ? [] : points; - }, + }, - getPrevKeyWith: function (sid, h, key) { + function ( t ) { - var keys = this.data.hierarchy[h].keys; - key = key >= 0 ? key : key + keys.length; + var points = this.points; + var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 - for (; key >= 0; key--) { + var intPoint = Math.floor( point ); + var weight = point - intPoint; - if (keys[key].hasTarget(sid)) { + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - return keys[key]; + 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 ]; - } + 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 keys[keys.length - 1]; + return vector; - } + } -}; +); -// File:src/extras/animation/MorphAnimation.js +// File:src/extras/geometries/BoxGeometry.js /** - * @author mrdoob / http://mrdoob.com - * @author willy-vvu / http://willy-vvu.github.io + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as */ -THREE.MorphAnimation = function (mesh) { +THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - this.mesh = mesh; - this.frames = mesh.morphTargetInfluences.length; - this.currentTime = 0; - this.duration = 1000; - this.loop = true; - this.lastFrame = 0; - this.currentFrame = 0; + THREE.Geometry.call( this ); - this.isPlaying = false; + this.type = 'BoxGeometry'; -}; + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; -THREE.MorphAnimation.prototype = { + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; - constructor: THREE.MorphAnimation, + var scope = this; - play: function () { + var width_half = width / 2; + var height_half = height / 2; + var depth_half = depth / 2; - this.isPlaying = true; + 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 - }, + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { - pause: function () { + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; - this.isPlaying = false; + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { - }, + w = 'z'; - update: function (delta) { + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { - if (this.isPlaying === false) return; + w = 'y'; + gridY = scope.depthSegments; - this.currentTime += delta; + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { - if (this.loop === true && this.currentTime > this.duration) { + w = 'x'; + gridX = scope.depthSegments; - this.currentTime %= this.duration; + } - } + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); - this.currentTime = Math.min(this.currentTime, this.duration); + normal[ w ] = depth > 0 ? 1 : - 1; - var interpolation = this.duration / this.frames; - var frame = Math.floor(this.currentTime / interpolation); + for ( iy = 0; iy < gridY1; iy ++ ) { - var influences = this.mesh.morphTargetInfluences; + for ( ix = 0; ix < gridX1; ix ++ ) { - if (frame != this.currentFrame) { + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; - influences[this.lastFrame] = 0; - influences[this.currentFrame] = 1; - influences[frame] = 0; + scope.vertices.push( vector ); - this.lastFrame = this.currentFrame; - this.currentFrame = frame; + } - } + } - influences[frame] = ( this.currentTime % interpolation ) / interpolation; - influences[this.lastFrame] = 1 - influences[frame]; + for ( iy = 0; iy < gridY; iy ++ ) { - } + for ( ix = 0; ix < gridX; ix ++ ) { -}; + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; -// File:src/extras/geometries/BoxGeometry.js + 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 ); -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as - */ + 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 ] ); -THREE.BoxGeometry = function (width, height, depth, widthSegments, heightSegments, depthSegments) { + 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; - THREE.Geometry.call(this); + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - 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; + this.mergeVertices(); - var width_half = width / 2; - var height_half = height / 2; - var depth_half = depth / 2; +}; - buildPlane('z', 'y', -1, -1, depth, height, width_half); // px - buildPlane('z', 'y', 1, -1, depth, height, -width_half); // nx - buildPlane('x', 'z', 1, 1, width, depth, height_half); // py - buildPlane('x', 'z', 1, -1, width, depth, -height_half); // ny - buildPlane('x', 'y', 1, -1, width, height, depth_half); // pz - buildPlane('x', 'y', -1, -1, width, height, -depth_half); // nz +THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; - function buildPlane(u, v, udir, vdir, width, height, depth) { +THREE.BoxGeometry.prototype.clone = function () { - var w, ix, iy, - gridX = scope.widthSegments, - gridY = scope.heightSegments, - width_half = width / 2, - height_half = height / 2, - offset = scope.vertices.length; + var geometry = new THREE.BoxGeometry( + this.parameters.width, + this.parameters.height, + this.parameters.depth, + this.parameters.widthSegments, + this.parameters.heightSegments, + this.parameters.depthSegments + ); - if (( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' )) { + return geometry; - w = 'z'; +}; - } else if (( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' )) { +THREE.CubeGeometry = THREE.BoxGeometry; // backwards compatibility - w = 'y'; - gridY = scope.depthSegments; +// File:src/extras/geometries/CircleGeometry.js - } else if (( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' )) { +/** + * @author hughes + */ - w = 'x'; - gridX = scope.depthSegments; +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { - } + THREE.Geometry.call( this ); - var gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY, - normal = new THREE.Vector3(); + this.type = 'CircleGeometry'; - normal[w] = depth > 0 ? 1 : -1; + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - for (iy = 0; iy < gridY1; iy++) { + radius = radius || 50; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - for (ix = 0; ix < gridX1; ix++) { + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - 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 i, uvs = [], + center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); - scope.vertices.push(vector); + this.vertices.push( center ); + uvs.push( centerUV ); - } + for ( i = 0; i <= segments; i ++ ) { - } + var vertex = new THREE.Vector3(); + var segment = thetaStart + i / segments * thetaLength; - for (iy = 0; iy < gridY; iy++) { + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - for (ix = 0; ix < gridX; ix++) { + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); - 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 n = new THREE.Vector3( 0, 0, 1 ); - var face = new THREE.Face3(a + offset, b + offset, d + offset); - face.normal.copy(normal); - face.vertexNormals.push(normal.clone(), normal.clone(), normal.clone()); + for ( i = 1; i <= segments; i ++ ) { - scope.faces.push(face); - scope.faceVertexUvs[0].push([uva, uvb, uvd]); + 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() ] ); - face = new THREE.Face3(b + offset, c + offset, d + offset); - face.normal.copy(normal); - face.vertexNormals.push(normal.clone(), normal.clone(), normal.clone()); + } - scope.faces.push(face); - scope.faceVertexUvs[0].push([uvb.clone(), uvc, uvd.clone()]); + this.computeFaceNormals(); - } + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - } +}; - } +THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; - this.mergeVertices(); +THREE.CircleGeometry.prototype.clone = function () { -}; + var geometry = new THREE.CircleGeometry( + this.parameters.radius, + this.parameters.segments, + this.parameters.thetaStart, + this.parameters.thetaLength + ); -THREE.BoxGeometry.prototype = Object.create(THREE.Geometry.prototype); -THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; + return geometry; -THREE.CubeGeometry = THREE.BoxGeometry; // backwards compatibility +}; -// File:src/extras/geometries/CircleGeometry.js +// File:src/extras/geometries/CircleBufferGeometry.js /** - * @author hughes + * @author benaadams / https://twitter.com/ben_a_adams */ -THREE.CircleGeometry = function (radius, segments, thetaStart, thetaLength) { +THREE.CircleBufferGeometry = function ( radius, segments, thetaStart, thetaLength ) { - THREE.Geometry.call(this); + THREE.BufferGeometry.call( this ); - this.type = 'CircleGeometry'; + this.type = 'CircleBufferGeometry'; - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - radius = radius || 50; - segments = segments !== undefined ? Math.max(3, segments) : 8; + radius = radius || 50; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - var i, uvs = [], - center = new THREE.Vector3(), centerUV = new THREE.Vector2(0.5, 0.5); + var vertices = segments + 2; - this.vertices.push(center); - uvs.push(centerUV); + var positions = new Float32Array( vertices * 3 ); + var normals = new Float32Array( vertices * 3 ); + var uvs = new Float32Array( vertices * 2 ); - for (i = 0; i <= segments; i++) { + // center data is already zero, but need to set a few extras + normals[ 3 ] = 1.0; + uvs[ 0 ] = 0.5; + uvs[ 1 ] = 0.5; - var vertex = new THREE.Vector3(); - var segment = thetaStart + i / segments * thetaLength; + for ( var s = 0, i = 3, ii = 2 ; s <= segments; s ++, i += 3, ii += 2 ) { - vertex.x = radius * Math.cos(segment); - vertex.y = radius * Math.sin(segment); + var segment = thetaStart + s / segments * thetaLength; - this.vertices.push(vertex); - uvs.push(new THREE.Vector2(( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2)); + positions[ i ] = radius * Math.cos( segment ); + positions[ i + 1 ] = radius * Math.sin( segment ); - } + normals[ i + 2 ] = 1; // normal z - var n = new THREE.Vector3(0, 0, 1); + uvs[ ii ] = ( positions[ i ] / radius + 1 ) / 2; + uvs[ ii + 1 ] = ( positions[ i + 1 ] / radius + 1 ) / 2; - 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 indices = []; - } + for ( var i = 1; i <= segments; i ++ ) { + + indices.push( i ); + indices.push( i + 1 ); + indices.push( 0 ); + + } - this.computeFaceNormals(); + this.setIndex( new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) ); + this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); + this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); - this.boundingSphere = new THREE.Sphere(new THREE.Vector3(), radius); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; -THREE.CircleGeometry.prototype = Object.create(THREE.Geometry.prototype); -THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; +THREE.CircleBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.CircleBufferGeometry.prototype.constructor = THREE.CircleBufferGeometry; + +THREE.CircleBufferGeometry.prototype.clone = function () { + + var geometry = new THREE.CircleBufferGeometry( + this.parameters.radius, + this.parameters.segments, + this.parameters.thetaStart, + this.parameters.thetaLength + ); + + geometry.copy( this ); + + return geometry; + +}; // File:src/extras/geometries/CylinderGeometry.js @@ -30587,272 +32537,287 @@ THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; * @author mrdoob / http://mrdoob.com/ */ -THREE.CylinderGeometry = function (radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) { +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'CylinderGeometry'; + this.type = 'CylinderGeometry'; - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + 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; + radiusTop = radiusTop !== undefined ? radiusTop : 20; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + height = height !== undefined ? height : 100; - radialSegments = radialSegments || 8; - heightSegments = heightSegments || 1; + radialSegments = radialSegments || 8; + heightSegments = heightSegments || 1; - openEnded = openEnded !== undefined ? openEnded : false; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; - var heightHalf = height / 2; + var heightHalf = height / 2; - var x, y, vertices = [], uvs = []; + var x, y, vertices = [], uvs = []; - for (y = 0; y <= heightSegments; y++) { + for ( y = 0; y <= heightSegments; y ++ ) { - var verticesRow = []; - var uvsRow = []; + var verticesRow = []; + var uvsRow = []; - var v = y / heightSegments; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + var v = y / heightSegments; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - for (x = 0; x <= radialSegments; x++) { + for ( x = 0; x <= radialSegments; x ++ ) { - var u = x / radialSegments; + var u = x / radialSegments; - var vertex = new THREE.Vector3(); - vertex.x = radius * Math.sin(u * thetaLength + thetaStart); - vertex.y = -v * height + heightHalf; - vertex.z = radius * Math.cos(u * thetaLength + thetaStart); + var vertex = new THREE.Vector3(); + 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); + this.vertices.push( vertex ); - verticesRow.push(this.vertices.length - 1); - uvsRow.push(new THREE.Vector2(u, 1 - v)); + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - } + } - vertices.push(verticesRow); - uvs.push(uvsRow); + vertices.push( verticesRow ); + uvs.push( uvsRow ); - } + } - var tanTheta = ( radiusBottom - radiusTop ) / height; - var na, nb; + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; - for (x = 0; x < radialSegments; x++) { + for ( x = 0; x < radialSegments; x ++ ) { - if (radiusTop !== 0) { + if ( radiusTop !== 0 ) { - na = this.vertices[vertices[0][x]].clone(); - nb = this.vertices[vertices[0][x + 1]].clone(); + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - } else { + } else { - na = this.vertices[vertices[1][x]].clone(); - nb = this.vertices[vertices[1][x + 1]].clone(); + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); - } + } - 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(); + 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++) { + 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]; + 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 n1 = na.clone(); - var n2 = na.clone(); - var n3 = nb.clone(); - var n4 = nb.clone(); + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); - 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(); + 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(); - this.faces.push(new THREE.Face3(v1, v2, v4, [n1, n2, n4])); - this.faceVertexUvs[0].push([uv1, uv2, uv4]); + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - this.faces.push(new THREE.Face3(v2, v3, v4, [n2.clone(), n3, n4.clone()])); - this.faceVertexUvs[0].push([uv2.clone(), uv3, uv4.clone()]); + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - } + } - } + } - // top cap + // top cap - if (openEnded === false && radiusTop > 0) { + if ( openEnded === false && radiusTop > 0 ) { - this.vertices.push(new THREE.Vector3(0, heightHalf, 0)); + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); - for (x = 0; x < radialSegments; x++) { + for ( x = 0; x < radialSegments; x ++ ) { - var v1 = vertices[0][x]; - var v2 = vertices[0][x + 1]; - var v3 = this.vertices.length - 1; + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; - var n1 = new THREE.Vector3(0, 1, 0); - var n2 = new THREE.Vector3(0, 1, 0); - var n3 = new THREE.Vector3(0, 1, 0); + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); - var uv1 = uvs[0][x].clone(); - var uv2 = uvs[0][x + 1].clone(); - var uv3 = new THREE.Vector2(uv2.x, 0); + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 0 ); - this.faces.push(new THREE.Face3(v1, v2, v3, [n1, n2, n3])); - this.faceVertexUvs[0].push([uv1, uv2, uv3]); + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 1 ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - } + } - } + } - // bottom cap + // bottom cap - if (openEnded === false && radiusBottom > 0) { + if ( openEnded === false && radiusBottom > 0 ) { - this.vertices.push(new THREE.Vector3(0, -heightHalf, 0)); + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); - for (x = 0; x < radialSegments; x++) { + for ( x = 0; x < radialSegments; x ++ ) { - var v1 = vertices[heightSegments][x + 1]; - var v2 = vertices[heightSegments][x]; - var v3 = this.vertices.length - 1; + var v1 = vertices[ heightSegments ][ x + 1 ]; + var v2 = vertices[ heightSegments ][ x ]; + var v3 = this.vertices.length - 1; - var n1 = new THREE.Vector3(0, -1, 0); - var n2 = new THREE.Vector3(0, -1, 0); - var n3 = new THREE.Vector3(0, -1, 0); + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); - var uv1 = uvs[heightSegments][x + 1].clone(); - var uv2 = uvs[heightSegments][x].clone(); - var uv3 = new THREE.Vector2(uv2.x, 1); + var uv1 = uvs[ heightSegments ][ x + 1 ].clone(); + var uv2 = uvs[ heightSegments ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 1 ); - this.faces.push(new THREE.Face3(v1, v2, v3, [n1, n2, n3])); - this.faceVertexUvs[0].push([uv1, uv2, uv3]); + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 2 ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - } + } - } + } - this.computeFaceNormals(); + this.computeFaceNormals(); }; -THREE.CylinderGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry; +THREE.CylinderGeometry.prototype.clone = function () { + + var geometry = new THREE.CylinderGeometry( + this.parameters.radiusTop, + this.parameters.radiusBottom, + this.parameters.height, + this.parameters.radialSegments, + this.parameters.heightSegments, + this.parameters.openEnded, + this.parameters.thetaStart, + this.parameters.thetaLength + ); + + return geometry; + +}; + // File:src/extras/geometries/EdgesGeometry.js /** * @author WestLangley / http://github.com/WestLangley */ -THREE.EdgesGeometry = function (geometry, thresholdAngle) { +THREE.EdgesGeometry = function ( geometry, thresholdAngle ) { - THREE.BufferGeometry.call(this); + THREE.BufferGeometry.call( this ); - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - var thresholdDot = Math.cos(THREE.Math.degToRad(thresholdAngle)); + var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); - var edge = [0, 0], hash = {}; - var sortFunction = function (a, b) { - return a - b - }; + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { - var keys = ['a', 'b', 'c']; + return a - b; - var geometry2; + }; - if (geometry instanceof THREE.BufferGeometry) { + var keys = [ 'a', 'b', 'c' ]; - geometry2 = new THREE.Geometry(); - geometry2.fromBufferGeometry(geometry); + var geometry2; - } else { + if ( geometry instanceof THREE.BufferGeometry ) { - geometry2 = geometry.clone(); + geometry2 = new THREE.Geometry(); + geometry2.fromBufferGeometry( geometry ); - } + } else { - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); + geometry2 = geometry.clone(); - var vertices = geometry2.vertices; - var faces = geometry2.faces; - var numEdges = 0; + } - for (var i = 0, l = faces.length; i < l; i++) { + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); - var face = faces[i]; + var vertices = geometry2.vertices; + var faces = geometry2.faces; - for (var j = 0; j < 3; j++) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - edge[0] = face[keys[j]]; - edge[1] = face[keys[( j + 1 ) % 3]]; - edge.sort(sortFunction); + var face = faces[ i ]; - var key = edge.toString(); + for ( var j = 0; j < 3; j ++ ) { - if (hash[key] === undefined) { + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - hash[key] = {vert1: edge[0], vert2: edge[1], face1: i, face2: undefined}; - numEdges++; + var key = edge.toString(); - } else { + if ( hash[ key ] === undefined ) { - hash[key].face2 = i; + hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; - } + } else { - } + hash[ key ].face2 = i; - } + } - var coords = new Float32Array(numEdges * 2 * 3); + } - var index = 0; + } - for (var key in hash) { + var coords = []; - var h = hash[key]; + for ( var key in hash ) { - if (h.face2 === undefined || faces[h.face1].normal.dot(faces[h.face2].normal) <= thresholdDot) { + var h = hash[ key ]; - var vertex = vertices[h.vert1]; - coords[index++] = vertex.x; - coords[index++] = vertex.y; - coords[index++] = vertex.z; + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { - vertex = vertices[h.vert2]; - coords[index++] = vertex.x; - coords[index++] = vertex.y; - coords[index++] = vertex.z; + var vertex = vertices[ h.vert1 ]; + coords.push( vertex.x ); + coords.push( vertex.y ); + coords.push( vertex.z ); - } + vertex = vertices[ h.vert2 ]; + coords.push( vertex.x ); + coords.push( vertex.y ); + coords.push( vertex.z ); - } + } + + } - this.addAttribute('position', new THREE.BufferAttribute(coords, 3)); + this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( coords ), 3 ) ); }; -THREE.EdgesGeometry.prototype = Object.create(THREE.BufferGeometry.prototype); +THREE.EdgesGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.EdgesGeometry.prototype.constructor = THREE.EdgesGeometry; // File:src/extras/geometries/ExtrudeGeometry.js @@ -30865,7 +32830,7 @@ THREE.EdgesGeometry.prototype.constructor = THREE.EdgesGeometry; * parameters = { * * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too + * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too * amount: , // Depth to extrude the shape * * bevelEnabled: , // turn on bevel @@ -30881,647 +32846,687 @@ THREE.EdgesGeometry.prototype.constructor = THREE.EdgesGeometry; * } **/ -THREE.ExtrudeGeometry = function (shapes, options) { +THREE.ExtrudeGeometry = function ( shapes, options ) { - if (typeof( shapes ) === "undefined") { - shapes = []; - return; - } + if ( typeof( shapes ) === "undefined" ) { + + shapes = []; + return; - THREE.Geometry.call(this); + } - this.type = 'ExtrudeGeometry'; + THREE.Geometry.call( this ); - shapes = shapes instanceof Array ? shapes : [shapes]; + this.type = 'ExtrudeGeometry'; - this.addShapeList(shapes, options); + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - this.computeFaceNormals(); + this.addShapeList( shapes, options ); - // can't really use automatic vertex normals - // as then front and back sides get smoothed too - // should do separate smoothing just for sides + this.computeFaceNormals(); - //this.computeVertexNormals(); + // can't really use automatic vertex normals + // as then front and back sides get smoothed too + // should do separate smoothing just for sides - //THREE.log( "took", ( Date.now() - startTime ) ); + //this.computeVertexNormals(); + + //console.log( "took", ( Date.now() - startTime ) ); }; -THREE.ExtrudeGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; -THREE.ExtrudeGeometry.prototype.addShapeList = function (shapes, options) { - var sl = shapes.length; +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 ); + + } - for (var s = 0; s < sl; s++) { - var shape = shapes[s]; - this.addShape(shape, options); - } }; -THREE.ExtrudeGeometry.prototype.addShape = function (shape, options) { +THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { - var amount = options.amount !== undefined ? options.amount : 100; + var amount = options.amount !== undefined ? options.amount : 100; - 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; + 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; - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - var steps = options.steps !== undefined ? options.steps : 1; + var steps = options.steps !== undefined ? options.steps : 1; - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; - var splineTube, binormal, normal, position2; - if (extrudePath) { + var splineTube, binormal, normal, position2; + if ( extrudePath ) { - extrudePts = extrudePath.getSpacedPoints(steps); + extrudePts = extrudePath.getSpacedPoints( steps ); - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion - // SETUP TNB variables + // SETUP TNB variables - // Reuse TNB from TubeGeomtry for now. - // TODO1 - have a .isClosed in spline? + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? - splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames( extrudePath, steps, false ); - // THREE.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - binormal = new THREE.Vector3(); - normal = new THREE.Vector3(); - position2 = new THREE.Vector3(); + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); - } + } - // Safeguards if bevels are not enabled + // Safeguards if bevels are not enabled - if (!bevelEnabled) { + if ( ! bevelEnabled ) { - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; - } + } - // Variables initalization + // Variables initialization - var ahole, h, hl; // looping of holes - var scope = this; + var ahole, h, hl; // looping of holes + var scope = this; - var shapesOffset = this.vertices.length; + var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints(curveSegments); + var shapePoints = shape.extractPoints( curveSegments ); - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - var reverse = !THREE.Shape.Utils.isClockWise(vertices); + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ); - if (reverse) { + if ( reverse ) { - vertices = vertices.reverse(); + vertices = vertices.reverse(); - // Maybe we should also check if holes are in the opposite direction, just to be safe ... + // 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++) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - ahole = holes[h]; + ahole = holes[ h ]; - if (THREE.Shape.Utils.isClockWise(ahole)) { + if ( THREE.Shape.Utils.isClockWise( ahole ) ) { - holes[h] = ahole.reverse(); + holes[ h ] = ahole.reverse(); - } + } - } + } - reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! - } + } - var faces = THREE.Shape.Utils.triangulateShape(vertices, holes); + var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); - /* Vertices */ + /* Vertices */ - var contour = vertices; // vertices has all points but contour has only points of circumference + var contour = vertices; // vertices has all points but contour has only points of circumference - for (h = 0, hl = holes.length; h < hl; h++) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - ahole = holes[h]; + ahole = holes[ h ]; - vertices = vertices.concat(ahole); + vertices = vertices.concat( ahole ); - } + } - function scalePt2(pt, vec, size) { + function scalePt2 ( pt, vec, size ) { - if (!vec) THREE.error("THREE.ExtrudeGeometry: vec does not exist"); + if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); - return vec.clone().multiplyScalar(size).add(pt); + return vec.clone().multiplyScalar( size ).add( pt ); - } + } - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length; + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length; - // Find directions for point movement + // Find directions for point movement - function getBevelVec(inPt, inPrev, inNext) { + function getBevelVec( inPt, inPrev, inNext ) { - var EPSILON = 0.0000000001; + 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. + // computes for inPt the corresponding point inPt' on a new contour + // shifted 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 + 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 + // 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_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 ); + 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 ); + // check for collinear edges + var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - if (Math.abs(colinear0) > EPSILON) { // not colinear + if ( Math.abs( collinear0 ) > EPSILON ) { - // length of vectors for normalizing + // not collinear - 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); + // length of vectors for normalizing - // shift adjacent points by unit vectors to the left + 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 ); - var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + // shift adjacent points by unit vectors to the left - var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - // scaling factor for v_prev to intersection point + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - 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 ); + // scaling factor for v_prev to intersection point - // vector from inPt 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 ); - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + // vector from inPt to intersection point - // 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); - } + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - } else { // handle special case of colinear edges + // 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 ) { - 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; - } - } - } + return new THREE.Vector2( v_trans_x, v_trans_y ); - if (direction_eq) { - // THREE.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 { - // THREE.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); - } + } else { - } + shrink_by = Math.sqrt( v_trans_lensq / 2 ); - return new THREE.Vector2(v_trans_x / shrink_by, v_trans_y / shrink_by); + } - } + } else { + // handle special case of collinear edges - var contourMovements = []; + var direction_eq = false; // assumes: opposite + if ( v_prev_x > EPSILON ) { - for (var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) { + if ( v_next_x > EPSILON ) { - if (j === il) j = 0; - if (k === il) k = 0; + direction_eq = true; - // (j)---(i)---(k) - // THREE.log('i,j,k', i, j , k) + } - contourMovements[i] = getBevelVec(contour[i], contour[j], contour[k]); + } else { - } + if ( v_prev_x < - EPSILON ) { - var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + if ( v_next_x < - EPSILON ) { - for (h = 0, hl = holes.length; h < hl; h++) { + direction_eq = true; - ahole = holes[h]; + } - oneHoleMovements = []; + } else { - for (i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) { + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - if (j === il) j = 0; - if (k === il) k = 0; + direction_eq = true; - // (j)---(i)---(k) - oneHoleMovements[i] = getBevelVec(ahole[i], ahole[j], ahole[k]); + } - } + } - holesMovements.push(oneHoleMovements); - verticesMovements = verticesMovements.concat(oneHoleMovements); + } - } + 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 ); - // Loop bevelSegments, 1 for the front, 1 for the back + } else { - for (b = 0; b < bevelSegments; b++) { - //for ( b = bevelSegments; b > 0; b -- ) { + // 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 ); - 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 + return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - for (i = 0, il = contour.length; i < il; i++) { + } - vert = scalePt2(contour[i], contourMovements[i], bs); - v(vert.x, vert.y, -z); + var contourMovements = []; - } + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - // expand holes + if ( j === il ) j = 0; + if ( k === il ) k = 0; - for (h = 0, hl = holes.length; h < hl; h++) { + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - ahole = holes[h]; - oneHoleMovements = holesMovements[h]; + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - for (i = 0, il = ahole.length; i < il; i++) { + } - vert = scalePt2(ahole[i], oneHoleMovements[i], bs); + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); - v(vert.x, vert.y, -z); + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - } + ahole = holes[ h ]; - } + oneHoleMovements = []; - } + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - bs = bevelSize; + if ( j === il ) j = 0; + if ( k === il ) k = 0; - // Back facing vertices + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - for (i = 0; i < vlen; i++) { + } - vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); - if (!extrudeByPath) { + } - v(vert.x, vert.y, 0); - } else { + // Loop bevelSegments, 1 for the front, 1 for the back - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + for ( b = 0; b < bevelSegments; b ++ ) { - normal.copy(splineTube.normals[0]).multiplyScalar(vert.x); - binormal.copy(splineTube.binormals[0]).multiplyScalar(vert.y); + //for ( b = bevelSegments; b > 0; b -- ) { - position2.copy(extrudePts[0]).add(normal).add(binormal); + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); - v(position2.x, position2.y, position2.z); + //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 ++ ) { - // Add stepped vertices... - // Including front facing vertices + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - var s; + v( vert.x, vert.y, - z ); - for (s = 1; s <= steps; s++) { + } - for (i = 0; i < vlen; i++) { + // expand holes - vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - if (!extrudeByPath) { + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - v(vert.x, vert.y, amount / steps * s); + for ( i = 0, il = ahole.length; i < il; i ++ ) { - } else { + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + v( vert.x, vert.y, - z ); - 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); + } - } + bs = bevelSize; - } + // Back facing vertices - } + for ( i = 0; i < vlen; i ++ ) { + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - // Add bevel segments planes + if ( ! extrudeByPath ) { - //for ( b = 1; b <= bevelSegments; b ++ ) { - for (b = bevelSegments - 1; b >= 0; b--) { + v( vert.x, vert.y, 0 ); - 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); + } else { - // contract shape + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - for (i = 0, il = contour.length; i < il; i++) { + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - vert = scalePt2(contour[i], contourMovements[i], bs); - v(vert.x, vert.y, amount + z); + position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - } + v( position2.x, position2.y, position2.z ); - // expand holes + } - for (h = 0, hl = holes.length; h < hl; h++) { + } - ahole = holes[h]; - oneHoleMovements = holesMovements[h]; + // Add stepped vertices... + // Including front facing vertices - for (i = 0, il = ahole.length; i < il; i++) { + var s; - vert = scalePt2(ahole[i], oneHoleMovements[i], bs); + for ( s = 1; s <= steps; s ++ ) { - if (!extrudeByPath) { + for ( i = 0; i < vlen; i ++ ) { - v(vert.x, vert.y, amount + z); + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - } else { + if ( ! extrudeByPath ) { - v(vert.x, vert.y + extrudePts[steps - 1].y, extrudePts[steps - 1].x + z); + v( vert.x, vert.y, amount / steps * s ); - } + } else { - } + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - } + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - } + position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - /* Faces */ + v( position2.x, position2.y, position2.z ); - // Top and bottom faces + } - buildLidFaces(); + } - // Sides faces + } - buildSideFaces(); + // Add bevel segments planes - ///// Internal functions + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { - function buildLidFaces() { + 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 ); - if (bevelEnabled) { + // contract shape - var layer = 0; // steps + 1 - var offset = vlen * layer; + for ( i = 0, il = contour.length; i < il; i ++ ) { - // Bottom faces + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, amount + z ); - for (i = 0; i < flen; i++) { + } - face = faces[i]; - f3(face[2] + offset, face[1] + offset, face[0] + offset); + // expand holes - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - layer = steps + bevelSegments * 2; - offset = vlen * layer; + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - // Top faces + for ( i = 0, il = ahole.length; i < il; i ++ ) { - for (i = 0; i < flen; i++) { + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - face = faces[i]; - f3(face[0] + offset, face[1] + offset, face[2] + offset); + if ( ! extrudeByPath ) { - } + v( vert.x, vert.y, amount + z ); - } else { + } else { - // Bottom faces + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - for (i = 0; i < flen; i++) { + } - face = faces[i]; - f3(face[2], face[1], face[0]); + } - } + } - // Top faces + } - for (i = 0; i < flen; i++) { + /* Faces */ - face = faces[i]; - f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps); + // Top and bottom faces - } - } + buildLidFaces(); - } + // Sides faces - // Create faces for the z-sides of the shape + buildSideFaces(); - function buildSideFaces() { - var layeroffset = 0; - sidewalls(contour, layeroffset); - layeroffset += contour.length; + ///// Internal functions - for (h = 0, hl = holes.length; h < hl; h++) { + function buildLidFaces() { - ahole = holes[h]; - sidewalls(ahole, layeroffset); + if ( bevelEnabled ) { - //, true - layeroffset += ahole.length; + var layer = 0; // steps + 1 + var offset = vlen * layer; - } + // Bottom faces - } + for ( i = 0; i < flen; i ++ ) { - function sidewalls(contour, layeroffset) { + face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - var j, k; - i = contour.length; + } - while (--i >= 0) { + layer = steps + bevelSegments * 2; + offset = vlen * layer; - j = i; - k = i - 1; - if (k < 0) k = contour.length - 1; + // Top faces - //THREE.log('b', i,j, i-1, k,vertices.length); + for ( i = 0; i < flen; i ++ ) { - var s = 0, sl = steps + bevelSegments * 2; + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - for (s = 0; s < sl; s++) { + } - var slen1 = vlen * s; - var slen2 = vlen * ( s + 1 ); + } else { - var a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; + // Bottom faces - f4(a, b, c, d, contour, s, sl, j, k); + for ( i = 0; i < flen; i ++ ) { - } - } + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - } + } + // Top faces - function v(x, y, z) { + for ( i = 0; i < flen; i ++ ) { - scope.vertices.push(new THREE.Vector3(x, y, z)); + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - } + } - function f3(a, b, c) { + } - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; + } - scope.faces.push(new THREE.Face3(a, b, c)); + // Create faces for the z-sides of the shape - var uvs = uvgen.generateTopUV(scope, a, b, c); + function buildSideFaces() { - scope.faceVertexUvs[0].push(uvs); + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - function f4(a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2) { + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - d += shapesOffset; + //, true + layeroffset += ahole.length; - scope.faces.push(new THREE.Face3(a, b, d)); - scope.faces.push(new THREE.Face3(b, c, d)); + } - 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]]); + function sidewalls( contour, layeroffset ) { - } + var j, k; + i = contour.length; + + while ( -- i >= 0 ) { + + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; + + //console.log('b', i,j, i-1, k,vertices.length); + + var s = 0, sl = steps + bevelSegments * 2; + + 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 ); + + } + + } + + } + + + function v( x, y, z ) { + + scope.vertices.push( new THREE.Vector3( x, y, z ) ); + + } + + function f3( a, b, c ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + + scope.faces.push( new THREE.Face3( a, b, c ) ); + + var uvs = uvgen.generateTopUV( scope, a, b, c ); + + scope.faceVertexUvs[ 0 ].push( uvs ); + + } + + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; + + scope.faces.push( new THREE.Face3( a, b, d ) ); + scope.faces.push( new THREE.Face3( b, c, d ) ); + + 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.ExtrudeGeometry.WorldUVGenerator = { - generateTopUV: function (geometry, indexA, indexB, indexC) { - - var vertices = geometry.vertices; - - var a = vertices[indexA]; - var b = vertices[indexB]; - var c = vertices[indexC]; - - return [ - new THREE.Vector2(a.x, a.y), - new THREE.Vector2(b.x, b.y), - new THREE.Vector2(c.x, c.y) - ]; - - }, - - generateSideWallUV: function (geometry, indexA, indexB, indexC, indexD) { - - var vertices = geometry.vertices; - - 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) - ]; - } - } + generateTopUV: function ( geometry, indexA, indexB, indexC ) { + + var vertices = geometry.vertices; + + var a = vertices[ indexA ]; + var b = vertices[ indexB ]; + var c = vertices[ indexC ]; + + return [ + new THREE.Vector2( a.x, a.y ), + new THREE.Vector2( b.x, b.y ), + new THREE.Vector2( c.x, c.y ) + ]; + + }, + + generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { + + var vertices = geometry.vertices; + + 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 ) + ]; + + } + + } }; // File:src/extras/geometries/ShapeGeometry.js @@ -31542,121 +33547,119 @@ THREE.ExtrudeGeometry.WorldUVGenerator = { * } **/ -THREE.ShapeGeometry = function (shapes, options) { +THREE.ShapeGeometry = function ( shapes, options ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'ShapeGeometry'; + this.type = 'ShapeGeometry'; - if (shapes instanceof Array === false) shapes = [shapes]; + if ( Array.isArray( shapes ) === false ) shapes = [ shapes ]; - this.addShapeList(shapes, options); + this.addShapeList( shapes, options ); - this.computeFaceNormals(); + this.computeFaceNormals(); }; -THREE.ShapeGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry; /** * Add an array of shapes to THREE.ShapeGeometry. */ -THREE.ShapeGeometry.prototype.addShapeList = function (shapes, options) { +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { - for (var i = 0, l = shapes.length; i < l; i++) { + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - this.addShape(shapes[i], options); + this.addShape( shapes[ i ], options ); - } + } - return this; + return this; }; /** * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. */ -THREE.ShapeGeometry.prototype.addShape = function (shape, options) { +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { - if (options === undefined) options = {}; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + 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; + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; - // + // - var i, l, hole; + var i, l, hole; - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints(curveSegments); + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - var reverse = !THREE.Shape.Utils.isClockWise(vertices); + var reverse = ! THREE.Shape.Utils.isClockWise( vertices ); - if (reverse) { + if ( reverse ) { - vertices = vertices.reverse(); + vertices = vertices.reverse(); - // Maybe we should also check if holes are in the opposite direction, just to be safe... + // 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++) { + for ( i = 0, l = holes.length; i < l; i ++ ) { - hole = holes[i]; + hole = holes[ i ]; - if (THREE.Shape.Utils.isClockWise(hole)) { + if ( THREE.Shape.Utils.isClockWise( hole ) ) { - holes[i] = hole.reverse(); + holes[ i ] = hole.reverse(); - } + } - } + } - reverse = false; + reverse = false; - } - - var faces = THREE.Shape.Utils.triangulateShape(vertices, holes); + } - // Vertices + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); - var contour = vertices; + // Vertices - for (i = 0, l = holes.length; i < l; i++) { + for ( i = 0, l = holes.length; i < l; i ++ ) { - hole = holes[i]; - vertices = vertices.concat(hole); + hole = holes[ i ]; + vertices = vertices.concat( hole ); - } + } - // + // - var vert, vlen = vertices.length; - var face, flen = faces.length; + var vert, vlen = vertices.length; + var face, flen = faces.length; - for (i = 0; i < vlen; i++) { + for ( i = 0; i < vlen; i ++ ) { - vert = vertices[i]; + vert = vertices[ i ]; - this.vertices.push(new THREE.Vector3(vert.x, vert.y, 0)); + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); - } + } - for (i = 0; i < flen; i++) { + for ( i = 0; i < flen; i ++ ) { - face = faces[i]; + face = faces[ i ]; - var a = face[0] + shapesOffset; - var b = face[1] + shapesOffset; - var c = face[2] + shapesOffset; + 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)); + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) ); - } + } }; @@ -31665,7 +33668,7 @@ THREE.ShapeGeometry.prototype.addShape = function (shape, options) { /** * @author astrodud / http://astrodud.isgreat.org/ * @author zz85 / https://github.com/zz85 - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io */ // points - to create a closed torus, one must use a set of points @@ -31675,432 +33678,409 @@ THREE.ShapeGeometry.prototype.addShape = function (shape, options) { // 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.LatheGeometry = function ( points, segments, phiStart, phiLength ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'LatheGeometry'; + this.type = 'LatheGeometry'; - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - segments = segments || 12; - phiStart = phiStart || 0; - phiLength = phiLength || 2 * Math.PI; + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; - var inversePointLength = 1.0 / ( points.length - 1 ); - var inverseSegments = 1.0 / segments; + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; - for (var i = 0, il = segments; i <= il; i++) { + for ( var i = 0, il = segments; i <= il; i ++ ) { - var phi = phiStart + i * inverseSegments * phiLength; + var phi = phiStart + i * inverseSegments * phiLength; - var c = Math.cos(phi), - s = Math.sin(phi); + var c = Math.cos( phi ), + s = Math.sin( phi ); - for (var j = 0, jl = points.length; j < jl; j++) { + for ( var j = 0, jl = points.length; j < jl; j ++ ) { - var pt = points[j]; + var pt = points[ j ]; - var vertex = new THREE.Vector3(); + var vertex = new THREE.Vector3(); - vertex.x = c * pt.x - s * pt.y; - vertex.y = s * pt.x + c * pt.y; - vertex.z = pt.z; + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; - this.vertices.push(vertex); + this.vertices.push( vertex ); - } + } - } + } - var np = points.length; + var np = points.length; - for (var i = 0, il = segments; i < il; i++) { + for ( var i = 0, il = segments; i < il; i ++ ) { - for (var j = 0, jl = points.length - 1; j < jl; j++) { + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { - var base = j + np * i; - var a = base; - var b = base + np; - var c = base + 1 + np; - var d = base + 1; + 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; + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; - this.faces.push(new THREE.Face3(a, b, d)); + this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[0].push([ + this.faceVertexUvs[ 0 ].push( [ - new THREE.Vector2(u0, v0), - new THREE.Vector2(u1, v0), - new THREE.Vector2(u0, v1) + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u0, v1 ) - ]); + ] ); - this.faces.push(new THREE.Face3(b, c, d)); + this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[0].push([ + this.faceVertexUvs[ 0 ].push( [ - new THREE.Vector2(u1, v0), - new THREE.Vector2(u1, v1), - new THREE.Vector2(u0, v1) + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) - ]); + ] ); - } + } - } + } - this.mergeVertices(); - this.computeFaceNormals(); - this.computeVertexNormals(); + this.mergeVertices(); + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.LatheGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry; -// File:src/extras/geometries/PlaneGeometry.js - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -THREE.PlaneGeometry = function (width, height, widthSegments, heightSegments) { - - THREE.log('THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.'); - - THREE.Geometry.call(this); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - this.fromBufferGeometry(new THREE.PlaneBufferGeometry(width, height, widthSegments, heightSegments)); - -}; - -THREE.PlaneGeometry.prototype = Object.create(THREE.Geometry.prototype); -THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; - -// File:src/extras/geometries/PlaneBufferGeometry.js +// File:src/extras/geometries/PlaneGeometry.js /** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as */ -THREE.PlaneBufferGeometry = function (width, height, widthSegments, heightSegments) { +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { - THREE.BufferGeometry.call(this); + THREE.Geometry.call( this ); - this.type = 'PlaneBufferGeometry'; + this.type = 'PlaneGeometry'; - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - var width_half = width / 2; - var height_half = height / 2; + this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - var gridX = widthSegments || 1; - var gridY = heightSegments || 1; +}; - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; +THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; - var segment_width = width / gridX; - var segment_height = height / gridY; +THREE.PlaneGeometry.prototype.clone = function () { - var vertices = new Float32Array(gridX1 * gridY1 * 3); - var normals = new Float32Array(gridX1 * gridY1 * 3); - var uvs = new Float32Array(gridX1 * gridY1 * 2); + var geometry = new THREE.PlaneGeometry( + this.parameters.width, + this.parameters.height, + this.parameters.widthSegments, + this.parameters.heightSegments + ); - var offset = 0; - var offset2 = 0; + return geometry; - for (var iy = 0; iy < gridY1; iy++) { +}; - var y = iy * segment_height - height_half; +// File:src/extras/geometries/PlaneBufferGeometry.js - for (var ix = 0; ix < gridX1; ix++) { +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ - var x = ix * segment_width - width_half; +THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) { - vertices[offset] = x; - vertices[offset + 1] = -y; + THREE.BufferGeometry.call( this ); - normals[offset + 2] = 1; + this.type = 'PlaneBufferGeometry'; - uvs[offset2] = ix / gridX; - uvs[offset2 + 1] = 1 - ( iy / gridY ); + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - offset += 3; - offset2 += 2; + var width_half = width / 2; + var height_half = height / 2; - } + var gridX = Math.floor( widthSegments ) || 1; + var gridY = Math.floor( heightSegments ) || 1; - } + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; - offset = 0; + var segment_width = width / gridX; + var segment_height = height / gridY; - var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )(gridX * gridY * 6); + var vertices = new Float32Array( gridX1 * gridY1 * 3 ); + var normals = new Float32Array( gridX1 * gridY1 * 3 ); + var uvs = new Float32Array( gridX1 * gridY1 * 2 ); - for (var iy = 0; iy < gridY; iy++) { + var offset = 0; + var offset2 = 0; - for (var ix = 0; ix < gridX; ix++) { + for ( var iy = 0; iy < gridY1; iy ++ ) { - 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 y = iy * segment_height - height_half; - indices[offset] = a; - indices[offset + 1] = b; - indices[offset + 2] = d; + for ( var ix = 0; ix < gridX1; ix ++ ) { - indices[offset + 3] = b; - indices[offset + 4] = c; - indices[offset + 5] = d; + var x = ix * segment_width - width_half; - offset += 6; + vertices[ offset ] = x; + vertices[ offset + 1 ] = - y; - } + normals[ offset + 2 ] = 1; - } + uvs[ offset2 ] = ix / gridX; + uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); - 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)); + offset += 3; + offset2 += 2; -}; + } -THREE.PlaneBufferGeometry.prototype = Object.create(THREE.BufferGeometry.prototype); -THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; + } -// File:src/extras/geometries/RingGeometry.js + offset = 0; -/** - * @author Kaleb Murphy - */ + var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); -THREE.RingGeometry = function (innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength) { + for ( var iy = 0; iy < gridY; iy ++ ) { - THREE.Geometry.call(this); + for ( var ix = 0; ix < gridX; ix ++ ) { - this.type = 'RingGeometry'; + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + indices[ offset ] = a; + indices[ offset + 1 ] = b; + indices[ offset + 2 ] = d; - innerRadius = innerRadius || 0; - outerRadius = outerRadius || 50; + indices[ offset + 3 ] = b; + indices[ offset + 4 ] = c; + indices[ offset + 5 ] = d; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + offset += 6; - thetaSegments = thetaSegments !== undefined ? Math.max(3, thetaSegments) : 8; - phiSegments = phiSegments !== undefined ? Math.max(1, phiSegments) : 8; + } - var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + } - for (i = 0; i < phiSegments + 1; i++) { // concentric circles inside ring + this.setIndex( 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 ) ); - for (o = 0; o < thetaSegments + 1; o++) { // number of segments per circle +}; - var vertex = new THREE.Vector3(); - var segment = thetaStart + o / thetaSegments * thetaLength; - vertex.x = radius * Math.cos(segment); - vertex.y = radius * Math.sin(segment); +THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; - this.vertices.push(vertex); - uvs.push(new THREE.Vector2(( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2)); - } +THREE.PlaneBufferGeometry.prototype.clone = function () { - radius += radiusStep; + var geometry = new THREE.PlaneBufferGeometry( + this.parameters.width, + this.parameters.height, + this.parameters.widthSegments, + this.parameters.heightSegments + ); - } + geometry.copy( this ); - var n = new THREE.Vector3(0, 0, 1); + return geometry; - for (i = 0; i < phiSegments; i++) { // concentric circles inside ring +}; - var thetaSegment = i * (thetaSegments + 1); +// File:src/extras/geometries/RingGeometry.js - for (o = 0; o < thetaSegments; o++) { // number of segments per circle +/** + * @author Kaleb Murphy + */ - var segment = o + thetaSegment; +THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - var v1 = segment; - var v2 = segment + thetaSegments + 1; - var v3 = segment + thetaSegments + 2; + THREE.Geometry.call( this ); - 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()]); + this.type = 'RingGeometry'; - v1 = segment; - v2 = segment + thetaSegments + 2; - v3 = segment + 1; + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - 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()]); + innerRadius = innerRadius || 0; + outerRadius = outerRadius || 50; - } - } + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - this.computeFaceNormals(); + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 8; - this.boundingSphere = new THREE.Sphere(new THREE.Vector3(), radius); + var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); -}; + for ( i = 0; i < phiSegments + 1; i ++ ) { -THREE.RingGeometry.prototype = Object.create(THREE.Geometry.prototype); -THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; + // concentric circles inside ring + for ( o = 0; o < thetaSegments + 1; o ++ ) { -// File:src/extras/geometries/SphereGeometry.js + // number of segments per circle -/** - * @author mrdoob / http://mrdoob.com/ - */ + var vertex = new THREE.Vector3(); + var segment = thetaStart + o / thetaSegments * thetaLength; + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); -THREE.SphereGeometry = function (radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) { + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); - THREE.log('THREE.SphereGeometry: Consider using THREE.SphereBufferGeometry for lower memory footprint.'); + } - THREE.Geometry.call(this); + radius += radiusStep; - this.type = 'SphereGeometry'; + } - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + var n = new THREE.Vector3( 0, 0, 1 ); - radius = radius || 50; + for ( i = 0; i < phiSegments; i ++ ) { - widthSegments = Math.max(3, Math.floor(widthSegments) || 8); - heightSegments = Math.max(2, Math.floor(heightSegments) || 6); + // concentric circles inside ring - phiStart = phiStart !== undefined ? phiStart : 0; - phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + var thetaSegment = i * ( thetaSegments + 1 ); - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + for ( o = 0; o < thetaSegments ; o ++ ) { - var x, y, vertices = [], uvs = []; + // number of segments per circle - for (y = 0; y <= heightSegments; y++) { + var segment = o + thetaSegment; - var verticesRow = []; - var uvsRow = []; + var v1 = segment; + var v2 = segment + thetaSegments + 1; + var v3 = segment + thetaSegments + 2; - for (x = 0; x <= widthSegments; x++) { + 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() ] ); - var u = x / widthSegments; - var v = y / heightSegments; + v1 = segment; + v2 = segment + thetaSegments + 2; + v3 = segment + 1; - 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); + 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() ] ); - this.vertices.push(vertex); + } - verticesRow.push(this.vertices.length - 1); - uvsRow.push(new THREE.Vector2(u, 1 - v)); + } - } + this.computeFaceNormals(); - vertices.push(verticesRow); - uvs.push(uvsRow); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - } +}; - for (y = 0; y < heightSegments; y++) { +THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; - for (x = 0; x < widthSegments; x++) { +THREE.RingGeometry.prototype.clone = function () { - 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 geometry = new THREE.RingGeometry( + this.parameters.innerRadius, + this.parameters.outerRadius, + this.parameters.thetaSegments, + this.parameters.phiSegments, + this.parameters.thetaStart, + this.parameters.thetaLength + ); - 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(); + return geometry; - 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) === radius) { +// File:src/extras/geometries/SphereGeometry.js - 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]); +/** + * @author mrdoob / http://mrdoob.com/ + */ - } else if (Math.abs(this.vertices[v3].y) === radius) { +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - 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]); + THREE.Geometry.call( this ); - } else { + this.type = 'SphereGeometry'; - this.faces.push(new THREE.Face3(v1, v2, v4, [n1, n2, n4])); - this.faceVertexUvs[0].push([uv1, uv2, uv4]); + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.faces.push(new THREE.Face3(v2, v3, v4, [n2.clone(), n3, n4.clone()])); - this.faceVertexUvs[0].push([uv2.clone(), uv3, uv4.clone()]); + this.fromBufferGeometry( new THREE.SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); - } +}; - } +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); +THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; - } +THREE.SphereGeometry.prototype.clone = function () { - this.computeFaceNormals(); + var geometry = new THREE.SphereGeometry( + this.parameters.radius, + this.parameters.widthSegments, + this.parameters.heightSegments, + this.parameters.phiStart, + this.parameters.phiLength, + this.parameters.thetaStart, + this.parameters.thetaLength + ); - this.boundingSphere = new THREE.Sphere(new THREE.Vector3(), radius); + return geometry; }; -THREE.SphereGeometry.prototype = Object.create(THREE.Geometry.prototype); -THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; - // File:src/extras/geometries/SphereBufferGeometry.js /** @@ -32108,112 +34088,121 @@ THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; * based on THREE.SphereGeometry */ -THREE.SphereBufferGeometry = function (radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) { +THREE.SphereBufferGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - THREE.BufferGeometry.call(this); + THREE.BufferGeometry.call( this ); - this.type = 'SphereBufferGeometry'; + this.type = 'SphereBufferGeometry'; - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - radius = radius || 50; + radius = radius || 50; - widthSegments = Math.max(3, Math.floor(widthSegments) || 8); - heightSegments = Math.max(2, Math.floor(heightSegments) || 6); + 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; + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - var stride = ( 3 + 3 + 2 ); - var vertexBuffer = new THREE.InterleavedBuffer(new Float32Array(( ( widthSegments + 1 ) * ( heightSegments + 1 ) ) * stride), stride); + var thetaEnd = thetaStart + thetaLength; - var positions = new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0); - this.addAttribute('position', positions); - var normals = new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 3); - this.addAttribute('normal', normals); - var uvs = new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 6); - this.addAttribute('uv', uvs); + var vertexCount = ( ( widthSegments + 1 ) * ( heightSegments + 1 ) ); - var x, y, u, v, px, py, pz, index = 0, vertices = [], normal = new THREE.Vector3(); + var positions = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 ); + var normals = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 ); + var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 ); - for (y = 0; y <= heightSegments; y++) { + var index = 0, vertices = [], normal = new THREE.Vector3(); - var verticesRow = []; + for ( var y = 0; y <= heightSegments; y ++ ) { - v = y / heightSegments; + var verticesRow = []; - for (x = 0; x <= widthSegments; x++) { + var v = y / heightSegments; - u = x / widthSegments; + for ( var x = 0; x <= widthSegments; x ++ ) { - px = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); - py = radius * Math.cos(thetaStart + v * thetaLength); - pz = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); + var u = x / widthSegments; - normal.set(px, py, pz).normalize(); + var px = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + var py = radius * Math.cos( thetaStart + v * thetaLength ); + var pz = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - positions.setXYZ(index, px, py, pz); - normals.setXYZ(index, normal.x, normal.y, normal.z); - uvs.setXY(index, u, 1 - v); + normal.set( px, py, pz ).normalize(); - verticesRow.push(index); + positions.setXYZ( index, px, py, pz ); + normals.setXYZ( index, normal.x, normal.y, normal.z ); + uvs.setXY( index, u, 1 - v ); - index++; + verticesRow.push( index ); - } + index ++; - vertices.push(verticesRow); + } - } + vertices.push( verticesRow ); - var indices = []; - var ul; - for (y = 0, ul = heightSegments - 1; y < ul; y++) { + } - for (x = 0; x < widthSegments; x++) { + var indices = []; - var v1 = vertices[y][x + 1]; - var v2 = vertices[y][x]; - var v3 = vertices[y + 1][x]; - var v4 = vertices[y + 1][x + 1]; + for ( var y = 0; y < heightSegments; y ++ ) { - if (y !== 0) indices.push(v1, v2, v4); - indices.push(v2, v3, v4); + for ( var x = 0; x < 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 ]; - y = heightSegments; + if ( y !== 0 || thetaStart > 0 ) indices.push( v1, v2, v4 ); + if ( y !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( v2, v3, v4 ); - for (x = 0; x < widthSegments; x++) { + } - var v2 = vertices[y][x]; - var v3 = vertices[y - 1][x]; - var v4 = vertices[y - 1][x + 1]; + } - indices.push(v2, v4, v3); + this.setIndex( new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) ); + this.addAttribute( 'position', positions ); + this.addAttribute( 'normal', normals ); + this.addAttribute( 'uv', uvs ); - } + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.SphereBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); +THREE.SphereBufferGeometry.prototype.constructor = THREE.SphereBufferGeometry; + +THREE.SphereBufferGeometry.prototype.clone = function () { - this.addAttribute('index', new THREE.BufferAttribute(new Uint16Array(indices), 1)); + var geometry = new THREE.SphereBufferGeometry( + this.parameters.radius, + this.parameters.widthSegments, + this.parameters.heightSegments, + this.parameters.phiStart, + this.parameters.phiLength, + this.parameters.thetaStart, + this.parameters.thetaLength + ); - this.boundingSphere = new THREE.Sphere(new THREE.Vector3(), radius); + geometry.copy( this ); + + return geometry; }; -THREE.SphereBufferGeometry.prototype = Object.create(THREE.BufferGeometry.prototype); -THREE.SphereBufferGeometry.prototype.constructor = THREE.SphereBufferGeometry; // File:src/extras/geometries/TextGeometry.js /** @@ -32242,41 +34231,41 @@ THREE.SphereBufferGeometry.prototype.constructor = THREE.SphereBufferGeometry; /* Usage Examples - // TextGeometry wrapper + // TextGeometry wrapper - var text3d = new TextGeometry( text, options ); + var text3d = new TextGeometry( text, options ); - // Complete manner + // Complete manner - var textShapes = THREE.FontUtils.generateShapes( text, options ); - var text3d = new ExtrudeGeometry( textShapes, options ); + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); - */ +*/ -THREE.TextGeometry = function (text, parameters) { +THREE.TextGeometry = function ( text, parameters ) { - parameters = parameters || {}; + parameters = parameters || {}; - var textShapes = THREE.FontUtils.generateShapes(text, parameters); + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - // translate parameters to ExtrudeGeometry API + // translate parameters to ExtrudeGeometry API - parameters.amount = parameters.height !== undefined ? parameters.height : 50; + parameters.amount = parameters.height !== undefined ? parameters.height : 50; - // defaults + // defaults - if (parameters.bevelThickness === undefined) parameters.bevelThickness = 10; - if (parameters.bevelSize === undefined) parameters.bevelSize = 8; - if (parameters.bevelEnabled === undefined) parameters.bevelEnabled = false; + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - THREE.ExtrudeGeometry.call(this, textShapes, parameters); + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); - this.type = 'TextGeometry'; + this.type = 'TextGeometry'; }; -THREE.TextGeometry.prototype = Object.create(THREE.ExtrudeGeometry.prototype); +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); THREE.TextGeometry.prototype.constructor = THREE.TextGeometry; // File:src/extras/geometries/TorusGeometry.js @@ -32287,80 +34276,94 @@ THREE.TextGeometry.prototype.constructor = THREE.TextGeometry; * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 */ -THREE.TorusGeometry = function (radius, tube, radialSegments, tubularSegments, arc) { +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'TorusGeometry'; + this.type = 'TorusGeometry'; - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 8; - tubularSegments = tubularSegments || 6; - arc = arc || Math.PI * 2; + radius = radius || 100; + tube = tube || 40; + radialSegments = radialSegments || 8; + tubularSegments = tubularSegments || 6; + arc = arc || Math.PI * 2; - var center = new THREE.Vector3(), uvs = [], normals = []; + var center = new THREE.Vector3(), uvs = [], normals = []; - for (var j = 0; j <= radialSegments; j++) { + for ( var j = 0; j <= radialSegments; j ++ ) { - for (var i = 0; i <= tubularSegments; i++) { + for ( var i = 0; i <= tubularSegments; i ++ ) { - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; - center.x = radius * Math.cos(u); - center.y = radius * Math.sin(u); + 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); + 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); + this.vertices.push( vertex ); - uvs.push(new THREE.Vector2(i / tubularSegments, j / radialSegments)); - normals.push(vertex.clone().sub(center).normalize()); + uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); - } + } - } + } - for (var j = 1; j <= radialSegments; j++) { + for ( var j = 1; j <= radialSegments; j ++ ) { - for (var i = 1; i <= tubularSegments; i++) { + for ( var i = 1; i <= tubularSegments; i ++ ) { - 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; + 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; - 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 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() ] ); - 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()]); + 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() ] ); - } + } - } + } - this.computeFaceNormals(); + this.computeFaceNormals(); }; -THREE.TorusGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; +THREE.TorusGeometry.prototype.clone = function () { + + var geometry = new THREE.TorusGeometry( + this.parameters.radius, + this.parameters.tube, + this.parameters.radialSegments, + this.parameters.tubularSegments, + this.parameters.arc + ); + + return geometry; + +}; + // File:src/extras/geometries/TorusKnotGeometry.js /** @@ -32368,115 +34371,132 @@ THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; * 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.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'TorusKnotGeometry'; + this.type = 'TorusKnotGeometry'; - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - p: p, - q: q, - heightScale: heightScale - }; + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + p: p, + q: q, + heightScale: heightScale + }; - radius = radius || 100; - tube = tube || 40; - radialSegments = radialSegments || 64; - tubularSegments = tubularSegments || 8; - p = p || 2; - q = q || 3; - heightScale = heightScale || 1; + 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(); + var grid = new Array( radialSegments ); + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); - for (var i = 0; i < radialSegments; ++i) { + for ( var i = 0; i < radialSegments; ++ i ) { - 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); + 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 ); - bitan.crossVectors(tang, n); - n.crossVectors(bitan, tang); - bitan.normalize(); - n.normalize(); + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); - for (var j = 0; j < tubularSegments; ++j) { + for ( var j = 0; j < tubularSegments; ++ j ) { - 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); + 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 ); - 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; + 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; + grid[ i ][ j ] = this.vertices.push( pos ) - 1; - } + } - } + } - for (var i = 0; i < radialSegments; ++i) { + for ( var i = 0; i < radialSegments; ++ i ) { - for (var j = 0; j < tubularSegments; ++j) { + for ( var j = 0; j < tubularSegments; ++ j ) { - var ip = ( i + 1 ) % radialSegments; - var jp = ( j + 1 ) % tubularSegments; + 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]; + var a = grid[ i ][ j ]; + var b = grid[ ip ][ j ]; + var c = grid[ ip ][ jp ]; + var d = grid[ i ][ jp ]; - 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); + 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 ); - this.faces.push(new THREE.Face3(a, b, d)); - this.faceVertexUvs[0].push([uva, uvb, uvd]); + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - this.faces.push(new THREE.Face3(b, c, d)); - this.faceVertexUvs[0].push([uvb.clone(), uvc, uvd.clone()]); + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - } - } + } - this.computeFaceNormals(); - this.computeVertexNormals(); + } - function getPos(u, in_q, in_p, radius, heightScale) { + this.computeFaceNormals(); + this.computeVertexNormals(); - var cu = Math.cos(u); - var su = Math.sin(u); - var quOverP = in_q / in_p * u; - var cs = Math.cos(quOverP); + function getPos( u, in_q, in_p, radius, heightScale ) { - 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 cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); - return new THREE.Vector3(tx, ty, tz); + 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 = Object.create( THREE.Geometry.prototype ); THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; +THREE.TorusKnotGeometry.prototype.clone = function () { + + var geometry = new THREE.TorusKnotGeometry( + this.parameters.radius, + this.parameters.tube, + this.parameters.radialSegments, + this.parameters.tubularSegments, + this.parameters.p, + this.parameters.q, + this.parameters.heightScale + ); + + return geometry; + +}; + // File:src/extras/geometries/TubeGeometry.js /** @@ -32493,285 +34513,296 @@ THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; * http://www.cs.indiana.edu/pub/techreports/TR425.pdf */ -THREE.TubeGeometry = function (path, segments, radius, radialSegments, closed, taper) { +THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, taper ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'TubeGeometry'; + this.type = 'TubeGeometry'; - this.parameters = { - path: path, - segments: segments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + this.parameters = { + path: path, + segments: segments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; - segments = segments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; - taper = taper || THREE.TubeGeometry.NoTaper; + segments = segments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; + taper = taper || THREE.TubeGeometry.NoTaper; - var grid = []; + var grid = []; - var scope = this, + var scope = this, - tangent, - normal, - binormal, + tangent, + normal, + binormal, - numpoints = segments + 1, + numpoints = segments + 1, - u, v, r, + u, v, r, - cx, cy, - pos, pos2 = new THREE.Vector3(), - i, j, - ip, jp, - a, b, c, d, - uva, uvb, uvc, uvd; + 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; + 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; + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - function vert(x, y, z) { + function vert( x, y, z ) { - return scope.vertices.push(new THREE.Vector3(x, y, z)) - 1; + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; - } + } - // consruct the grid + // construct the grid - for (i = 0; i < numpoints; i++) { + for ( i = 0; i < numpoints; i ++ ) { - grid[i] = []; + grid[ i ] = []; - u = i / ( numpoints - 1 ); + u = i / ( numpoints - 1 ); - pos = path.getPointAt(u); + pos = path.getPointAt( u ); - tangent = tangents[i]; - normal = normals[i]; - binormal = binormals[i]; + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; - r = radius * taper(u); + r = radius * taper( u ); - for (j = 0; j < radialSegments; j++) { + for ( j = 0; j < radialSegments; j ++ ) { - v = j / radialSegments * 2 * Math.PI; + v = j / radialSegments * 2 * Math.PI; - cx = -r * Math.cos(v); // TODO: Hack: Negating it so it faces outside. - cy = r * Math.sin(v); + cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = r * Math.sin( v ); - 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; + 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; - grid[i][j] = vert(pos2.x, pos2.y, pos2.z); + grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); - } - } + } + } - // construct the mesh - for (i = 0; i < segments; i++) { + // construct the mesh - for (j = 0; j < radialSegments; j++) { + for ( i = 0; i < segments; i ++ ) { - ip = ( closed ) ? (i + 1) % segments : i + 1; - jp = (j + 1) % radialSegments; + for ( j = 0; j < radialSegments; j ++ ) { - a = grid[i][j]; // *** NOT NECESSARILY PLANAR ! *** - b = grid[ip][j]; - c = grid[ip][jp]; - d = grid[i][jp]; + ip = ( closed ) ? ( i + 1 ) % segments : i + 1; + jp = ( j + 1 ) % radialSegments; - 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); + a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = grid[ ip ][ j ]; + c = grid[ ip ][ jp ]; + d = grid[ i ][ jp ]; - this.faces.push(new THREE.Face3(a, b, d)); - this.faceVertexUvs[0].push([uva, uvb, uvd]); + 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 ); - this.faces.push(new THREE.Face3(b, c, d)); - this.faceVertexUvs[0].push([uvb.clone(), uvc, uvd.clone()]); + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - } - } + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - this.computeFaceNormals(); - this.computeVertexNormals(); + } + + } + + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.TubeGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; -THREE.TubeGeometry.NoTaper = function (u) { +THREE.TubeGeometry.NoTaper = function ( u ) { - return 1; + return 1; }; -THREE.TubeGeometry.SinusoidalTaper = function (u) { +THREE.TubeGeometry.SinusoidalTaper = function ( u ) { - return Math.sin(Math.PI * u); + return Math.sin( Math.PI * u ); }; // For computing of Frenet frames, exposing the tangents, normals and binormals the spline -THREE.TubeGeometry.FrenetFrames = function (path, segments, closed) { +THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { - var normal = new THREE.Vector3(), + var normal = new THREE.Vector3(), - tangents = [], - normals = [], - binormals = [], + tangents = [], + normals = [], + binormals = [], - vec = new THREE.Vector3(), - mat = new THREE.Matrix4(), + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), - numpoints = segments + 1, - theta, - epsilon = 0.0001, - smallest, + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, - tx, ty, tz, - i, u; + tx, ty, tz, + i, u; - // expose internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; - // compute the tangent vectors for each segment on the path + // compute the tangent vectors for each segment on the path - for (i = 0; i < numpoints; i++) { + for ( i = 0; i < numpoints; i ++ ) { - u = i / ( numpoints - 1 ); + u = i / ( numpoints - 1 ); - tangents[i] = path.getTangentAt(u); - tangents[i].normalize(); + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); - } + } - initialNormal3(); + 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(); - } + /* + 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(); + } - function initialNormal2() { + function initialNormal2() { - // This uses the Frenet-Serret formula for deriving binormal - var t2 = path.getTangentAt( epsilon ); + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); - normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); - binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + 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(); + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - } - */ + } + */ - function initialNormal3() { - // select an initial normal vector perpenicular to the first tangent vector, - // and in the direction of the smallest tangent xyz component + function initialNormal3() { - 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); + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component - if (tx <= smallest) { - smallest = tx; - normal.set(1, 0, 0); - } + 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 ); - if (ty <= smallest) { - smallest = ty; - normal.set(0, 1, 0); - } + if ( tx <= smallest ) { - if (tz <= smallest) { - normal.set(0, 0, 1); - } + smallest = tx; + normal.set( 1, 0, 0 ); - vec.crossVectors(tangents[0], normal).normalize(); + } - normals[0].crossVectors(tangents[0], vec); - binormals[0].crossVectors(tangents[0], normals[0]); - } + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); - // compute the slowly-varying normal and binormal vectors for each segment on the path + } - for (i = 1; i < numpoints; i++) { + if ( tz <= smallest ) { - normals[i] = normals[i - 1].clone(); + normal.set( 0, 0, 1 ); - binormals[i] = binormals[i - 1].clone(); + } - vec.crossVectors(tangents[i - 1], tangents[i]); + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - if (vec.length() > epsilon) { + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - vec.normalize(); + } - theta = Math.acos(THREE.Math.clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors - normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta)); + // compute the slowly-varying normal and binormal vectors for each segment on the path - } + for ( i = 1; i < numpoints; i ++ ) { - binormals[i].crossVectors(tangents[i], normals[i]); + normals[ i ] = normals[ i - 1 ].clone(); - } + binormals[ i ] = binormals[ i - 1 ].clone(); + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + if ( vec.length() > epsilon ) { - if (closed) { + vec.normalize(); - theta = Math.acos(THREE.Math.clamp(normals[0].dot(normals[numpoints - 1]), -1, 1)); - theta /= ( numpoints - 1 ); + theta = Math.acos( THREE.Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - if (tangents[0].dot(vec.crossVectors(normals[0], normals[numpoints - 1])) > 0) { + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - theta = -theta; + } - } + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - for (i = 1; i < numpoints; i++) { + } - // twist a little... - normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i)); - binormals[i].crossVectors(tangents[i], normals[i]); - } + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + + if ( closed ) { + + theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) ); + theta /= ( numpoints - 1 ); + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { + + theta = - theta; + + } + + for ( i = 1; i < numpoints; i ++ ) { + + // 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 @@ -32780,397 +34811,474 @@ THREE.TubeGeometry.FrenetFrames = function (path, segments, closed) { * @author clockworkgeek / https://github.com/clockworkgeek * @author timothypratley / https://github.com/timothypratley * @author WestLangley / http://github.com/WestLangley - */ +*/ -THREE.PolyhedronGeometry = function (vertices, indices, radius, detail) { +THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'PolyhedronGeometry'; + this.type = 'PolyhedronGeometry'; - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - radius = radius || 1; - detail = detail || 0; + radius = radius || 1; + detail = detail || 0; - var that = this; + var that = this; - for (var i = 0, l = vertices.length; i < l; i += 3) { + for ( var i = 0, l = vertices.length; i < l; i += 3 ) { - prepare(new THREE.Vector3(vertices[i], vertices[i + 1], vertices[i + 2])); + prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); - } + } - var p = this.vertices; + var p = this.vertices; - var faces = []; + var faces = []; - for (var i = 0, j = 0, l = indices.length; i < l; i += 3, j++) { + for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { - var v1 = p[indices[i]]; - var v2 = p[indices[i + 1]]; - var v3 = p[indices[i + 2]]; + var v1 = p[ indices[ i ] ]; + var v2 = p[ indices[ i + 1 ] ]; + var v3 = p[ indices[ i + 2 ] ]; - faces[j] = new THREE.Face3(v1.index, v2.index, v3.index, [v1.clone(), v2.clone(), v3.clone()]); + faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ], undefined, j ); - } + } - var centroid = new THREE.Vector3(); + var centroid = new THREE.Vector3(); - for (var i = 0, l = faces.length; i < l; i++) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - subdivide(faces[i], detail); + subdivide( faces[ i ], detail ); - } + } - // Handle case when face straddles the seam + // Handle case when face straddles the seam - for (var i = 0, l = this.faceVertexUvs[0].length; i < l; i++) { + for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { - var uvs = this.faceVertexUvs[0][i]; + var uvs = this.faceVertexUvs[ 0 ][ i ]; - var x0 = uvs[0].x; - var x1 = uvs[1].x; - var x2 = uvs[2].x; + 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)); + var max = Math.max( x0, Math.max( x1, x2 ) ); + var min = Math.min( x0, Math.min( x1, x2 ) ); - if (max > 0.9 && min < 0.1) { // 0.9 is somewhat arbitrary + if ( max > 0.9 && min < 0.1 ) { - if (x0 < 0.2) uvs[0].x += 1; - if (x1 < 0.2) uvs[1].x += 1; - if (x2 < 0.2) uvs[2].x += 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; - } + } + } - // Apply radius - for (var i = 0, l = this.vertices.length; i < l; i++) { + // Apply radius - this.vertices[i].multiplyScalar(radius); + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { - } + this.vertices[ i ].multiplyScalar( radius ); + } - // Merge vertices - this.mergeVertices(); + // Merge vertices - this.computeFaceNormals(); + this.mergeVertices(); - this.boundingSphere = new THREE.Sphere(new THREE.Vector3(), radius); + this.computeFaceNormals(); + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - // Project vector onto sphere's surface - function prepare(vector) { + // Project vector onto sphere's surface - var vertex = vector.normalize().clone(); - vertex.index = that.vertices.push(vertex) - 1; + function prepare( vector ) { - // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; - 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); + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. - return vertex; + 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 ); - } + return vertex; + } - // Approximate a curved face with recursively sub-divided triangles. - function make(v1, v2, v3) { + // Approximate a curved face with recursively sub-divided triangles. - var face = new THREE.Face3(v1.index, v2.index, v3.index, [v1.clone(), v2.clone(), v3.clone()]); - that.faces.push(face); + function make( v1, v2, v3, materialIndex ) { - centroid.copy(v1).add(v2).add(v3).divideScalar(3); + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ], undefined, materialIndex ); + that.faces.push( face ); - var azi = azimuth(centroid); + centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - that.faceVertexUvs[0].push([ - correctUV(v1.uv, v1, azi), - correctUV(v2.uv, v2, azi), - correctUV(v3.uv, v3, azi) - ]); + var azi = azimuth( centroid ); - } + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); + } - // Analytically subdivide a face to the required detail level. - function subdivide(face, detail) { + // Analytically subdivide a face to the required detail level. - 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 = []; + function subdivide( face, detail ) { - // Construct all of the vertices for this subdivision. + 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 = []; - for (var i = 0; i <= cols; i++) { + var materialIndex = face.materialIndex; - v[i] = []; + // Construct all of the vertices for this subdivision. - var aj = prepare(a.clone().lerp(c, i / cols)); - var bj = prepare(b.clone().lerp(c, i / cols)); - var rows = cols - i; + for ( var i = 0 ; i <= cols; i ++ ) { - for (var j = 0; j <= rows; j++) { + v[ i ] = []; - if (j == 0 && i == cols) { + var aj = prepare( a.clone().lerp( c, i / cols ) ); + var bj = prepare( b.clone().lerp( c, i / cols ) ); + var rows = cols - i; - v[i][j] = aj; + for ( var j = 0; j <= rows; j ++ ) { - } else { + if ( j === 0 && i === cols ) { - v[i][j] = prepare(aj.clone().lerp(bj, j / rows)); + v[ i ][ j ] = aj; - } + } else { - } + v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); - } + } - // Construct all of the faces. + } - for (var i = 0; i < cols; i++) { + } - for (var j = 0; j < 2 * (cols - i) - 1; j++) { + // Construct all of the faces. - var k = Math.floor(j / 2); + for ( var i = 0; i < cols ; i ++ ) { - if (j % 2 == 0) { + for ( var j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - make( - v[i][k + 1], - v[i + 1][k], - v[i][k] - ); + var k = Math.floor( j / 2 ); - } else { + if ( j % 2 === 0 ) { - make( - v[i][k + 1], - v[i + 1][k + 1], - v[i + 1][k] - ); + make( + v[ i ][ k + 1 ], + v[ i + 1 ][ k ], + v[ i ][ k ], + materialIndex + ); - } + } else { - } + make( + v[ i ][ k + 1 ], + v[ i + 1 ][ k + 1 ], + v[ i + 1 ][ k ], + materialIndex + ); - } + } - } + } + } - // Angle around the Y axis, counter-clockwise when looking from above. + } - function azimuth(vector) { - return Math.atan2(vector.z, -vector.x); + // Angle around the Y axis, counter-clockwise when looking from above. - } + 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 ))); + // 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(); + // 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 = Object.create( THREE.Geometry.prototype ); THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry; +THREE.PolyhedronGeometry.prototype.clone = function () { + + var geometry = new THREE.PolyhedronGeometry( + this.parameters.vertices, + this.parameters.indices, + this.parameters.radius, + this.parameters.detail + ); + + return geometry.copy( this ); + +}; + +THREE.PolyhedronGeometry.prototype.copy = function ( source ) { + + THREE.Geometry.prototype.copy.call( this, source ); + return this; + +}; + // File:src/extras/geometries/DodecahedronGeometry.js /** * @author Abe Pazos / https://hamoid.com */ -THREE.DodecahedronGeometry = function (radius, detail) { +THREE.DodecahedronGeometry = function ( radius, detail ) { - this.parameters = { - radius: radius, - detail: detail - }; + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; - var t = ( 1 + Math.sqrt(5) ) / 2; - var r = 1 / t; + var vertices = [ - var vertices = [ + // (±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, - // (±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, + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, - // (0, ±1/φ, ±φ) - 0, -r, -t, 0, -r, t, - 0, r, -t, 0, r, t, + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, - // (±1/φ, ±φ, 0) - -r, -t, 0, -r, t, 0, - r, -t, 0, r, t, 0, + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; - // (±φ, 0, ±1/φ) - -t, 0, -r, t, 0, -r, - -t, 0, r, t, 0, r - ]; + 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 + ]; - 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.PolyhedronGeometry.call(this, vertices, indices, radius, detail); + this.type = 'DodecahedronGeometry'; + + this.parameters = { + radius: radius, + detail: detail + }; }; -THREE.DodecahedronGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.DodecahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry; +THREE.DodecahedronGeometry.prototype.clone = function () { + + var geometry = new THREE.DodecahedronGeometry( + this.parameters.radius, + this.parameters.detail + ); + + geometry.copy( this ); + + return geometry; + +}; + // File:src/extras/geometries/IcosahedronGeometry.js /** * @author timothypratley / https://github.com/timothypratley */ -THREE.IcosahedronGeometry = function (radius, detail) { +THREE.IcosahedronGeometry = function ( radius, detail ) { + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; - var t = ( 1 + Math.sqrt(5) ) / 2; + 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 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 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 + ]; - 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 - ]; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - THREE.PolyhedronGeometry.call(this, vertices, indices, radius, detail); + this.type = 'IcosahedronGeometry'; - this.type = 'IcosahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail + }; - this.parameters = { - radius: radius, - detail: detail - }; }; -THREE.IcosahedronGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.IcosahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry; +THREE.IcosahedronGeometry.prototype.clone = function () { + + var geometry = new THREE.IcosahedronGeometry( + this.parameters.radius, + this.parameters.detail + ); + + geometry.copy( this ); + + return geometry; + +}; + // File:src/extras/geometries/OctahedronGeometry.js /** * @author timothypratley / https://github.com/timothypratley */ -THREE.OctahedronGeometry = function (radius, detail) { +THREE.OctahedronGeometry = function ( radius, detail ) { - this.parameters = { - radius: radius, - detail: detail - }; + var vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; - var vertices = [ - 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -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 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 - ]; + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - THREE.PolyhedronGeometry.call(this, vertices, indices, radius, detail); + this.type = 'OctahedronGeometry'; - this.type = 'OctahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail + }; - this.parameters = { - radius: radius, - detail: detail - }; }; -THREE.OctahedronGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.OctahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry; +THREE.OctahedronGeometry.prototype.clone = function () { + + var geometry = new THREE.OctahedronGeometry( + this.parameters.radius, + this.parameters.detail + ); + + geometry.copy( this ); + + return geometry; + +}; + // File:src/extras/geometries/TetrahedronGeometry.js /** * @author timothypratley / https://github.com/timothypratley */ -THREE.TetrahedronGeometry = function (radius, detail) { +THREE.TetrahedronGeometry = function ( radius, detail ) { - var vertices = [ - 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1 - ]; + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; - var indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; - THREE.PolyhedronGeometry.call(this, vertices, indices, radius, detail); + THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); - this.type = 'TetrahedronGeometry'; + this.type = 'TetrahedronGeometry'; - this.parameters = { - radius: radius, - detail: detail - }; + this.parameters = { + radius: radius, + detail: detail + }; }; -THREE.TetrahedronGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.TetrahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; +THREE.TetrahedronGeometry.prototype.clone = function () { + + var geometry = new THREE.TetrahedronGeometry( + this.parameters.radius, + this.parameters.detail + ); + + geometry.copy( this ); + + return geometry; + +}; + // File:src/extras/geometries/ParametricGeometry.js /** @@ -33182,80 +35290,81 @@ THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; * */ -THREE.ParametricGeometry = function (func, slices, stacks) { +THREE.ParametricGeometry = function ( func, slices, stacks ) { - THREE.Geometry.call(this); + THREE.Geometry.call( this ); - this.type = 'ParametricGeometry'; + this.type = 'ParametricGeometry'; - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; - var verts = this.vertices; - var faces = this.faces; - var uvs = this.faceVertexUvs[0]; + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; - var i, j, p; - var u, v; + var i, j, p; + var u, v; - var sliceCount = slices + 1; + var sliceCount = slices + 1; - for (i = 0; i <= stacks; i++) { + for ( i = 0; i <= stacks; i ++ ) { - v = i / stacks; + v = i / stacks; - for (j = 0; j <= slices; j++) { + for ( j = 0; j <= slices; j ++ ) { - u = j / slices; + u = j / slices; - p = func(u, v); - verts.push(p); + p = func( u, v ); + verts.push( p ); - } - } + } - var a, b, c, d; - var uva, uvb, uvc, uvd; + } - for (i = 0; i < stacks; i++) { + var a, b, c, d; + var uva, uvb, uvc, uvd; - for (j = 0; j < slices; j++) { + for ( i = 0; i < stacks; i ++ ) { - a = i * sliceCount + j; - b = i * sliceCount + j + 1; - c = (i + 1) * sliceCount + j + 1; - d = (i + 1) * sliceCount + j; + for ( j = 0; j < slices; 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); + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = ( i + 1 ) * sliceCount + j + 1; + d = ( i + 1 ) * sliceCount + j; - faces.push(new THREE.Face3(a, b, d)); - uvs.push([uva, uvb, uvd]); + 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(b, c, d)); - uvs.push([uvb.clone(), uvc, uvd.clone()]); + 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.log(this); + } - // magic bullet - // var diff = this.mergeVertices(); - // THREE.log('removed ', diff, ' vertices by merging'); + // console.log(this); - this.computeFaceNormals(); - this.computeVertexNormals(); + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); + + this.computeFaceNormals(); + this.computeVertexNormals(); }; -THREE.ParametricGeometry.prototype = Object.create(THREE.Geometry.prototype); +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; // File:src/extras/geometries/WireframeGeometry.js @@ -33264,175 +35373,182 @@ THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; * @author mrdoob / http://mrdoob.com/ */ -THREE.WireframeGeometry = function (geometry) { +THREE.WireframeGeometry = function ( geometry ) { - THREE.BufferGeometry.call(this); + THREE.BufferGeometry.call( this ); - var edge = [0, 0], hash = {}; - var sortFunction = function (a, b) { - return a - b - }; + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { - var keys = ['a', 'b', 'c']; + return a - b; - if (geometry instanceof THREE.Geometry) { + }; - var vertices = geometry.vertices; - var faces = geometry.faces; - var numEdges = 0; + var keys = [ 'a', 'b', 'c' ]; - // allocate maximal size - var edges = new Uint32Array(6 * faces.length); + if ( geometry instanceof THREE.Geometry ) { - for (var i = 0, l = faces.length; i < l; i++) { + var vertices = geometry.vertices; + var faces = geometry.faces; + var numEdges = 0; - var face = faces[i]; + // allocate maximal size + var edges = new Uint32Array( 6 * faces.length ); - for (var j = 0; j < 3; j++) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - edge[0] = face[keys[j]]; - edge[1] = face[keys[( j + 1 ) % 3]]; - edge.sort(sortFunction); + var face = faces[ i ]; - var key = edge.toString(); + for ( var j = 0; j < 3; j ++ ) { - if (hash[key] === undefined) { + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); - edges[2 * numEdges] = edge[0]; - edges[2 * numEdges + 1] = edge[1]; - hash[key] = true; - numEdges++; + var key = edge.toString(); - } + if ( hash[ key ] === undefined ) { - } + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - } + } - var coords = new Float32Array(numEdges * 2 * 3); + } - for (var i = 0, l = numEdges; i < l; i++) { + } - for (var j = 0; j < 2; j++) { + var coords = new Float32Array( numEdges * 2 * 3 ); - var vertex = vertices[edges [2 * i + j]]; + for ( var i = 0, l = numEdges; i < l; i ++ ) { - var index = 6 * i + 3 * j; - coords[index + 0] = vertex.x; - coords[index + 1] = vertex.y; - coords[index + 2] = vertex.z; + 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; - this.addAttribute('position', new THREE.BufferAttribute(coords, 3)); + } - } else if (geometry instanceof THREE.BufferGeometry) { + } - if (geometry.attributes.index !== undefined) { // Indexed BufferGeometry + this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - var vertices = geometry.attributes.position; - var indices = geometry.attributes.index.array; - var drawcalls = geometry.drawcalls; - var numEdges = 0; + } else if ( geometry instanceof THREE.BufferGeometry ) { - if (drawcalls.length === 0) { + if ( geometry.index !== null ) { - drawcalls = [{count: indices.length, index: 0, start: 0}]; + // Indexed BufferGeometry - } + var indices = geometry.index.array; + var vertices = geometry.attributes.position; + var drawcalls = geometry.drawcalls; + var numEdges = 0; - // allocate maximal size - var edges = new Uint32Array(2 * indices.length); + if ( drawcalls.length === 0 ) { - for (var o = 0, ol = drawcalls.length; o < ol; ++o) { + geometry.addGroup( 0, indices.length ); - var start = drawcalls[o].start; - var count = drawcalls[o].count; - var index = drawcalls[o].index; + } - for (var i = start, il = start + count; i < il; i += 3) { + // allocate maximal size + var edges = new Uint32Array( 2 * indices.length ); - for (var j = 0; j < 3; j++) { + for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) { - edge[0] = index + indices[i + j]; - edge[1] = index + indices[i + ( j + 1 ) % 3]; - edge.sort(sortFunction); + var drawcall = drawcalls[ o ]; - var key = edge.toString(); + var start = drawcall.start; + var count = drawcall.count; - if (hash[key] === undefined) { + for ( var i = start, il = start + count; i < il; i += 3 ) { - edges[2 * numEdges] = edge[0]; - edges[2 * numEdges + 1] = edge[1]; - hash[key] = true; - numEdges++; + for ( var j = 0; j < 3; j ++ ) { - } + edge[ 0 ] = indices[ i + j ]; + edge[ 1 ] = indices[ i + ( j + 1 ) % 3 ]; + edge.sort( sortFunction ); - } + var key = edge.toString(); - } + if ( hash[ key ] === undefined ) { - } + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; - var coords = new Float32Array(numEdges * 2 * 3); + } - for (var i = 0, l = numEdges; i < l; i++) { + } - for (var j = 0; j < 2; j++) { + } - var index = 6 * i + 3 * j; - var index2 = edges[2 * i + j]; + } - coords[index + 0] = vertices.getX(index2); - coords[index + 1] = vertices.getY(index2); - coords[index + 2] = vertices.getZ(index2); + var coords = new Float32Array( numEdges * 2 * 3 ); - } + for ( var i = 0, l = numEdges; i < l; i ++ ) { - } + for ( var j = 0; j < 2; j ++ ) { - this.addAttribute('position', new THREE.BufferAttribute(coords, 3)); + var index = 6 * i + 3 * j; + var index2 = edges[ 2 * i + j ]; - } else { // non-indexed BufferGeometry + coords[ index + 0 ] = vertices.getX( index2 ); + coords[ index + 1 ] = vertices.getY( index2 ); + coords[ index + 2 ] = vertices.getZ( index2 ); - var vertices = geometry.attributes.position.array; - var numEdges = vertices.length / 3; - var numTris = numEdges / 3; + } - var coords = new Float32Array(numEdges * 2 * 3); + } - for (var i = 0, l = numTris; i < l; i++) { + this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); - for (var j = 0; j < 3; j++) { + } else { - var index = 18 * i + 6 * j; + // non-indexed BufferGeometry - var index1 = 9 * i + 3 * j; - coords[index + 0] = vertices[index1]; - coords[index + 1] = vertices[index1 + 1]; - coords[index + 2] = vertices[index1 + 2]; + var vertices = geometry.attributes.position.array; + var numEdges = vertices.length / 3; + var numTris = numEdges / 3; - 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]; + var coords = new Float32Array( numEdges * 2 * 3 ); - } + for ( var i = 0, l = numTris; i < l; i ++ ) { - } + for ( var j = 0; j < 3; j ++ ) { - this.addAttribute('position', new THREE.BufferAttribute(coords, 3)); + var index = 18 * i + 6 * j; - } + var index1 = 9 * i + 3 * j; + coords[ index + 0 ] = vertices[ index1 ]; + coords[ index + 1 ] = vertices[ index1 + 1 ]; + coords[ index + 2 ] = vertices[ index1 + 2 ]; - } + 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 ]; + + } + + } + + this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); + + } + + } }; -THREE.WireframeGeometry.prototype = Object.create(THREE.BufferGeometry.prototype); +THREE.WireframeGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.WireframeGeometry.prototype.constructor = THREE.WireframeGeometry; // File:src/extras/helpers/AxisHelper.js @@ -33442,33 +35558,33 @@ THREE.WireframeGeometry.prototype.constructor = THREE.WireframeGeometry; * @author mrdoob / http://mrdoob.com/ */ -THREE.AxisHelper = function (size) { +THREE.AxisHelper = function ( size ) { - size = size || 1; + 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 - ]); + var vertices = new Float32Array( [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ] ); - 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 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 geometry = new THREE.BufferGeometry(); - geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); - geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3)); + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); - var material = new THREE.LineBasicMaterial({vertexColors: THREE.VertexColors}); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - THREE.Line.call(this, geometry, material, THREE.LinePieces); + THREE.LineSegments.call( this, geometry, material ); }; -THREE.AxisHelper.prototype = Object.create(THREE.Line.prototype); +THREE.AxisHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; // File:src/extras/helpers/ArrowHelper.js @@ -33476,7 +35592,7 @@ THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; /** * @author WestLangley / http://github.com/WestLangley * @author zz85 / http://github.com/zz85 - * @author bhouston / http://exocortex.com + * @author bhouston / http://clara.io * * Creates an arrow for visualizing directions * @@ -33491,92 +35607,96 @@ THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; THREE.ArrowHelper = ( function () { - var lineGeometry = new THREE.Geometry(); - lineGeometry.vertices.push(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 1, 0)); - - var coneGeometry = new THREE.CylinderGeometry(0, 0.5, 1, 5, 1); - coneGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, -0.5, 0)); + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); - return function (dir, origin, length, color, headLength, headWidth) { + var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.translate( 0, - 0.5, 0 ); - // dir is assumed to be normalized + return function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { - THREE.Object3D.call(this); + // dir is assumed to be normalized - if (color === undefined) color = 0xffff00; - if (length === undefined) length = 1; - if (headLength === undefined) headLength = 0.2 * length; - if (headWidth === undefined) headWidth = 0.2 * headLength; + THREE.Object3D.call( this ); - this.position.copy(origin); + 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.line = new THREE.Line(lineGeometry, new THREE.LineBasicMaterial({color: color})); - this.line.matrixAutoUpdate = false; - this.add(this.line); + this.position.copy( origin ); + + if ( headLength < length ) { + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + } - this.cone = new THREE.Mesh(coneGeometry, new THREE.MeshBasicMaterial({color: color})); - this.cone.matrixAutoUpdate = false; - this.add(this.cone); + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); - this.setDirection(dir); - this.setLength(length, headLength, headWidth); + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); - } + } }() ); -THREE.ArrowHelper.prototype = Object.create(THREE.Object3D.prototype); +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; + var axis = new THREE.Vector3(); + var radians; - return function (dir) { + return function setDirection( dir ) { - // dir is assumed to be normalized + // dir is assumed to be normalized - if (dir.y > 0.99999) { + if ( dir.y > 0.99999 ) { - this.quaternion.set(0, 0, 0, 1); + this.quaternion.set( 0, 0, 0, 1 ); - } else if (dir.y < -0.99999) { + } else if ( dir.y < - 0.99999 ) { - this.quaternion.set(1, 0, 0, 0); + this.quaternion.set( 1, 0, 0, 0 ); - } else { + } else { - axis.set(dir.z, 0, -dir.x).normalize(); + axis.set( dir.z, 0, - dir.x ).normalize(); - radians = Math.acos(dir.y); + radians = Math.acos( dir.y ); - this.quaternion.setFromAxisAngle(axis, radians); + this.quaternion.setFromAxisAngle( axis, radians ); - } + } - }; + }; }() ); -THREE.ArrowHelper.prototype.setLength = function (length, headLength, headWidth) { +THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { - if (headLength === undefined) headLength = 0.2 * length; - if (headWidth === undefined) headWidth = 0.2 * headLength; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; - this.line.scale.set(1, length - headLength, 1); - this.line.updateMatrix(); + if ( headLength < length ){ + this.line.scale.set( 1, length - headLength, 1 ); + this.line.updateMatrix(); + } - this.cone.scale.set(headWidth, headLength, headWidth); - this.cone.position.y = length; - this.cone.updateMatrix(); + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); }; -THREE.ArrowHelper.prototype.setColor = function (color) { +THREE.ArrowHelper.prototype.setColor = function ( color ) { - this.line.material.color.set(color); - this.cone.material.color.set(color); + if ( this.line !== undefined ) this.line.material.color.set( color ); + this.cone.material.color.set( color ); }; @@ -33586,151 +35706,76 @@ THREE.ArrowHelper.prototype.setColor = function (color) { * @author mrdoob / http://mrdoob.com/ */ -THREE.BoxHelper = function (object) { +THREE.BoxHelper = function ( object ) { - var geometry = new THREE.BufferGeometry(); - geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(72), 3)); + var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + var positions = new Float32Array( 8 * 3 ); - THREE.Line.call(this, geometry, new THREE.LineBasicMaterial({color: 0xffff00}), THREE.LinePieces); + var geometry = new THREE.BufferGeometry(); + geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); - if (object !== undefined) { + THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ) ); - this.update(object); + if ( object !== undefined ) { - } + this.update( object ); + + } }; -THREE.BoxHelper.prototype = Object.create(THREE.Line.prototype); +THREE.BoxHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.BoxHelper.prototype.constructor = THREE.BoxHelper; -THREE.BoxHelper.prototype.update = function (object) { +THREE.BoxHelper.prototype.update = ( function () { - var geometry = object.geometry; + var box = new THREE.Box3(); - if (geometry.boundingBox === null) { + return function ( object ) { - geometry.computeBoundingBox(); + box.setFromObject( object ); - } + if ( box.empty() ) return; - var min = geometry.boundingBox.min; - var max = geometry.boundingBox.max; - - /* - 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 - */ - - var vertices = this.geometry.attributes.position.array; - - vertices[0] = max.x; - vertices[1] = max.y; - vertices[2] = max.z; - vertices[3] = min.x; - vertices[4] = max.y; - vertices[5] = max.z; - - vertices[6] = min.x; - vertices[7] = max.y; - vertices[8] = max.z; - vertices[9] = min.x; - vertices[10] = min.y; - vertices[11] = max.z; - - vertices[12] = min.x; - vertices[13] = min.y; - vertices[14] = max.z; - vertices[15] = max.x; - vertices[16] = min.y; - vertices[17] = max.z; - - vertices[18] = max.x; - vertices[19] = min.y; - vertices[20] = max.z; - vertices[21] = max.x; - vertices[22] = max.y; - vertices[23] = max.z; - - // - - vertices[24] = max.x; - vertices[25] = max.y; - vertices[26] = min.z; - vertices[27] = min.x; - vertices[28] = max.y; - vertices[29] = min.z; - - vertices[30] = min.x; - vertices[31] = max.y; - vertices[32] = min.z; - vertices[33] = min.x; - vertices[34] = min.y; - vertices[35] = min.z; - - vertices[36] = min.x; - vertices[37] = min.y; - vertices[38] = min.z; - vertices[39] = max.x; - vertices[40] = min.y; - vertices[41] = min.z; - - vertices[42] = max.x; - vertices[43] = min.y; - vertices[44] = min.z; - vertices[45] = max.x; - vertices[46] = max.y; - vertices[47] = min.z; - - // - - vertices[48] = max.x; - vertices[49] = max.y; - vertices[50] = max.z; - vertices[51] = max.x; - vertices[52] = max.y; - vertices[53] = min.z; - - vertices[54] = min.x; - vertices[55] = max.y; - vertices[56] = max.z; - vertices[57] = min.x; - vertices[58] = max.y; - vertices[59] = min.z; - - vertices[60] = min.x; - vertices[61] = min.y; - vertices[62] = max.z; - vertices[63] = min.x; - vertices[64] = min.y; - vertices[65] = min.z; - - vertices[66] = max.x; - vertices[67] = min.y; - vertices[68] = max.z; - vertices[69] = max.x; - vertices[70] = min.y; - vertices[71] = min.z; - - this.geometry.attributes.position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + var min = box.min; + var max = box.max; -}; + /* + 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 + */ + + var position = this.geometry.attributes.position; + var array = position.array; + + array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; + array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; + array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; + array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; + array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; + array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; + array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; + array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + + position.needsUpdate = true; + + this.geometry.computeBoundingSphere(); + + } + +} )(); // File:src/extras/helpers/BoundingBoxHelper.js @@ -33740,28 +35785,28 @@ THREE.BoxHelper.prototype.update = function (object) { // a helper to show the world-axis-aligned bounding box for an object -THREE.BoundingBoxHelper = function (object, hex) { +THREE.BoundingBoxHelper = function ( object, hex ) { - var color = ( hex !== undefined ) ? hex : 0x888888; + var color = ( hex !== undefined ) ? hex : 0x888888; - this.object = object; + this.object = object; - this.box = new THREE.Box3(); + this.box = new THREE.Box3(); - THREE.Mesh.call(this, new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({color: color, wireframe: true})); + THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); }; -THREE.BoundingBoxHelper.prototype = Object.create(THREE.Mesh.prototype); +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.setFromObject( this.object ); - this.box.size(this.scale); + this.box.size( this.scale ); - this.box.center(this.position); + this.box.center( this.position ); }; @@ -33770,188 +35815,188 @@ THREE.BoundingBoxHelper.prototype.update = function () { /** * @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 + * - 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 */ -THREE.CameraHelper = function (camera) { +THREE.CameraHelper = function ( camera ) { - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial({color: 0xffffff, vertexColors: THREE.FaceColors}); + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); - var pointMap = {}; + var pointMap = {}; - // colors + // colors - var hexFrustum = 0xffaa00; - var hexCone = 0xff0000; - var hexUp = 0x00aaff; - var hexTarget = 0xffffff; - var hexCross = 0x333333; + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; - // near + // near - addLine("n1", "n2", hexFrustum); - addLine("n2", "n4", hexFrustum); - addLine("n4", "n3", hexFrustum); - addLine("n3", "n1", hexFrustum); + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); - // far + // far - addLine("f1", "f2", hexFrustum); - addLine("f2", "f4", hexFrustum); - addLine("f4", "f3", hexFrustum); - addLine("f3", "f1", hexFrustum); + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); - // sides + // sides - addLine("n1", "f1", hexFrustum); - addLine("n2", "f2", hexFrustum); - addLine("n3", "f3", hexFrustum); - addLine("n4", "f4", hexFrustum); + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); - // cone + // cone - addLine("p", "n1", hexCone); - addLine("p", "n2", hexCone); - addLine("p", "n3", hexCone); - addLine("p", "n4", hexCone); + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); - // up + // up - addLine("u1", "u2", hexUp); - addLine("u2", "u3", hexUp); - addLine("u3", "u1", hexUp); + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); - // target + // target - addLine("c", "t", hexTarget); - addLine("p", "c", hexCross); + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); - // cross + // cross - addLine("cn1", "cn2", hexCross); - addLine("cn3", "cn4", hexCross); + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); - addLine("cf1", "cf2", hexCross); - addLine("cf3", "cf4", hexCross); + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); - function addLine(a, b, hex) { + function addLine( a, b, hex ) { - addPoint(a, hex); - addPoint(b, hex); + addPoint( a, hex ); + addPoint( b, hex ); - } + } - function addPoint(id, hex) { + function addPoint( id, hex ) { - geometry.vertices.push(new THREE.Vector3()); - geometry.colors.push(new THREE.Color(hex)); + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( hex ) ); - if (pointMap[id] === undefined) { + if ( pointMap[ id ] === undefined ) { - pointMap[id] = []; + pointMap[ id ] = []; - } + } - pointMap[id].push(geometry.vertices.length - 1); + pointMap[ id ].push( geometry.vertices.length - 1 ); - } + } - THREE.Line.call(this, geometry, material, THREE.LinePieces); + THREE.LineSegments.call( this, geometry, material ); - this.camera = camera; - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; + this.camera = camera; + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - this.pointMap = pointMap; + this.pointMap = pointMap; - this.update(); + this.update(); }; -THREE.CameraHelper.prototype = Object.create(THREE.Line.prototype); +THREE.CameraHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.CameraHelper.prototype.constructor = THREE.CameraHelper; THREE.CameraHelper.prototype.update = function () { - var geometry, pointMap; + var geometry, pointMap; - var vector = new THREE.Vector3(); - var camera = new THREE.Camera(); + var vector = new THREE.Vector3(); + var camera = new THREE.Camera(); - var setPoint = function (point, x, y, z) { + var setPoint = function ( point, x, y, z ) { - vector.set(x, y, z).unproject(camera); + vector.set( x, y, z ).unproject( camera ); - var points = pointMap[point]; + var points = pointMap[ point ]; - if (points !== undefined) { + if ( points !== undefined ) { - for (var i = 0, il = points.length; i < il; i++) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - geometry.vertices[points[i]].copy(vector); + geometry.vertices[ points[ i ] ].copy( vector ); - } + } - } + } - }; + }; - return function () { + return function () { - geometry = this.geometry; - pointMap = this.pointMap; + geometry = this.geometry; + pointMap = this.pointMap; - var w = 1, h = 1; + var w = 1, h = 1; - // we need just camera projection matrix - // world matrix must be identity + // we need just camera projection matrix + // world matrix must be identity - camera.projectionMatrix.copy(this.camera.projectionMatrix); + camera.projectionMatrix.copy( this.camera.projectionMatrix ); - // center / target + // center / target - setPoint("c", 0, 0, -1); - setPoint("t", 0, 0, 1); + setPoint( "c", 0, 0, - 1 ); + setPoint( "t", 0, 0, 1 ); - // near + // near - setPoint("n1", -w, -h, -1); - setPoint("n2", w, -h, -1); - setPoint("n3", -w, h, -1); - setPoint("n4", w, h, -1); + setPoint( "n1", - w, - h, - 1 ); + setPoint( "n2", w, - h, - 1 ); + setPoint( "n3", - w, h, - 1 ); + setPoint( "n4", w, h, - 1 ); - // far + // far - setPoint("f1", -w, -h, 1); - setPoint("f2", w, -h, 1); - setPoint("f3", -w, h, 1); - setPoint("f4", w, h, 1); + setPoint( "f1", - w, - h, 1 ); + setPoint( "f2", w, - h, 1 ); + setPoint( "f3", - w, h, 1 ); + setPoint( "f4", w, h, 1 ); - // up + // 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); + 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 + // cross - setPoint("cf1", -w, 0, 1); - setPoint("cf2", w, 0, 1); - setPoint("cf3", 0, -h, 1); - setPoint("cf4", 0, h, 1); + setPoint( "cf1", - w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, - h, 1 ); + setPoint( "cf4", 0, h, 1 ); - setPoint("cn1", -w, 0, -1); - setPoint("cn2", w, 0, -1); - setPoint("cn3", 0, -h, -1); - setPoint("cn4", 0, h, -1); + setPoint( "cn1", - w, 0, - 1 ); + setPoint( "cn2", w, 0, - 1 ); + setPoint( "cn3", 0, - h, - 1 ); + setPoint( "cn4", 0, h, - 1 ); - geometry.verticesNeedUpdate = true; + geometry.verticesNeedUpdate = true; - }; + }; }(); @@ -33963,80 +36008,81 @@ THREE.CameraHelper.prototype.update = function () { * @author WestLangley / http://github.com/WestLangley */ -THREE.DirectionalLightHelper = function (light, size) { +THREE.DirectionalLightHelper = function ( light, size ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.light = light; - this.light.updateMatrixWorld(); + this.light = light; + this.light.updateMatrixWorld(); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - size = size || 1; + 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 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); + var material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.lightPlane = new THREE.Line(geometry, material); - this.add(this.lightPlane); + this.lightPlane = new THREE.Line( geometry, material ); + this.add( this.lightPlane ); - geometry = new THREE.Geometry(); - geometry.vertices.push( - new THREE.Vector3(), - new THREE.Vector3() - ); + geometry = new THREE.Geometry(); + geometry.vertices.push( + new THREE.Vector3(), + new THREE.Vector3() + ); - material = new THREE.LineBasicMaterial({fog: false}); - material.color.copy(this.light.color).multiplyScalar(this.light.intensity); + material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.targetLine = new THREE.Line(geometry, material); - this.add(this.targetLine); + this.targetLine = new THREE.Line( geometry, material ); + this.add( this.targetLine ); - this.update(); + this.update(); }; -THREE.DirectionalLightHelper.prototype = Object.create(THREE.Object3D.prototype); +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(); + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); + }; THREE.DirectionalLightHelper.prototype.update = function () { - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var v3 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var v3 = new THREE.Vector3(); - return function () { + return function () { - v1.setFromMatrixPosition(this.light.matrixWorld); - v2.setFromMatrixPosition(this.light.target.matrixWorld); - v3.subVectors(v2, v1); + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); - this.lightPlane.lookAt(v3); - this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity); + this.lightPlane.lookAt( v3 ); + this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.targetLine.geometry.vertices[1].copy(v3); - this.targetLine.geometry.verticesNeedUpdate = true; - this.targetLine.material.color.copy(this.lightPlane.material.color); + this.targetLine.geometry.vertices[ 1 ].copy( v3 ); + this.targetLine.geometry.verticesNeedUpdate = true; + this.targetLine.material.color.copy( this.lightPlane.material.color ); - }; + }; }(); @@ -34046,24 +36092,24 @@ THREE.DirectionalLightHelper.prototype.update = function () { * @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), + * @param thresholdAngle the minimum 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. */ -THREE.EdgesHelper = function (object, hex, thresholdAngle) { +THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { - var color = ( hex !== undefined ) ? hex : 0xffffff; + var color = ( hex !== undefined ) ? hex : 0xffffff; - THREE.Line.call(this, new THREE.EdgesGeometry(object.geometry, thresholdAngle), new THREE.LineBasicMaterial({color: color}), THREE.LinePieces); + THREE.LineSegments.call( this, new THREE.EdgesGeometry( object.geometry, thresholdAngle ), new THREE.LineBasicMaterial( { color: color } ) ); - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; }; -THREE.EdgesHelper.prototype = Object.create(THREE.Line.prototype); +THREE.EdgesHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; // File:src/extras/helpers/FaceNormalsHelper.js @@ -34071,78 +36117,113 @@ THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley - */ +*/ -THREE.FaceNormalsHelper = function (object, size, hex, linewidth) { +THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { - this.object = object; + // FaceNormalsHelper only supports THREE.Geometry - this.size = ( size !== undefined ) ? size : 1; + this.object = object; - var color = ( hex !== undefined ) ? hex : 0xffff00; + this.size = ( size !== undefined ) ? size : 1; - var width = ( linewidth !== undefined ) ? linewidth : 1; + var color = ( hex !== undefined ) ? hex : 0xffff00; - var geometry = new THREE.Geometry(); + var width = ( linewidth !== undefined ) ? linewidth : 1; - var faces = this.object.geometry.faces; + // - for (var i = 0, l = faces.length; i < l; i++) { + var nNormals = 0; - geometry.vertices.push(new THREE.Vector3(), new THREE.Vector3()); + var objGeometry = this.object.geometry; - } + if ( objGeometry instanceof THREE.Geometry ) { + + nNormals = objGeometry.faces.length; - THREE.Line.call(this, geometry, new THREE.LineBasicMaterial({color: color, linewidth: width}), THREE.LinePieces); + } else { - this.matrixAutoUpdate = false; + console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); - this.normalMatrix = new THREE.Matrix3(); + } - this.update(); + // + + var geometry = new THREE.BufferGeometry(); + + var positions = new THREE.Float32Attribute( nNormals * 2 * 3, 3 ); + + geometry.addAttribute( 'position', positions ); + + THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ) ); + + // + + this.matrixAutoUpdate = false; + this.update(); }; -THREE.FaceNormalsHelper.prototype = Object.create(THREE.Line.prototype); +THREE.FaceNormalsHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper; -THREE.FaceNormalsHelper.prototype.update = function () { +THREE.FaceNormalsHelper.prototype.update = ( function () { - var vertices = this.geometry.vertices; + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var normalMatrix = new THREE.Matrix3(); - var object = this.object; - var objectVertices = object.geometry.vertices; - var objectFaces = object.geometry.faces; - var objectWorldMatrix = object.matrixWorld; + return function update() { - object.updateMatrixWorld(true); + this.object.updateMatrixWorld( true ); - this.normalMatrix.getNormalMatrix(objectWorldMatrix); + normalMatrix.getNormalMatrix( this.object.matrixWorld ); - for (var i = 0, i2 = 0, l = objectFaces.length; i < l; i++, i2 += 2) { + var matrixWorld = this.object.matrixWorld; - var face = objectFaces[i]; + var position = this.geometry.attributes.position; - vertices[i2].copy(objectVertices[face.a]) - .add(objectVertices[face.b]) - .add(objectVertices[face.c]) - .divideScalar(3) - .applyMatrix4(objectWorldMatrix); + // - vertices[i2 + 1].copy(face.normal) - .applyMatrix3(this.normalMatrix) - .normalize() - .multiplyScalar(this.size) - .add(vertices[i2]); + var objGeometry = this.object.geometry; - } + var vertices = objGeometry.vertices; - this.geometry.verticesNeedUpdate = true; + var faces = objGeometry.faces; - return this; + var idx = 0; -}; + for ( var i = 0, l = faces.length; i < l; i ++ ) { + var face = faces[ i ]; + + var normal = face.normal; + + v1.copy( vertices[ face.a ] ) + .add( vertices[ face.b ] ) + .add( vertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( matrixWorld ); + + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + + position.setXYZ( idx, v1.x, v1.y, v1.z ); + + idx = idx + 1; + + position.setXYZ( idx, v2.x, v2.y, v2.z ); + + idx = idx + 1; + + } + + position.needsUpdate = true; + + return this; + + } + +}() ); // File:src/extras/helpers/GridHelper.js @@ -34150,40 +36231,40 @@ THREE.FaceNormalsHelper.prototype.update = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.GridHelper = function (size, step) { +THREE.GridHelper = function ( size, step ) { - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial({vertexColors: THREE.VertexColors}); + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - this.color1 = new THREE.Color(0x444444); - this.color2 = new THREE.Color(0x888888); + this.color1 = new THREE.Color( 0x444444 ); + this.color2 = new THREE.Color( 0x888888 ); - for (var i = -size; i <= size; i += step) { + for ( var i = - size; i <= size; i += step ) { - 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) - ); + 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 color = i === 0 ? this.color1 : this.color2; + var color = i === 0 ? this.color1 : this.color2; - geometry.colors.push(color, color, color, color); + geometry.colors.push( color, color, color, color ); - } + } - THREE.Line.call(this, geometry, material, THREE.LinePieces); + THREE.LineSegments.call( this, geometry, material ); }; -THREE.GridHelper.prototype = Object.create(THREE.Line.prototype); +THREE.GridHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.GridHelper.prototype.constructor = THREE.GridHelper; -THREE.GridHelper.prototype.setColors = function (colorCenterLine, colorGrid) { +THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { - this.color1.set(colorCenterLine); - this.color2.set(colorGrid); + this.color1.set( colorCenterLine ); + this.color2.set( colorGrid ); - this.geometry.colorsNeedUpdate = true; + this.geometry.colorsNeedUpdate = true; }; @@ -34194,57 +36275,59 @@ THREE.GridHelper.prototype.setColors = function (colorCenterLine, colorGrid) { * @author mrdoob / http://mrdoob.com/ */ -THREE.HemisphereLightHelper = function (light, sphereSize) { +THREE.HemisphereLightHelper = function ( light, sphereSize ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.light = light; - this.light.updateMatrixWorld(); + this.light = light; + this.light.updateMatrixWorld(); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - this.colors = [new THREE.Color(), new THREE.Color()]; + this.colors = [ new THREE.Color(), new THREE.Color() ]; - var geometry = new THREE.SphereGeometry(sphereSize, 4, 2); - geometry.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2)); + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + geometry.rotateX( - Math.PI / 2 ); - for (var i = 0, il = 8; i < il; i++) { + for ( var i = 0, il = 8; i < il; i ++ ) { - geometry.faces[i].color = this.colors[i < 4 ? 0 : 1]; + geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; - } + } - var material = new THREE.MeshBasicMaterial({vertexColors: THREE.FaceColors, wireframe: true}); + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); - this.lightSphere = new THREE.Mesh(geometry, material); - this.add(this.lightSphere); + this.lightSphere = new THREE.Mesh( geometry, material ); + this.add( this.lightSphere ); - this.update(); + this.update(); }; -THREE.HemisphereLightHelper.prototype = Object.create(THREE.Object3D.prototype); +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(); + + this.lightSphere.geometry.dispose(); + this.lightSphere.material.dispose(); + }; THREE.HemisphereLightHelper.prototype.update = function () { - var vector = new THREE.Vector3(); + var vector = new THREE.Vector3(); - return function () { + 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.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); - this.lightSphere.lookAt(vector.setFromMatrixPosition(this.light.matrixWorld).negate()); - this.lightSphere.geometry.colorsNeedUpdate = true; + this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + this.lightSphere.geometry.colorsNeedUpdate = true; - } + } }(); @@ -34255,71 +36338,72 @@ THREE.HemisphereLightHelper.prototype.update = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.PointLightHelper = function (light, sphereSize) { +THREE.PointLightHelper = function ( light, sphereSize ) { - this.light = light; - this.light.updateMatrixWorld(); + this.light = light; + this.light.updateMatrixWorld(); - 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); + 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 ); - THREE.Mesh.call(this, geometry, material); + THREE.Mesh.call( this, geometry, material ); - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; - /* - var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + /* + var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - var d = light.distance; + var d = light.distance; - if ( d === 0.0 ) { + if ( d === 0.0 ) { - this.lightDistance.visible = false; + this.lightDistance.visible = false; - } else { + } else { - this.lightDistance.scale.set( d, d, d ); + this.lightDistance.scale.set( d, d, d ); - } + } - this.add( this.lightDistance ); - */ + this.add( this.lightDistance ); + */ }; -THREE.PointLightHelper.prototype = Object.create(THREE.Mesh.prototype); +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(); + this.geometry.dispose(); + this.material.dispose(); + }; THREE.PointLightHelper.prototype.update = function () { - this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity); + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - /* - var d = this.light.distance; + /* + var d = this.light.distance; - if ( d === 0.0 ) { + if ( d === 0.0 ) { - this.lightDistance.visible = false; + this.lightDistance.visible = false; - } else { + } else { - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); - } - */ + } + */ }; @@ -34332,100 +36416,97 @@ THREE.PointLightHelper.prototype.update = function () { * @author ikerr / http://verold.com */ -THREE.SkeletonHelper = function (object) { +THREE.SkeletonHelper = function ( object ) { - this.bones = this.getBoneList(object); + this.bones = this.getBoneList( object ); - var geometry = new THREE.Geometry(); + var geometry = new THREE.Geometry(); - for (var i = 0; i < this.bones.length; i++) { + for ( var i = 0; i < this.bones.length; i ++ ) { - var bone = this.bones[i]; + var bone = this.bones[ i ]; - if (bone.parent instanceof THREE.Bone) { + if ( bone.parent instanceof THREE.Bone ) { - 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)); + 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 ) ); - } + } - } + } - var material = new THREE.LineBasicMaterial({ - vertexColors: THREE.VertexColors, - depthTest: false, - depthWrite: false, - transparent: true - }); + geometry.dynamic = true; - THREE.Line.call(this, geometry, material, THREE.LinePieces); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } ); - this.root = object; + THREE.LineSegments.call( this, geometry, material ); - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + this.root = object; - this.update(); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; + + this.update(); }; -THREE.SkeletonHelper.prototype = Object.create(THREE.Line.prototype); +THREE.SkeletonHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper; -THREE.SkeletonHelper.prototype.getBoneList = function (object) { +THREE.SkeletonHelper.prototype.getBoneList = function( object ) { - var boneList = []; + var boneList = []; - if (object instanceof THREE.Bone) { + if ( object instanceof THREE.Bone ) { - boneList.push(object); + boneList.push( object ); - } + } - for (var i = 0; i < object.children.length; i++) { + for ( var i = 0; i < object.children.length; i ++ ) { - boneList.push.apply(boneList, this.getBoneList(object.children[i])); + boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); - } + } - return boneList; + return boneList; }; THREE.SkeletonHelper.prototype.update = function () { - var geometry = this.geometry; + var geometry = this.geometry; - var matrixWorldInv = new THREE.Matrix4().getInverse(this.root.matrixWorld); + var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld ); - var boneMatrix = new THREE.Matrix4(); + var boneMatrix = new THREE.Matrix4(); - var j = 0; + var j = 0; - for (var i = 0; i < this.bones.length; i++) { + for ( var i = 0; i < this.bones.length; i ++ ) { - var bone = this.bones[i]; + var bone = this.bones[ i ]; - if (bone.parent instanceof THREE.Bone) { + if ( bone.parent instanceof THREE.Bone ) { - boneMatrix.multiplyMatrices(matrixWorldInv, bone.matrixWorld); - geometry.vertices[j].setFromMatrixPosition(boneMatrix); + boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); + geometry.vertices[ j ].setFromMatrixPosition( boneMatrix ); - boneMatrix.multiplyMatrices(matrixWorldInv, bone.parent.matrixWorld); - geometry.vertices[j + 1].setFromMatrixPosition(boneMatrix); + boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); + geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix ); - j += 2; + j += 2; - } + } - } + } - geometry.verticesNeedUpdate = true; + geometry.verticesNeedUpdate = true; - geometry.computeBoundingSphere(); + geometry.computeBoundingSphere(); }; @@ -34435,60 +36516,62 @@ THREE.SkeletonHelper.prototype.update = function () { * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley - */ +*/ -THREE.SpotLightHelper = function (light) { +THREE.SpotLightHelper = function ( light ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.light = light; - this.light.updateMatrixWorld(); + this.light = light; + this.light.updateMatrixWorld(); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - var geometry = new THREE.CylinderGeometry(0, 1, 1, 8, 1, true); + var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); - geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, -0.5, 0)); - geometry.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2)); + geometry.translate( 0, - 0.5, 0 ); + geometry.rotateX( - Math.PI / 2 ); - var material = new THREE.MeshBasicMaterial({wireframe: true, fog: false}); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - this.cone = new THREE.Mesh(geometry, material); - this.add(this.cone); + this.cone = new THREE.Mesh( geometry, material ); + this.add( this.cone ); - this.update(); + this.update(); }; -THREE.SpotLightHelper.prototype = Object.create(THREE.Object3D.prototype); +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(); + + this.cone.geometry.dispose(); + this.cone.material.dispose(); + }; THREE.SpotLightHelper.prototype.update = function () { - var vector = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); + var vector = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); - return function () { + return function () { - var coneLength = this.light.distance ? this.light.distance : 10000; - var coneWidth = coneLength * Math.tan(this.light.angle); + var coneLength = this.light.distance ? this.light.distance : 10000; + var coneWidth = coneLength * Math.tan( this.light.angle ); - this.cone.scale.set(coneWidth, coneWidth, coneLength); + this.cone.scale.set( coneWidth, coneWidth, coneLength ); - vector.setFromMatrixPosition(this.light.matrixWorld); - vector2.setFromMatrixPosition(this.light.target.matrixWorld); + vector.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); - this.cone.lookAt(vector2.sub(vector)); + this.cone.lookAt( vector2.sub( vector ) ); - this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity); + this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - }; + }; }(); @@ -34497,199 +36580,148 @@ THREE.SpotLightHelper.prototype.update = function () { /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley - */ - -THREE.VertexNormalsHelper = function (object, size, hex, linewidth) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xff0000; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var faces = object.geometry.faces; - - for (var i = 0, l = faces.length; i < l; i++) { - - var face = faces[i]; - - for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) { - - geometry.vertices.push(new THREE.Vector3(), new THREE.Vector3()); - - } - - } - - THREE.Line.call(this, geometry, new THREE.LineBasicMaterial({color: color, linewidth: width}), THREE.LinePieces); - - this.matrixAutoUpdate = false; - - 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 (object) { - - var v1 = new THREE.Vector3(); - - return function (object) { +THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - var keys = ['a', 'b', 'c', 'd']; + this.object = object; - this.object.updateMatrixWorld(true); + this.size = ( size !== undefined ) ? size : 1; - this.normalMatrix.getNormalMatrix(this.object.matrixWorld); + var color = ( hex !== undefined ) ? hex : 0xff0000; - var vertices = this.geometry.vertices; + var width = ( linewidth !== undefined ) ? linewidth : 1; - var verts = this.object.geometry.vertices; + // - var faces = this.object.geometry.faces; + var nNormals = 0; - var worldMatrix = this.object.matrixWorld; + var objGeometry = this.object.geometry; - var idx = 0; + if ( objGeometry instanceof THREE.Geometry ) { - for (var i = 0, l = faces.length; i < l; i++) { + nNormals = objGeometry.faces.length * 3; - var face = faces[i]; + } else if ( objGeometry instanceof THREE.BufferGeometry ) { - for (var j = 0, jl = face.vertexNormals.length; j < jl; j++) { + nNormals = objGeometry.attributes.normal.count - var vertexId = face[keys[j]]; - var vertex = verts[vertexId]; + } - var normal = face.vertexNormals[j]; + // - vertices[idx].copy(vertex).applyMatrix4(worldMatrix); + var geometry = new THREE.BufferGeometry(); - v1.copy(normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size); + var positions = new THREE.Float32Attribute( nNormals * 2 * 3, 3 ); - v1.add(vertices[idx]); - idx = idx + 1; + geometry.addAttribute( 'position', positions ); - vertices[idx].copy(v1); - idx = idx + 1; + THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ) ); - } + // - } + this.matrixAutoUpdate = false; - this.geometry.verticesNeedUpdate = true; + this.update(); - return this; +}; - } +THREE.VertexNormalsHelper.prototype = Object.create( THREE.LineSegments.prototype ); +THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper; -}()); +THREE.VertexNormalsHelper.prototype.update = ( function () { -// File:src/extras/helpers/VertexTangentsHelper.js + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var normalMatrix = new THREE.Matrix3(); -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + return function update() { -THREE.VertexTangentsHelper = function (object, size, hex, linewidth) { + var keys = [ 'a', 'b', 'c' ]; - this.object = object; + this.object.updateMatrixWorld( true ); - this.size = ( size !== undefined ) ? size : 1; + normalMatrix.getNormalMatrix( this.object.matrixWorld ); - var color = ( hex !== undefined ) ? hex : 0x0000ff; + var matrixWorld = this.object.matrixWorld; - var width = ( linewidth !== undefined ) ? linewidth : 1; + var position = this.geometry.attributes.position; - var geometry = new THREE.Geometry(); + // - var faces = object.geometry.faces; + var objGeometry = this.object.geometry; - for (var i = 0, l = faces.length; i < l; i++) { + if ( objGeometry instanceof THREE.Geometry ) { - var face = faces[i]; + var vertices = objGeometry.vertices; - for (var j = 0, jl = face.vertexTangents.length; j < jl; j++) { + var faces = objGeometry.faces; - geometry.vertices.push(new THREE.Vector3()); - geometry.vertices.push(new THREE.Vector3()); + var idx = 0; - } + for ( var i = 0, l = faces.length; i < l; i ++ ) { - } + var face = faces[ i ]; - THREE.Line.call(this, geometry, new THREE.LineBasicMaterial({color: color, linewidth: width}), THREE.LinePieces); + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - this.matrixAutoUpdate = false; + var vertex = vertices[ face[ keys[ j ] ] ]; - this.update(); + var normal = face.vertexNormals[ j ]; -}; + v1.copy( vertex ).applyMatrix4( matrixWorld ); -THREE.VertexTangentsHelper.prototype = Object.create(THREE.Line.prototype); -THREE.VertexTangentsHelper.prototype.constructor = THREE.VertexTangentsHelper; + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); -THREE.VertexTangentsHelper.prototype.update = ( function (object) { + position.setXYZ( idx, v1.x, v1.y, v1.z ); - var v1 = new THREE.Vector3(); + idx = idx + 1; - return function (object) { + position.setXYZ( idx, v2.x, v2.y, v2.z ); - var keys = ['a', 'b', 'c', 'd']; + idx = idx + 1; - this.object.updateMatrixWorld(true); + } - var vertices = this.geometry.vertices; + } - var verts = this.object.geometry.vertices; + } else if ( objGeometry instanceof THREE.BufferGeometry ) { - var faces = this.object.geometry.faces; + var objPos = objGeometry.attributes.position; - var worldMatrix = this.object.matrixWorld; + var objNorm = objGeometry.attributes.normal; - var idx = 0; + var idx = 0; - for (var i = 0, l = faces.length; i < l; i++) { + // for simplicity, ignore index and drawcalls, and render every normal - var face = faces[i]; + for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { - for (var j = 0, jl = face.vertexTangents.length; j < jl; j++) { + v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); - var vertexId = face[keys[j]]; - var vertex = verts[vertexId]; + v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); - var tangent = face.vertexTangents[j]; + v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); - vertices[idx].copy(vertex).applyMatrix4(worldMatrix); + position.setXYZ( idx, v1.x, v1.y, v1.z ); - v1.copy(tangent).transformDirection(worldMatrix).multiplyScalar(this.size); + idx = idx + 1; - v1.add(vertices[idx]); - idx = idx + 1; + position.setXYZ( idx, v2.x, v2.y, v2.z ); - vertices[idx].copy(v1); - idx = idx + 1; + idx = idx + 1; - } + } - } + } - this.geometry.verticesNeedUpdate = true; + position.needsUpdate = true; - return this; + return this; - } + } -}()); +}() ); // File:src/extras/helpers/WireframeHelper.js @@ -34697,18 +36729,18 @@ THREE.VertexTangentsHelper.prototype.update = ( function (object) { * @author mrdoob / http://mrdoob.com/ */ -THREE.WireframeHelper = function (object, hex) { +THREE.WireframeHelper = function ( object, hex ) { - var color = ( hex !== undefined ) ? hex : 0xffffff; + var color = ( hex !== undefined ) ? hex : 0xffffff; - THREE.Line.call(this, new THREE.WireframeGeometry(object.geometry), new THREE.LineBasicMaterial({color: color}), THREE.LinePieces); + THREE.LineSegments.call( this, new THREE.WireframeGeometry( object.geometry ), new THREE.LineBasicMaterial( { color: color } ) ); - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; }; -THREE.WireframeHelper.prototype = Object.create(THREE.Line.prototype); +THREE.WireframeHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; // File:src/extras/objects/ImmediateRenderObject.js @@ -34717,16 +36749,16 @@ THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; * @author alteredq / http://alteredqualia.com/ */ -THREE.ImmediateRenderObject = function () { +THREE.ImmediateRenderObject = function ( material ) { - THREE.Object3D.call(this); + THREE.Object3D.call( this ); - this.render = function (renderCallback) { - }; + this.material = material; + this.render = function ( renderCallback ) {}; }; -THREE.ImmediateRenderObject.prototype = Object.create(THREE.Object3D.prototype); +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; // File:src/extras/objects/MorphBlendMesh.js @@ -34735,307 +36767,315 @@ THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; * @author alteredq / http://alteredqualia.com/ */ -THREE.MorphBlendMesh = function (geometry, material) { +THREE.MorphBlendMesh = function( geometry, material ) { - THREE.Mesh.call(this, geometry, material); + THREE.Mesh.call( this, geometry, material ); - this.animationsMap = {}; - this.animationsList = []; + this.animationsMap = {}; + this.animationsList = []; - // prepare default animation - // (all frames played together in 1 second) + // prepare default animation + // (all frames played together in 1 second) - var numFrames = this.geometry.morphTargets.length; + var numFrames = this.geometry.morphTargets.length; - var name = "__default"; + var name = "__default"; - var startFrame = 0; - var endFrame = numFrames - 1; + var startFrame = 0; + var endFrame = numFrames - 1; - var fps = numFrames / 1; + var fps = numFrames / 1; - this.createAnimation(name, startFrame, endFrame, fps); - this.setAnimationWeight(name, 1); + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); }; -THREE.MorphBlendMesh.prototype = Object.create(THREE.Mesh.prototype); +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; -THREE.MorphBlendMesh.prototype.createAnimation = function (name, start, end, fps) { +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { - var animation = { + var animation = { - startFrame: start, - endFrame: end, + start: start, + end: end, - length: end - start + 1, + length: end - start + 1, - fps: fps, - duration: ( end - start ) / fps, + fps: fps, + duration: ( end - start ) / fps, - lastFrame: 0, - currentFrame: 0, + lastFrame: 0, + currentFrame: 0, - active: false, + active: false, - time: 0, - direction: 1, - weight: 1, + time: 0, + direction: 1, + weight: 1, - directionBackwards: false, - mirroredLoop: false + directionBackwards: false, + mirroredLoop: false - }; + }; - this.animationsMap[name] = animation; - this.animationsList.push(animation); + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); }; -THREE.MorphBlendMesh.prototype.autoCreateAnimations = function (fps) { +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { - var pattern = /([a-z]+)_?(\d+)/; + var pattern = /([a-z]+)_?(\d+)/; - var firstAnimation, frameRanges = {}; + var firstAnimation, frameRanges = {}; - var geometry = this.geometry; + var geometry = this.geometry; - for (var i = 0, il = geometry.morphTargets.length; i < il; i++) { + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - var morph = geometry.morphTargets[i]; - var chunks = morph.name.match(pattern); + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); - if (chunks && chunks.length > 1) { + if ( chunks && chunks.length > 1 ) { - var name = chunks[1]; + var name = chunks[ 1 ]; - if (!frameRanges[name]) frameRanges[name] = {start: Infinity, end: -Infinity}; + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; - var range = frameRanges[name]; + var range = frameRanges[ name ]; - if (i < range.start) range.start = i; - if (i > range.end) range.end = i; + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; - if (!firstAnimation) firstAnimation = name; + if ( ! firstAnimation ) firstAnimation = name; - } + } - } + } - for (var name in frameRanges) { + for ( var name in frameRanges ) { - var range = frameRanges[name]; - this.createAnimation(name, range.start, range.end, fps); + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); - } + } - this.firstAnimation = firstAnimation; + this.firstAnimation = firstAnimation; }; -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function (name) { +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.direction = 1; - animation.directionBackwards = false; + animation.direction = 1; + animation.directionBackwards = false; - } + } }; -THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function (name) { +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.direction = -1; - animation.directionBackwards = true; + animation.direction = - 1; + animation.directionBackwards = true; - } + } }; -THREE.MorphBlendMesh.prototype.setAnimationFPS = function (name, fps) { +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.fps = fps; - animation.duration = ( animation.end - animation.start ) / animation.fps; + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; - } + } }; -THREE.MorphBlendMesh.prototype.setAnimationDuration = function (name, duration) { +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.duration = duration; - animation.fps = ( animation.end - animation.start ) / animation.duration; + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; - } + } }; -THREE.MorphBlendMesh.prototype.setAnimationWeight = function (name, weight) { +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.weight = weight; + animation.weight = weight; - } + } }; -THREE.MorphBlendMesh.prototype.setAnimationTime = function (name, time) { +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.time = time; + animation.time = time; - } + } }; -THREE.MorphBlendMesh.prototype.getAnimationTime = function (name) { +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { - var time = 0; + var time = 0; - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - time = animation.time; + time = animation.time; - } + } - return time; + return time; }; -THREE.MorphBlendMesh.prototype.getAnimationDuration = function (name) { +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { - var duration = -1; + var duration = - 1; - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - duration = animation.duration; + duration = animation.duration; - } + } - return duration; + return duration; }; -THREE.MorphBlendMesh.prototype.playAnimation = function (name) { +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.time = 0; - animation.active = true; + animation.time = 0; + animation.active = true; - } else { + } else { - THREE.warn("THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()"); + console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); - } + } }; -THREE.MorphBlendMesh.prototype.stopAnimation = function (name) { +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { - var animation = this.animationsMap[name]; + var animation = this.animationsMap[ name ]; - if (animation) { + if ( animation ) { - animation.active = false; + animation.active = false; - } + } }; -THREE.MorphBlendMesh.prototype.update = function (delta) { +THREE.MorphBlendMesh.prototype.update = function ( delta ) { - for (var i = 0, il = this.animationsList.length; i < il; i++) { + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { - var animation = this.animationsList[i]; + var animation = this.animationsList[ i ]; - if (!animation.active) continue; + if ( ! animation.active ) continue; - var frameTime = animation.duration / animation.length; + var frameTime = animation.duration / animation.length; - animation.time += animation.direction * delta; + animation.time += animation.direction * delta; - if (animation.mirroredLoop) { + if ( animation.mirroredLoop ) { - if (animation.time > animation.duration || animation.time < 0) { + if ( animation.time > animation.duration || animation.time < 0 ) { - animation.direction *= -1; + animation.direction *= - 1; - if (animation.time > animation.duration) { + if ( animation.time > animation.duration ) { - animation.time = animation.duration; - animation.directionBackwards = true; + animation.time = animation.duration; + animation.directionBackwards = true; - } + } - if (animation.time < 0) { + if ( animation.time < 0 ) { - animation.time = 0; - animation.directionBackwards = false; + animation.time = 0; + animation.directionBackwards = false; - } + } - } + } - } else { + } else { - animation.time = animation.time % animation.duration; + animation.time = animation.time % animation.duration; - if (animation.time < 0) animation.time += animation.duration; + if ( animation.time < 0 ) animation.time += animation.duration; - } + } - var keyframe = animation.startFrame + THREE.Math.clamp(Math.floor(animation.time / frameTime), 0, animation.length - 1); - var weight = animation.weight; + var keyframe = animation.start + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; - if (keyframe !== animation.currentFrame) { + if ( keyframe !== animation.currentFrame ) { - this.morphTargetInfluences[animation.lastFrame] = 0; - this.morphTargetInfluences[animation.currentFrame] = 1 * weight; + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; - this.morphTargetInfluences[keyframe] = 0; + this.morphTargetInfluences[ keyframe ] = 0; - animation.lastFrame = animation.currentFrame; - animation.currentFrame = keyframe; + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; - } + } - var mix = ( animation.time % frameTime ) / frameTime; + var mix = ( animation.time % frameTime ) / frameTime; - if (animation.directionBackwards) mix = 1 - mix; + if ( animation.directionBackwards ) mix = 1 - mix; - this.morphTargetInfluences[animation.currentFrame] = mix * weight; - this.morphTargetInfluences[animation.lastFrame] = ( 1 - mix ) * weight; + if ( animation.currentFrame !== animation.lastFrame ) { - } + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + + } else { + + this.morphTargetInfluences[ animation.currentFrame ] = weight; + + } + + } }; diff --git a/webapp/shaders/conservative_model_proj.frag b/webapp/shaders/conservative_model_proj.frag new file mode 100644 index 00000000..9cb7dc1f --- /dev/null +++ b/webapp/shaders/conservative_model_proj.frag @@ -0,0 +1,29 @@ +#extension GL_EXT_frag_depth : require +varying vec3 AABB_min; +varying vec3 AABB_max; +varying vec3 positionK; +// depth encoding : http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ +highp float factor = (exp2(24.0) - 1.0) / exp2(24.0); +vec3 EncodeFloatRGB(highp float v) { + vec3 enc = fract(vec3(1.0, 255.0, 255.0 * 255.0) * factor * v); + enc -= enc.yzz * vec3(1.0 / 255.0, 1.0 / 255.0, 0.0); + return enc; +} +highp float DecodeFloatRGB(vec3 rgb) { + return dot(rgb, vec3(1.0, 1.0 / 255.0, 1.0 / 255.0 / 255.0)) / factor; +} +void main() { + vec2 pos = positionK.xy; +//lets destroy the fragments that are really out there between the input corner and the dilated corner + if(any(bvec4(lessThan(pos, AABB_min.xy), greaterThan(pos, AABB_max.xy)))) + discard; +// ok, we were pessimistic, but one thing still holds: +// the true Z value can never ever be higher or lower than any Z value of the input vertices, +// so we clip to get back to some reality + float z = clamp(positionK.z, AABB_min.z, AABB_max.z); +// go back to fragment world + z = (0.5 * z + 0.5); +// update the depth buffer, since what was a nice triangle is now a triangle with 2 bent corners (flattened by the Z clamp). + gl_FragDepthEXT = z; + gl_FragData[0] = vec4(1.0 - z, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/webapp/shaders/conservative_model_proj.vert b/webapp/shaders/conservative_model_proj.vert new file mode 100644 index 00000000..6cd5179e --- /dev/null +++ b/webapp/shaders/conservative_model_proj.vert @@ -0,0 +1,59 @@ +attribute vec3 prevPoint; +attribute vec3 nextPoint; +uniform vec2 hPixel; +uniform vec2 hPixelWorld; +varying vec3 AABB_min; +varying vec3 AABB_max; +varying vec3 positionK; + +float cross2d(vec2 v1, vec2 v2) { + return v1.x * v2.y - v1.y * v2.x; +} + +// http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter42.html +void main() { + vec3 eyeDirection = vec3(0.0, 0.0, -1.0); + vec3 p1 = prevPoint, p2 = position, p3 = nextPoint; + vec2 e1 = normalize(p2.xy - p1.xy); + vec2 e2 = normalize(p2.xy - p3.xy); +// project the side on the bisector +// http://stackoverflow.com/a/32515402/72637 + float halfsine = sqrt((1.0 - dot(e1, e2)) / 2.0); + vec2 resultPoint2D = p2.xy + length(hPixelWorld) / halfsine * normalize(e1 + e2); + +// project the 2D point to the triangle plane in 3D +// grab the triangle normal + vec3 normal = normalize(cross(p2.xyz - p1.xyz, p3.xyz - p2.xyz)); +// grab the Z for (x=0, y=0) + float d = dot(normal, p2.xyz); +// the new Z is the distance from the 2D projected point to its projection on the triangle plane + float t = (dot(normal, vec3(resultPoint2D, 0.0)) - d) / (dot(normal, eyeDirection)); + +//I suspect the normalize() function is a bit off and sometimes give a number slightly bigger than 1, and sqrt() is unhappy + float normalZSquared = clamp(normal.z * normal.z, 0.0, 1.0); +//shift the whole triangle up because Z is sampled at pixel center, but the maximum Z is at a corner. +//A mostly vertical triangle might send the Z very high or very low, well clamp that in the fragment shader + float cornerPessimization = sqrt(1.0 - normalZSquared) * length(hPixelWorld); + vec4 shiftedPosition = vec4(resultPoint2D, t + cornerPessimization, 1.0); + vec4 projectedShiftedPosition = projectionMatrix * modelViewMatrix * shiftedPosition; + +//compute the Axis Aligned bounding box + vec4 prevPos = projectionMatrix * modelViewMatrix * vec4(p1, 1.0); + vec4 currPos = projectionMatrix * modelViewMatrix * vec4(p2, 1.0); + vec4 nextPos = projectionMatrix * modelViewMatrix * vec4(p3, 1.0); + vec3 minBounds = prevPos.xyz; + minBounds = min(currPos.xyz, minBounds); + minBounds = min(nextPos.xyz, minBounds); + vec3 maxBounds = prevPos.xyz; + maxBounds = max(currPos.xyz, maxBounds); + maxBounds = max(nextPos.xyz, maxBounds); +// extend the box by one pixel + minBounds = minBounds - vec3(hPixel, 0.0); + maxBounds = maxBounds + vec3(hPixel, 0.0); + + AABB_min = minBounds; + AABB_max = maxBounds; + gl_PointSize = 10.0; + positionK = projectedShiftedPosition.xyz; + gl_Position = projectedShiftedPosition; +} \ No newline at end of file diff --git a/webapp/shaders/model_proj.frag b/webapp/shaders/model_proj.frag new file mode 100644 index 00000000..8a8901f7 --- /dev/null +++ b/webapp/shaders/model_proj.frag @@ -0,0 +1,3 @@ +void main() { + gl_FragData[0] = vec4(1.0 - gl_FragCoord.z, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/webapp/shaders/model_proj.vert b/webapp/shaders/model_proj.vert new file mode 100644 index 00000000..efdfe723 --- /dev/null +++ b/webapp/shaders/model_proj.vert @@ -0,0 +1,5 @@ +attribute vec3 prevPoint; +attribute vec3 nextPoint; +void main() { + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/webgcode.xcodeproj/project.pbxproj b/webgcode.xcodeproj/project.pbxproj index 07622892..4508dced 100644 --- a/webgcode.xcodeproj/project.pbxproj +++ b/webgcode.xcodeproj/project.pbxproj @@ -165,6 +165,7 @@ DDAA52AFFAE054B9E7D1FA72 /* cnc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cnc.h; sourceTree = ""; }; DDAA52B1A4915275E73497A2 /* box2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = box2.js; sourceTree = ""; }; DDAA52CAC3926B8B4F4B829A /* threeDView.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = threeDView.js; path = ui/threeDView.js; sourceTree = ""; }; + DDAA52DF37746F4522541880 /* median.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = median.frag; path = shaders/median.frag; sourceTree = ""; }; DDAA52E5A7394BAD5D0799D3 /* build-sandbox.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "build-sandbox.js"; sourceTree = ""; }; DDAA52F3574050B6296E6814 /* test_pycam.ngc */ = {isa = PBXFileReference; lastKnownFileType = file.ngc; path = test_pycam.ngc; sourceTree = ""; }; DDAA531F684874FDE40B5CDE /* morphology.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = morphology.js; sourceTree = ""; }; @@ -200,6 +201,7 @@ DDAA5583FA74E90180E93A59 /* jobView.hbs */ = {isa = PBXFileReference; lastKnownFileType = file.handlebars; path = jobView.hbs; sourceTree = ""; }; DDAA558DB0228EB233245972 /* cam.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = cam.js; path = cam/cam.js; sourceTree = ""; }; DDAA55AE23998F53B255B243 /* visucamTest.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = visucamTest.html; sourceTree = ""; }; + DDAA55B32FE868406218682F /* model_proj.vert */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = model_proj.vert; path = shaders/model_proj.vert; sourceTree = ""; }; DDAA55B330007C9773B22298 /* palette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = palette.png; sourceTree = ""; }; DDAA55BC4AF31055E9F8A697 /* worker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = worker.js; path = webapp/worker.js; sourceTree = ""; }; DDAA55C1BC3E322FEB4DDDDE /* contourExtractor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = contourExtractor.js; sourceTree = ""; }; @@ -265,6 +267,7 @@ DDAA5A99ECD28BC66706A677 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = file.json; name = manifest.json; path = webapp/manifest.json; sourceTree = ""; }; DDAA5AAFC3B9C67160FA662D /* geometry.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = geometry.js; path = gcode/geometry.js; sourceTree = ""; }; DDAA5AC14AAD3A2C784B1419 /* yenc.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = yenc.js; path = libs/yenc.js; sourceTree = ""; }; + DDAA5ADCFC9042BDEE4DA768 /* conservative_model_proj.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = conservative_model_proj.frag; path = shaders/conservative_model_proj.frag; sourceTree = ""; }; DDAA5B08E58D8D0CDBC74EAA /* cam.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cam.js; sourceTree = ""; }; DDAA5B32ABEAC29E2C09425A /* tux.ngc */ = {isa = PBXFileReference; lastKnownFileType = file.ngc; path = tux.ngc; sourceTree = ""; }; DDAA5B453A7758A947C1B962 /* loading.hbs */ = {isa = PBXFileReference; lastKnownFileType = file.hbs; path = loading.hbs; sourceTree = ""; }; @@ -293,6 +296,7 @@ DDAA5DA7202D3250BD94C922 /* contour.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = contour.js; sourceTree = ""; }; DDAA5DAA497AA174431D8606 /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = index.html; path = webapp/index.html; sourceTree = ""; }; DDAA5DADF1563A99CFD20E6D /* geometry.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = geometry.js; sourceTree = ""; }; + DDAA5DBBB429009377B8802F /* conservative_model_proj.vert */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = conservative_model_proj.vert; path = shaders/conservative_model_proj.vert; sourceTree = ""; }; DDAA5DBED23BB93B2FA59786 /* util.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = util.js; sourceTree = ""; }; DDAA5DFFCA6C2A31934FF748 /* job.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = job.js; sourceTree = ""; }; DDAA5E122DE608E329B07F71 /* compile_ember.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = compile_ember.sh; sourceTree = ""; }; @@ -307,6 +311,7 @@ DDAA5F0312AAB5E2ACBE6A7A /* view.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = view.js; sourceTree = ""; }; DDAA5F0C5AECEECBCBD8D9E4 /* icon_fraise_128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_fraise_128.png; sourceTree = ""; }; DDAA5F11D1C935F6D795348A /* test_3D.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test_3D.html; sourceTree = ""; }; + DDAA5F16C318EC66400EED7E /* model_proj.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = model_proj.frag; path = shaders/model_proj.frag; sourceTree = ""; }; DDAA5F1FE345E1887B17F30E /* test_3D_stream.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test_3D_stream.html; sourceTree = ""; }; DDAA5F329B72AC25F4AAA0F4 /* toolpath.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = toolpath.js; sourceTree = ""; }; DDAA5F376DB68FEFFF7FC133 /* CAM.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = CAM.html; path = webapp/CAM.html; sourceTree = ""; }; @@ -630,6 +635,11 @@ DDAA5BFCED9419518BAD691A /* medial_axis.frag */, DDAA53CBCFE5DFFC2B401675 /* simple.frag */, DDAA55F3A85B6FDBC03F92FA /* max_value.frag */, + DDAA52DF37746F4522541880 /* median.frag */, + DDAA55B32FE868406218682F /* model_proj.vert */, + DDAA5DBBB429009377B8802F /* conservative_model_proj.vert */, + DDAA5ADCFC9042BDEE4DA768 /* conservative_model_proj.frag */, + DDAA5F16C318EC66400EED7E /* model_proj.frag */, ); path = webapp; sourceTree = "";