[
  {
    "path": "README.md",
    "content": "3D lines animation with three.js \n========================================\n...and an animated background color\n\n\nTags\n-----------\nHTML5, javascript, canvas, three.js, animation, colors.\n\n\nWhat is?\n-----------\n\nI took a prebuild three.js [example](http://threejs.org/examples/#canvas_lines) and put a fancy animated background color, adjusted some parameters like number of lines, perspective and colors. Now is ready to use for everyone.\n\nOnline demo\n-----------\n[Check out the online demo](http://joanclaret.github.io/html5-canvas-animation/)\n\n\nPreview\n-----------\n\n![html5 canvas animation preview](http://joanclaret.github.io/html5-canvas-animation/preview.png)\n\n\n\nHow it works?\n-----------\n\n### Javascript initialization\n\n```html\n<!-- Main library -->\n<script src=\"js/three.min.js\"></script>\n      \n<!-- Helpers -->\n<script src=\"js/projector.js\"></script>\n<script src=\"js/canvas-renderer.js\"></script>\n\n<!-- Visualitzation adjustments -->\n<script src=\"js/3d-lines-animation.js\"></script>\n\n<!-- Animated background color -->\n<script src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js\"></script>\n<script src=\"js/color.js\"></script>\n```\n\n### Layout\n\n```html\n<div class=\"canvas-wrap\">\n    <div class=\"canvas-content\">\n        <h1>Hello world</h1>\n    </div>\n    <div id=\"canvas\" class=\"gradient\"></div>\n</div>\n```\n\n### Options\n\n* The script is fully configurable (colors, lines, opacities, perspectives...) but you'll need to dive in to the code to adjust them. Download the files and start checking out the file 3d-lines-animation.js\n\n### Follow the repository\n★ Star and watch [this repo](https://github.com/JoanClaret/html5-canvas-animation) in order to stay updated with news about this plugin\n\n\nLicense\n-------\n\n    The MIT License (MIT)\n\n    Copyright (c) 2015 Joan Claret\n\n    Permission is hereby granted, free of charge, to any person obtaining a copy\n    of this software and associated documentation files (the \"Software\"), to deal\n    in the Software without restriction, including without limitation the rights\n    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n    copies of the Software, and to permit persons to whom the Software is\n    furnished to do so, subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be included in\n    all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n    THE SOFTWARE.\n    \nOther useful  plugins\n----------------------\n* [Maximum Characters limit warning](https://github.com/JoanClaret/max-char-limit-warning): Get a warning when the max char limit has been exceeded with a jQuery plugin\n* [jcSlider](http://joanclaret.github.io/jcSlider): A responsive slider jQuery plugin with CSS animations \n* [slide and swipe menu](http://joanclaret.github.io/slide-and-swipe-menu): A sliding swipe menu that works with touchSwipe library. \n* [jquery dynamic max height](http://joanclaret.github.io/jquery-dynamic-max-height) : Dynamic max height plugin for jQuery with CSS animation\n"
  },
  {
    "path": "index.html",
    "content": "\n<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <title>3D lines animation with three.js</title>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0\">\n        <style>\n            body {\n                background-color: #fff;\n                margin: 0px;\n                overflow: hidden;\n                font-family:arial;\n                color:#fff;\n            }\n            h1{\n                margin:0;\n            }\n\n            a {\n                color:#0078ff;\n            }\n            #canvas{\n                width:100%;\n                height:700px;\n                overflow: hidden;\n                position:absolute;\n                top:0;\n                left:0;\n                background-color: #1a1724;               \n            }\n            .canvas-wrap{\n                position:relative;\n                \n            }\n            div.canvas-content{\n                position:relative;\n                z-index:2000;\n                color:#fff;\n                text-align:center;\n                padding-top:30px;\n            }\n        </style>\n    </head>\n    <body>\n        <section class=\"canvas-wrap\">\n            <div class=\"canvas-content\">\n                <h1>3D lines animation with three.js</h1>\n            </div>\n            <div id=\"canvas\" class=\"gradient\"></div>\n            \n        </section>\n        \n        <!-- Main library -->\n        <script src=\"js/three.min.js\"></script>\n      \n        <!-- Helpers -->\n        <script src=\"js/projector.js\"></script>\n        <script src=\"js/canvas-renderer.js\"></script>\n\n        <!-- Visualitzation adjustments -->\n        <script src=\"js/3d-lines-animation.js\"></script>\n\n        <!-- Animated background color -->\n        <script src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js\"></script>\n        <script src=\"js/color.js\"></script>\n\n    </body>\n</html>\n"
  },
  {
    "path": "js/3d-lines-animation.js",
    "content": "var mouseX = 0, mouseY = 0,\n\n            windowHalfX = window.innerWidth / 2,\n            windowHalfY = window.innerHeight / 2,\n\n            SEPARATION = 200,\n            AMOUNTX = 1,\n            AMOUNTY = 1,\n\n            camera, scene, renderer;\n\n            init();\n            animate();\n\n\n\n            function init() {\n\n\n                /*\n                 *   Define variables\n                 */\n                var container, separation = 1000, amountX = 50, amountY = 50, color = 0xffffff,\n                particles, particle;\n\n                container = document.getElementById(\"canvas\");\n\n\n                camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );\n                camera.position.z = 100;\n\n                scene = new THREE.Scene();\n\n                renderer = new THREE.CanvasRenderer({ alpha: true });\n                renderer.setPixelRatio( window.devicePixelRatio );\n                renderer.setClearColor( 0x000000, 0 );   // canvas background color\n                renderer.setSize( window.innerWidth, window.innerHeight );\n                container.appendChild( renderer.domElement );\n\n               \n\n                var PI2 = Math.PI * 2;\n                var material = new THREE.SpriteCanvasMaterial( {\n\n                    color: color,\n                    opacity: 0.5,\n                    program: function ( context ) {\n\n                        context.beginPath();\n                        context.arc( 0, 0, 0.5, 0, PI2, true );\n                        context.fill();\n\n                    }\n\n                } );\n\n                var geometry = new THREE.Geometry();\n\n                /*\n                 *   Number of particles\n                 */\n                for ( var i = 0; i < 150; i ++ ) {\n\n                    particle = new THREE.Sprite( material );\n                    particle.position.x = Math.random() * 2 - 1;\n                    particle.position.y = Math.random() * 2 - 1;\n                    particle.position.z = Math.random() * 2 - 1;\n                    particle.position.normalize();\n                    particle.position.multiplyScalar( Math.random() * 10 + 600 );\n                    particle.scale.x = particle.scale.y = 5;\n\n                    scene.add( particle );\n\n                    geometry.vertices.push( particle.position );\n\n                }\n\n                /*\n                 *   Lines\n                 */\n\n                var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) );\n                scene.add( line );\n\n                document.addEventListener( 'mousemove', onDocumentMouseMove, false );\n                document.addEventListener( 'touchstart', onDocumentTouchStart, false );\n                document.addEventListener( 'touchmove', onDocumentTouchMove, false );\n\n                //\n\n                window.addEventListener( 'resize', onWindowResize, false );\n\n            }\n\n            function onWindowResize() {\n\n                windowHalfX = window.innerWidth / 2;\n                windowHalfY = window.innerHeight / 2;\n\n                camera.aspect = window.innerWidth / window.innerHeight;\n                camera.updateProjectionMatrix();\n\n                renderer.setSize( window.innerWidth, window.innerHeight );\n\n            }\n\n            //\n\n            function onDocumentMouseMove(event) {\n\n                mouseX = (event.clientX - windowHalfX) * 0.05;\n                mouseY = (event.clientY - windowHalfY) * 0.2;\n\n            }\n\n            function onDocumentTouchStart( event ) {\n\n                if ( event.touches.length > 1 ) {\n\n                    event.preventDefault();\n\n                    mouseX = (event.touches[ 0 ].pageX - windowHalfX) * 0.7;\n                    mouseY = (event.touches[ 0 ].pageY - windowHalfY) * 0.7;\n\n                }\n\n            }\n\n            function onDocumentTouchMove( event ) {\n\n                if ( event.touches.length == 1 ) {\n\n                    event.preventDefault();\n\n                    mouseX = event.touches[ 0 ].pageX - windowHalfX;\n                    mouseY = event.touches[ 0 ].pageY - windowHalfY;\n\n                }\n\n            }\n\n            //\n\n            function animate() {\n\n                requestAnimationFrame( animate );\n\n                render();\n\n            }\n\n            function render() {\n\n                camera.position.x += ( mouseX - camera.position.x ) * 0.1;\n                camera.position.y += ( - mouseY + 200 - camera.position.y ) * 0.05;\n                camera.lookAt( scene.position );\n\n                renderer.render( scene, camera );\n\n            }"
  },
  {
    "path": "js/canvas-renderer.js",
    "content": "/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nTHREE.SpriteCanvasMaterial = function ( parameters ) {\n\n\tTHREE.Material.call( this );\n\n\tthis.type = 'SpriteCanvasMaterial';\n\n\tthis.color = new THREE.Color( 0xffffff );\n\tthis.program = function ( context, color ) {};\n\n\tthis.setValues( parameters );\n\n};\n\nTHREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );\nTHREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;\n\nTHREE.SpriteCanvasMaterial.prototype.clone = function () {\n\n\tvar material = new THREE.SpriteCanvasMaterial();\n\n\tTHREE.Material.prototype.clone.call( this, material );\n\n\tmaterial.color.copy( this.color );\n\tmaterial.program = this.program;\n\n\treturn material;\n\n};\n\n//\n\nTHREE.CanvasRenderer = function ( parameters ) {\n\n\tconsole.log( 'THREE.CanvasRenderer', THREE.REVISION );\n\n\tvar smoothstep = THREE.Math.smoothstep;\n\n\tparameters = parameters || {};\n\n\tvar _this = this,\n\t_renderData, _elements, _lights,\n\t_projector = new THREE.Projector(),\n\n\t_canvas = parameters.canvas !== undefined\n\t\t\t ? parameters.canvas\n\t\t\t : document.createElement( 'canvas' ),\n\n\t_canvasWidth = _canvas.width,\n\t_canvasHeight = _canvas.height,\n\t_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),\n\t_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),\n\n\t_viewportX = 0,\n\t_viewportY = 0,\n\t_viewportWidth = _canvasWidth,\n\t_viewportHeight = _canvasHeight,\n\n\tpixelRatio = 1,\n\n\t_context = _canvas.getContext( '2d', {\n\t\talpha: parameters.alpha === true\n\t} ),\n\n\t_clearColor = new THREE.Color( 0x000000 ),\n\t_clearAlpha = parameters.alpha === true ? 0 : 1,\n\n\t_contextGlobalAlpha = 1,\n\t_contextGlobalCompositeOperation = 0,\n\t_contextStrokeStyle = null,\n\t_contextFillStyle = null,\n\t_contextLineWidth = null,\n\t_contextLineCap = null,\n\t_contextLineJoin = null,\n\t_contextLineDash = [],\n\n\t_camera,\n\n\t_v1, _v2, _v3, _v4,\n\t_v5 = new THREE.RenderableVertex(),\n\t_v6 = new THREE.RenderableVertex(),\n\n\t_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,\n\t_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,\n\n\t_color = new THREE.Color(),\n\t_color1 = new THREE.Color(),\n\t_color2 = new THREE.Color(),\n\t_color3 = new THREE.Color(),\n\t_color4 = new THREE.Color(),\n\n\t_diffuseColor = new THREE.Color(),\n\t_emissiveColor = new THREE.Color(),\n\n\t_lightColor = new THREE.Color(),\n\n\t_patterns = {},\n\n\t_image, _uvs,\n\t_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,\n\n\t_clipBox = new THREE.Box2(),\n\t_clearBox = new THREE.Box2(),\n\t_elemBox = new THREE.Box2(),\n\n\t_ambientLight = new THREE.Color(),\n\t_directionalLights = new THREE.Color(),\n\t_pointLights = new THREE.Color(),\n\n\t_vector3 = new THREE.Vector3(), // Needed for PointLight\n\t_centroid = new THREE.Vector3(),\n\t_normal = new THREE.Vector3(),\n\t_normalViewMatrix = new THREE.Matrix3();\n\n\t// dash+gap fallbacks for Firefox and everything else\n\n\tif ( _context.setLineDash === undefined ) {\n\n\t\t_context.setLineDash = function () {}\n\n\t}\n\n\tthis.domElement = _canvas;\n\n\tthis.autoClear = true;\n\tthis.sortObjects = true;\n\tthis.sortElements = true;\n\n\tthis.info = {\n\n\t\trender: {\n\n\t\t\tvertices: 0,\n\t\t\tfaces: 0\n\n\t\t}\n\n\t}\n\n\t// WebGLRenderer compatibility\n\n\tthis.supportsVertexTextures = function () {};\n\tthis.setFaceCulling = function () {};\n\n\t//\n\n\tthis.getPixelRatio = function () {\n\n\t\treturn pixelRatio;\n\n\t};\n\n\tthis.setPixelRatio = function ( value ) {\n\n\t\tpixelRatio = value;\n\n\t};\n\n\tthis.setSize = function ( width, height, updateStyle ) {\n\n\t\t_canvasWidth = width * pixelRatio;\n\t\t_canvasHeight = height * pixelRatio;\n\n\t\t_canvas.width = _canvasWidth;\n\t\t_canvas.height = _canvasHeight;\n\n\t\t_canvasWidthHalf = Math.floor( _canvasWidth / 2 );\n\t\t_canvasHeightHalf = Math.floor( _canvasHeight / 2 );\n\n\t\tif ( updateStyle !== false ) {\n\n\t\t\t_canvas.style.width = width + 'px';\n\t\t\t_canvas.style.height = height + 'px';\n\n\t\t}\n\n\t\t_clipBox.min.set( -_canvasWidthHalf, -_canvasHeightHalf ),\n\t\t_clipBox.max.set(   _canvasWidthHalf,   _canvasHeightHalf );\n\n\t\t_clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );\n\t\t_clearBox.max.set(   _canvasWidthHalf,   _canvasHeightHalf );\n\n\t\t_contextGlobalAlpha = 1;\n\t\t_contextGlobalCompositeOperation = 0;\n\t\t_contextStrokeStyle = null;\n\t\t_contextFillStyle = null;\n\t\t_contextLineWidth = null;\n\t\t_contextLineCap = null;\n\t\t_contextLineJoin = null;\n\n\t\tthis.setViewport( 0, 0, width, height );\n\n\t};\n\n\tthis.setViewport = function ( x, y, width, height ) {\n\n\t\t_viewportX = x * pixelRatio;\n\t\t_viewportY = y * pixelRatio;\n\n\t\t_viewportWidth = width * pixelRatio;\n\t\t_viewportHeight = height * pixelRatio;\n\n\t};\n\n\tthis.setScissor = function () {};\n\tthis.enableScissorTest = function () {};\n\n\tthis.setClearColor = function ( color, alpha ) {\n\n\t\t_clearColor.set( color );\n\t\t_clearAlpha = alpha !== undefined ? alpha : 1;\n\n\t\t_clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );\n\t\t_clearBox.max.set(   _canvasWidthHalf,   _canvasHeightHalf );\n\n\t};\n\n\tthis.setClearColorHex = function ( hex, alpha ) {\n\n\t\tconsole.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' );\n\t\tthis.setClearColor( hex, alpha );\n\n\t};\n\n\tthis.getClearColor = function () {\n\n\t\treturn _clearColor;\n\n\t};\n\n\tthis.getClearAlpha = function () {\n\n\t\treturn _clearAlpha;\n\n\t};\n\n\tthis.getMaxAnisotropy = function () {\n\n\t\treturn 0;\n\n\t};\n\n\tthis.clear = function () {\n\n\t\tif ( _clearBox.empty() === false ) {\n\n\t\t\t_clearBox.intersect( _clipBox );\n\t\t\t_clearBox.expandByScalar( 2 );\n\n\t\t\t_clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;\n\t\t\t_clearBox.min.y =  - _clearBox.min.y + _canvasHeightHalf;\t\t// higher y value !\n\t\t\t_clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;\n\t\t\t_clearBox.max.y =  - _clearBox.max.y + _canvasHeightHalf;\t\t// lower y value !\n\n\t\t\tif ( _clearAlpha < 1 ) {\n\n\t\t\t\t_context.clearRect(\n\t\t\t\t\t_clearBox.min.x | 0,\n\t\t\t\t\t_clearBox.max.y | 0,\n\t\t\t\t\t( _clearBox.max.x - _clearBox.min.x ) | 0,\n\t\t\t\t\t( _clearBox.min.y - _clearBox.max.y ) | 0\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\tif ( _clearAlpha > 0 ) {\n\n\t\t\t\tsetBlending( THREE.NormalBlending );\n\t\t\t\tsetOpacity( 1 );\n\n\t\t\t\tsetFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );\n\n\t\t\t\t_context.fillRect(\n\t\t\t\t\t_clearBox.min.x | 0,\n\t\t\t\t\t_clearBox.max.y | 0,\n\t\t\t\t\t( _clearBox.max.x - _clearBox.min.x ) | 0,\n\t\t\t\t\t( _clearBox.min.y - _clearBox.max.y ) | 0\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\t_clearBox.makeEmpty();\n\n\t\t}\n\n\t};\n\n\t// compatibility\n\n\tthis.clearColor = function () {};\n\tthis.clearDepth = function () {};\n\tthis.clearStencil = function () {};\n\n\tthis.render = function ( scene, camera ) {\n\n\t\tif ( camera instanceof THREE.Camera === false ) {\n\n\t\t\tconsole.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.autoClear === true ) this.clear();\n\n\t\t_this.info.render.vertices = 0;\n\t\t_this.info.render.faces = 0;\n\n\t\t_context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY );\n\t\t_context.translate( _canvasWidthHalf, _canvasHeightHalf );\n\n\t\t_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );\n\t\t_elements = _renderData.elements;\n\t\t_lights = _renderData.lights;\n\t\t_camera = camera;\n\n\t\t_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );\n\n\t\t/* DEBUG\n\t\tsetFillStyle( 'rgba( 0, 255, 255, 0.5 )' );\n\t\t_context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y );\n\t\t*/\n\n\t\tcalculateLights();\n\n\t\tfor ( var e = 0, el = _elements.length; e < el; e ++ ) {\n\n\t\t\tvar element = _elements[ e ];\n\n\t\t\tvar material = element.material;\n\n\t\t\tif ( material === undefined || material.opacity === 0 ) continue;\n\n\t\t\t_elemBox.makeEmpty();\n\n\t\t\tif ( element instanceof THREE.RenderableSprite ) {\n\n\t\t\t\t_v1 = element;\n\t\t\t\t_v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;\n\n\t\t\t\trenderSprite( _v1, element, material );\n\n\t\t\t} else if ( element instanceof THREE.RenderableLine ) {\n\n\t\t\t\t_v1 = element.v1; _v2 = element.v2;\n\n\t\t\t\t_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;\n\t\t\t\t_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;\n\n\t\t\t\t_elemBox.setFromPoints( [\n\t\t\t\t\t_v1.positionScreen,\n\t\t\t\t\t_v2.positionScreen\n\t\t\t\t] );\n\n\t\t\t\tif ( _clipBox.isIntersectionBox( _elemBox ) === true ) {\n\n\t\t\t\t\trenderLine( _v1, _v2, element, material );\n\n\t\t\t\t}\n\n\t\t\t} else if ( element instanceof THREE.RenderableFace ) {\n\n\t\t\t\t_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;\n\n\t\t\t\tif ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;\n\t\t\t\tif ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;\n\t\t\t\tif ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;\n\n\t\t\t\t_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;\n\t\t\t\t_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;\n\t\t\t\t_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;\n\n\t\t\t\tif ( material.overdraw > 0 ) {\n\n\t\t\t\t\texpand( _v1.positionScreen, _v2.positionScreen, material.overdraw );\n\t\t\t\t\texpand( _v2.positionScreen, _v3.positionScreen, material.overdraw );\n\t\t\t\t\texpand( _v3.positionScreen, _v1.positionScreen, material.overdraw );\n\n\t\t\t\t}\n\n\t\t\t\t_elemBox.setFromPoints( [\n\t\t\t\t\t_v1.positionScreen,\n\t\t\t\t\t_v2.positionScreen,\n\t\t\t\t\t_v3.positionScreen\n\t\t\t\t] );\n\n\t\t\t\tif ( _clipBox.isIntersectionBox( _elemBox ) === true ) {\n\n\t\t\t\t\trenderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/* DEBUG\n\t\t\tsetLineWidth( 1 );\n\t\t\tsetStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' );\n\t\t\t_context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y );\n\t\t\t*/\n\n\t\t\t_clearBox.union( _elemBox );\n\n\t\t}\n\n\t\t/* DEBUG\n\t\tsetLineWidth( 1 );\n\t\tsetStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' );\n\t\t_context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y );\n\t\t*/\n\n\t\t_context.setTransform( 1, 0, 0, 1, 0, 0 );\n\n\t};\n\n\t//\n\n\tfunction calculateLights() {\n\n\t\t_ambientLight.setRGB( 0, 0, 0 );\n\t\t_directionalLights.setRGB( 0, 0, 0 );\n\t\t_pointLights.setRGB( 0, 0, 0 );\n\n\t\tfor ( var l = 0, ll = _lights.length; l < ll; l ++ ) {\n\n\t\t\tvar light = _lights[ l ];\n\t\t\tvar lightColor = light.color;\n\n\t\t\tif ( light instanceof THREE.AmbientLight ) {\n\n\t\t\t\t_ambientLight.add( lightColor );\n\n\t\t\t} else if ( light instanceof THREE.DirectionalLight ) {\n\n\t\t\t\t// for sprites\n\n\t\t\t\t_directionalLights.add( lightColor );\n\n\t\t\t} else if ( light instanceof THREE.PointLight ) {\n\n\t\t\t\t// for sprites\n\n\t\t\t\t_pointLights.add( lightColor );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction calculateLight( position, normal, color ) {\n\n\t\tfor ( var l = 0, ll = _lights.length; l < ll; l ++ ) {\n\n\t\t\tvar light = _lights[ l ];\n\n\t\t\t_lightColor.copy( light.color );\n\n\t\t\tif ( light instanceof THREE.DirectionalLight ) {\n\n\t\t\t\tvar lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();\n\n\t\t\t\tvar amount = normal.dot( lightPosition );\n\n\t\t\t\tif ( amount <= 0 ) continue;\n\n\t\t\t\tamount *= light.intensity;\n\n\t\t\t\tcolor.add( _lightColor.multiplyScalar( amount ) );\n\n\t\t\t} else if ( light instanceof THREE.PointLight ) {\n\n\t\t\t\tvar lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );\n\n\t\t\t\tvar amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );\n\n\t\t\t\tif ( amount <= 0 ) continue;\n\n\t\t\t\tamount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );\n\n\t\t\t\tif ( amount == 0 ) continue;\n\n\t\t\t\tamount *= light.intensity;\n\n\t\t\t\tcolor.add( _lightColor.multiplyScalar( amount ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction renderSprite( v1, element, material ) {\n\n\t\tsetOpacity( material.opacity );\n\t\tsetBlending( material.blending );\n\n\t\tvar scaleX = element.scale.x * _canvasWidthHalf;\n\t\tvar scaleY = element.scale.y * _canvasHeightHalf;\n\n\t\tvar dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite\n\t\t_elemBox.min.set( v1.x - dist, v1.y - dist );\n\t\t_elemBox.max.set( v1.x + dist, v1.y + dist );\n\n\t\tif ( material instanceof THREE.SpriteMaterial ) {\n\n\t\t\tvar texture = material.map;\n\n\t\t\tif ( texture !== null && texture.image !== undefined ) {\n\n\t\t\t\tif ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {\n\n\t\t\t\t\tif ( texture.image.width > 0 ) {\n\n\t\t\t\t\t\ttextureToPattern( texture );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.addEventListener( 'update', onTextureUpdate );\n\n\t\t\t\t}\n\n\t\t\t\tvar pattern = _patterns[ texture.id ];\n\n\t\t\t\tif ( pattern !== undefined ) {\n\n\t\t\t\t\tsetFillStyle( pattern );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsetFillStyle( 'rgba( 0, 0, 0, 1 )' );\n\n\t\t\t\t}\n\n\t\t\t\t//\n\n\t\t\t\tvar bitmap = texture.image;\n\n\t\t\t\tvar ox = bitmap.width * texture.offset.x;\n\t\t\t\tvar oy = bitmap.height * texture.offset.y;\n\n\t\t\t\tvar sx = bitmap.width * texture.repeat.x;\n\t\t\t\tvar sy = bitmap.height * texture.repeat.y;\n\n\t\t\t\tvar cx = scaleX / sx;\n\t\t\t\tvar cy = scaleY / sy;\n\n\t\t\t\t_context.save();\n\t\t\t\t_context.translate( v1.x, v1.y );\n\t\t\t\tif ( material.rotation !== 0 ) _context.rotate( material.rotation );\n\t\t\t\t_context.translate( - scaleX / 2, - scaleY / 2 );\n\t\t\t\t_context.scale( cx, cy );\n\t\t\t\t_context.translate( - ox, - oy );\n\t\t\t\t_context.fillRect( ox, oy, sx, sy );\n\t\t\t\t_context.restore();\n\n\t\t\t} else {\n\n\t\t\t\t// no texture\n\n\t\t\t\tsetFillStyle( material.color.getStyle() );\n\n\t\t\t\t_context.save();\n\t\t\t\t_context.translate( v1.x, v1.y );\n\t\t\t\tif ( material.rotation !== 0 ) _context.rotate( material.rotation );\n\t\t\t\t_context.scale( scaleX, - scaleY );\n\t\t\t\t_context.fillRect( - 0.5, - 0.5, 1, 1 );\n\t\t\t\t_context.restore();\n\n\t\t\t}\n\n\t\t} else if ( material instanceof THREE.SpriteCanvasMaterial ) {\n\n\t\t\tsetStrokeStyle( material.color.getStyle() );\n\t\t\tsetFillStyle( material.color.getStyle() );\n\n\t\t\t_context.save();\n\t\t\t_context.translate( v1.x, v1.y );\n\t\t\tif ( material.rotation !== 0 ) _context.rotate( material.rotation );\n\t\t\t_context.scale( scaleX, scaleY );\n\n\t\t\tmaterial.program( _context );\n\n\t\t\t_context.restore();\n\n\t\t}\n\n\t\t/* DEBUG\n\t\tsetStrokeStyle( 'rgb(255,255,0)' );\n\t\t_context.beginPath();\n\t\t_context.moveTo( v1.x - 10, v1.y );\n\t\t_context.lineTo( v1.x + 10, v1.y );\n\t\t_context.moveTo( v1.x, v1.y - 10 );\n\t\t_context.lineTo( v1.x, v1.y + 10 );\n\t\t_context.stroke();\n\t\t*/\n\n\t}\n\n\tfunction renderLine( v1, v2, element, material ) {\n\n\t\tsetOpacity( material.opacity );\n\t\tsetBlending( material.blending );\n\n\t\t_context.beginPath();\n\t\t_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );\n\t\t_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );\n\n\t\tif ( material instanceof THREE.LineBasicMaterial ) {\n\n\t\t\tsetLineWidth( material.linewidth );\n\t\t\tsetLineCap( material.linecap );\n\t\t\tsetLineJoin( material.linejoin );\n\n\t\t\tif ( material.vertexColors !== THREE.VertexColors ) {\n\n\t\t\t\tsetStrokeStyle( material.color.getStyle() );\n\n\t\t\t} else {\n\n\t\t\t\tvar colorStyle1 = element.vertexColors[ 0 ].getStyle();\n\t\t\t\tvar colorStyle2 = element.vertexColors[ 1 ].getStyle();\n\n\t\t\t\tif ( colorStyle1 === colorStyle2 ) {\n\n\t\t\t\t\tsetStrokeStyle( colorStyle1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttry {\n\n\t\t\t\t\t\tvar grad = _context.createLinearGradient(\n\t\t\t\t\t\t\tv1.positionScreen.x,\n\t\t\t\t\t\t\tv1.positionScreen.y,\n\t\t\t\t\t\t\tv2.positionScreen.x,\n\t\t\t\t\t\t\tv2.positionScreen.y\n\t\t\t\t\t\t);\n\t\t\t\t\t\tgrad.addColorStop( 0, colorStyle1 );\n\t\t\t\t\t\tgrad.addColorStop( 1, colorStyle2 );\n\n\t\t\t\t\t} catch ( exception ) {\n\n\t\t\t\t\t\tgrad = colorStyle1;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tsetStrokeStyle( grad );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_context.stroke();\n\t\t\t_elemBox.expandByScalar( material.linewidth * 2 );\n\n\t\t} else if ( material instanceof THREE.LineDashedMaterial ) {\n\n\t\t\tsetLineWidth( material.linewidth );\n\t\t\tsetLineCap( material.linecap );\n\t\t\tsetLineJoin( material.linejoin );\n\t\t\tsetStrokeStyle( material.color.getStyle() );\n\t\t\tsetLineDash( [ material.dashSize, material.gapSize ] );\n\n\t\t\t_context.stroke();\n\n\t\t\t_elemBox.expandByScalar( material.linewidth * 2 );\n\n\t\t\tsetLineDash( [] );\n\n\t\t}\n\n\t}\n\n\tfunction renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {\n\n\t\t_this.info.render.vertices += 3;\n\t\t_this.info.render.faces ++;\n\n\t\tsetOpacity( material.opacity );\n\t\tsetBlending( material.blending );\n\n\t\t_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;\n\t\t_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;\n\t\t_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;\n\n\t\tdrawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );\n\n\t\tif ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {\n\n\t\t\t_diffuseColor.copy( material.color );\n\t\t\t_emissiveColor.copy( material.emissive );\n\n\t\t\tif ( material.vertexColors === THREE.FaceColors ) {\n\n\t\t\t\t_diffuseColor.multiply( element.color );\n\n\t\t\t}\n\n\t\t\t_color.copy( _ambientLight );\n\n\t\t\t_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );\n\n\t\t\tcalculateLight( _centroid, element.normalModel, _color );\n\n\t\t\t_color.multiply( _diffuseColor ).add( _emissiveColor );\n\n\t\t\tmaterial.wireframe === true\n\t\t\t\t ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )\n\t\t\t\t : fillPath( _color );\n\n\t\t} else if ( material instanceof THREE.MeshBasicMaterial ||\n\t\t\t\t    material instanceof THREE.MeshLambertMaterial ||\n\t\t\t\t    material instanceof THREE.MeshPhongMaterial ) {\n\n\t\t\tif ( material.map !== null ) {\n\n\t\t\t\tvar mapping = material.map.mapping;\n\n\t\t\t\tif ( mapping === THREE.UVMapping ) {\n\n\t\t\t\t\t_uvs = element.uvs;\n\t\t\t\t\tpatternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map );\n\n\t\t\t\t}\n\n\t\t\t} else if ( material.envMap !== null ) {\n\n\t\t\t\tif ( material.envMap.mapping === THREE.SphericalReflectionMapping ) {\n\n\t\t\t\t\t_normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );\n\t\t\t\t\t_uv1x = 0.5 * _normal.x + 0.5;\n\t\t\t\t\t_uv1y = 0.5 * _normal.y + 0.5;\n\n\t\t\t\t\t_normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );\n\t\t\t\t\t_uv2x = 0.5 * _normal.x + 0.5;\n\t\t\t\t\t_uv2y = 0.5 * _normal.y + 0.5;\n\n\t\t\t\t\t_normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );\n\t\t\t\t\t_uv3x = 0.5 * _normal.x + 0.5;\n\t\t\t\t\t_uv3y = 0.5 * _normal.y + 0.5;\n\n\t\t\t\t\tpatternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t_color.copy( material.color );\n\n\t\t\t\tif ( material.vertexColors === THREE.FaceColors ) {\n\n\t\t\t\t\t_color.multiply( element.color );\n\n\t\t\t\t}\n\n\t\t\t\tmaterial.wireframe === true\n\t\t\t\t\t ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )\n\t\t\t\t\t : fillPath( _color );\n\n\t\t\t}\n\n\t\t} else if ( material instanceof THREE.MeshDepthMaterial ) {\n\n\t\t\t_color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far );\n\n\t\t\tmaterial.wireframe === true\n\t\t\t\t\t ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )\n\t\t\t\t\t : fillPath( _color );\n\n\t\t} else if ( material instanceof THREE.MeshNormalMaterial ) {\n\n\t\t\t_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );\n\n\t\t\t_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );\n\n\t\t\tmaterial.wireframe === true\n\t\t\t\t ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )\n\t\t\t\t : fillPath( _color );\n\n\t\t} else {\n\n\t\t\t_color.setRGB( 1, 1, 1 );\n\n\t\t\tmaterial.wireframe === true\n\t\t\t\t ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )\n\t\t\t\t : fillPath( _color );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction drawTriangle( x0, y0, x1, y1, x2, y2 ) {\n\n\t\t_context.beginPath();\n\t\t_context.moveTo( x0, y0 );\n\t\t_context.lineTo( x1, y1 );\n\t\t_context.lineTo( x2, y2 );\n\t\t_context.closePath();\n\n\t}\n\n\tfunction strokePath( color, linewidth, linecap, linejoin ) {\n\n\t\tsetLineWidth( linewidth );\n\t\tsetLineCap( linecap );\n\t\tsetLineJoin( linejoin );\n\t\tsetStrokeStyle( color.getStyle() );\n\n\t\t_context.stroke();\n\n\t\t_elemBox.expandByScalar( linewidth * 2 );\n\n\t}\n\n\tfunction fillPath( color ) {\n\n\t\tsetFillStyle( color.getStyle() );\n\t\t_context.fill();\n\n\t}\n\n\tfunction onTextureUpdate ( event ) {\n\n\t\ttextureToPattern( event.target );\n\n\t}\n\n\tfunction textureToPattern( texture ) {\n\n\t\tif ( texture instanceof THREE.CompressedTexture ) return;\n\n\t\tvar repeatX = texture.wrapS === THREE.RepeatWrapping;\n\t\tvar repeatY = texture.wrapT === THREE.RepeatWrapping;\n\n\t\tvar image = texture.image;\n\n\t\tvar canvas = document.createElement( 'canvas' );\n\t\tcanvas.width = image.width;\n\t\tcanvas.height = image.height;\n\n\t\tvar context = canvas.getContext( '2d' );\n\t\tcontext.setTransform( 1, 0, 0, - 1, 0, image.height );\n\t\tcontext.drawImage( image, 0, 0 );\n\n\t\t_patterns[ texture.id ] = _context.createPattern(\n\t\t\tcanvas, repeatX === true && repeatY === true\n\t\t\t\t ? 'repeat'\n\t\t\t\t : repeatX === true && repeatY === false\n\t\t\t\t\t ? 'repeat-x'\n\t\t\t\t\t : repeatX === false && repeatY === true\n\t\t\t\t\t\t ? 'repeat-y'\n\t\t\t\t\t\t : 'no-repeat'\n\t\t);\n\n\t}\n\n\tfunction patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {\n\n\t\tif ( texture instanceof THREE.DataTexture ) return;\n\n\t\tif ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {\n\n\t\t\tif ( texture.image !== undefined && texture.image.width > 0 ) {\n\n\t\t\t\ttextureToPattern( texture );\n\n\t\t\t}\n\n\t\t\ttexture.addEventListener( 'update', onTextureUpdate );\n\n\t\t}\n\n\t\tvar pattern = _patterns[ texture.id ];\n\n\t\tif ( pattern !== undefined ) {\n\n\t\t\tsetFillStyle( pattern );\n\n\t\t} else {\n\n\t\t\tsetFillStyle( 'rgba(0,0,0,1)' );\n\t\t\t_context.fill();\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120\n\n\t\tvar a, b, c, d, e, f, det, idet,\n\t\toffsetX = texture.offset.x / texture.repeat.x,\n\t\toffsetY = texture.offset.y / texture.repeat.y,\n\t\twidth = texture.image.width * texture.repeat.x,\n\t\theight = texture.image.height * texture.repeat.y;\n\n\t\tu0 = ( u0 + offsetX ) * width;\n\t\tv0 = ( v0 + offsetY ) * height;\n\n\t\tu1 = ( u1 + offsetX ) * width;\n\t\tv1 = ( v1 + offsetY ) * height;\n\n\t\tu2 = ( u2 + offsetX ) * width;\n\t\tv2 = ( v2 + offsetY ) * height;\n\n\t\tx1 -= x0; y1 -= y0;\n\t\tx2 -= x0; y2 -= y0;\n\n\t\tu1 -= u0; v1 -= v0;\n\t\tu2 -= u0; v2 -= v0;\n\n\t\tdet = u1 * v2 - u2 * v1;\n\n\t\tif ( det === 0 ) return;\n\n\t\tidet = 1 / det;\n\n\t\ta = ( v2 * x1 - v1 * x2 ) * idet;\n\t\tb = ( v2 * y1 - v1 * y2 ) * idet;\n\t\tc = ( u1 * x2 - u2 * x1 ) * idet;\n\t\td = ( u1 * y2 - u2 * y1 ) * idet;\n\n\t\te = x0 - a * u0 - c * v0;\n\t\tf = y0 - b * u0 - d * v0;\n\n\t\t_context.save();\n\t\t_context.transform( a, b, c, d, e, f );\n\t\t_context.fill();\n\t\t_context.restore();\n\n\t}\n\n\tfunction clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {\n\n\t\t// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120\n\n\t\tvar a, b, c, d, e, f, det, idet,\n\t\twidth = image.width - 1,\n\t\theight = image.height - 1;\n\n\t\tu0 *= width; v0 *= height;\n\t\tu1 *= width; v1 *= height;\n\t\tu2 *= width; v2 *= height;\n\n\t\tx1 -= x0; y1 -= y0;\n\t\tx2 -= x0; y2 -= y0;\n\n\t\tu1 -= u0; v1 -= v0;\n\t\tu2 -= u0; v2 -= v0;\n\n\t\tdet = u1 * v2 - u2 * v1;\n\n\t\tidet = 1 / det;\n\n\t\ta = ( v2 * x1 - v1 * x2 ) * idet;\n\t\tb = ( v2 * y1 - v1 * y2 ) * idet;\n\t\tc = ( u1 * x2 - u2 * x1 ) * idet;\n\t\td = ( u1 * y2 - u2 * y1 ) * idet;\n\n\t\te = x0 - a * u0 - c * v0;\n\t\tf = y0 - b * u0 - d * v0;\n\n\t\t_context.save();\n\t\t_context.transform( a, b, c, d, e, f );\n\t\t_context.clip();\n\t\t_context.drawImage( image, 0, 0 );\n\t\t_context.restore();\n\n\t}\n\n\t// Hide anti-alias gaps\n\n\tfunction expand( v1, v2, pixels ) {\n\n\t\tvar x = v2.x - v1.x, y = v2.y - v1.y,\n\t\tdet = x * x + y * y, idet;\n\n\t\tif ( det === 0 ) return;\n\n\t\tidet = pixels / Math.sqrt( det );\n\n\t\tx *= idet; y *= idet;\n\n\t\tv2.x += x; v2.y += y;\n\t\tv1.x -= x; v1.y -= y;\n\n\t}\n\n\t// Context cached methods.\n\n\tfunction setOpacity( value ) {\n\n\t\tif ( _contextGlobalAlpha !== value ) {\n\n\t\t\t_context.globalAlpha = value;\n\t\t\t_contextGlobalAlpha = value;\n\n\t\t}\n\n\t}\n\n\tfunction setBlending( value ) {\n\n\t\tif ( _contextGlobalCompositeOperation !== value ) {\n\n\t\t\tif ( value === THREE.NormalBlending ) {\n\n\t\t\t\t_context.globalCompositeOperation = 'source-over';\n\n\t\t\t} else if ( value === THREE.AdditiveBlending ) {\n\n\t\t\t\t_context.globalCompositeOperation = 'lighter';\n\n\t\t\t} else if ( value === THREE.SubtractiveBlending ) {\n\n\t\t\t\t_context.globalCompositeOperation = 'darker';\n\n\t\t\t}\n\n\t\t\t_contextGlobalCompositeOperation = value;\n\n\t\t}\n\n\t}\n\n\tfunction setLineWidth( value ) {\n\n\t\tif ( _contextLineWidth !== value ) {\n\n\t\t\t_context.lineWidth = value;\n\t\t\t_contextLineWidth = value;\n\n\t\t}\n\n\t}\n\n\tfunction setLineCap( value ) {\n\n\t\t// \"butt\", \"round\", \"square\"\n\n\t\tif ( _contextLineCap !== value ) {\n\n\t\t\t_context.lineCap = value;\n\t\t\t_contextLineCap = value;\n\n\t\t}\n\n\t}\n\n\tfunction setLineJoin( value ) {\n\n\t\t// \"round\", \"bevel\", \"miter\"\n\n\t\tif ( _contextLineJoin !== value ) {\n\n\t\t\t_context.lineJoin = value;\n\t\t\t_contextLineJoin = value;\n\n\t\t}\n\n\t}\n\n\tfunction setStrokeStyle( value ) {\n\n\t\tif ( _contextStrokeStyle !== value ) {\n\n\t\t\t_context.strokeStyle = value;\n\t\t\t_contextStrokeStyle = value;\n\n\t\t}\n\n\t}\n\n\tfunction setFillStyle( value ) {\n\n\t\tif ( _contextFillStyle !== value ) {\n\n\t\t\t_context.fillStyle = value;\n\t\t\t_contextFillStyle = value;\n\n\t\t}\n\n\t}\n\n\tfunction setLineDash( value ) {\n\n\t\tif ( _contextLineDash.length !== value.length ) {\n\n\t\t\t_context.setLineDash( value );\n\t\t\t_contextLineDash = value;\n\n\t\t}\n\n\t}\n\n};\n"
  },
  {
    "path": "js/color.js",
    "content": "\nvar colors = new Array(\n[62,35,255],\n  [60,255,60],\n  [255,35,98],\n  [45,175,230],\n  [255,0,255],\n  [255,128,0]);\n\n\n//  \n\nvar step = 0;\n//color table indices for: \n// current color left\n// next color left\n// current color right\n// next color right\nvar colorIndices = [0,1,2,3];\n\n//transition speed\nvar gradientSpeed = 0.002;\n\nfunction updateGradient()\n{\n  \n  if ( $===undefined ) return;\n  \nvar c0_0 = colors[colorIndices[0]];\nvar c0_1 = colors[colorIndices[1]];\nvar c1_0 = colors[colorIndices[2]];\nvar c1_1 = colors[colorIndices[3]];\n\nvar istep = 1 - step;\nvar r1 = Math.round(istep * c0_0[0] + step * c0_1[0]);\nvar g1 = Math.round(istep * c0_0[1] + step * c0_1[1]);\nvar b1 = Math.round(istep * c0_0[2] + step * c0_1[2]);\nvar color1 = \"rgb(\"+r1+\",\"+g1+\",\"+b1+\")\";\n\nvar r2 = Math.round(istep * c1_0[0] + step * c1_1[0]);\nvar g2 = Math.round(istep * c1_0[1] + step * c1_1[1]);\nvar b2 = Math.round(istep * c1_0[2] + step * c1_1[2]);\nvar color2 = \"rgb(\"+r2+\",\"+g2+\",\"+b2+\")\";\n\n $('.gradient').css({\n   background: \"-webkit-gradient(linear, left top, right top, from(\"+color1+\"), to(\"+color2+\"))\"}).css({\n    background: \"-moz-linear-gradient(left, \"+color1+\" 0%, \"+color2+\" 100%)\"});\n  \n  step += gradientSpeed;\n  if ( step >= 1 )\n  {\n    step %= 1;\n    colorIndices[0] = colorIndices[1];\n    colorIndices[2] = colorIndices[3];\n    \n    //pick two new target color indices\n    //do not pick the same as the current one\n    colorIndices[1] = ( colorIndices[1] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;\n    colorIndices[3] = ( colorIndices[3] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;\n    \n  }\n}\n\nsetInterval(updateGradient,10);"
  },
  {
    "path": "js/projector.js",
    "content": "/**\n * @author mrdoob / http://mrdoob.com/\n * @author supereggbert / http://www.paulbrunt.co.uk/\n * @author julianwa / https://github.com/julianwa\n */\n\nTHREE.RenderableObject = function () {\n\n\tthis.id = 0;\n\n\tthis.object = null;\n\tthis.z = 0;\n\n};\n\n//\n\nTHREE.RenderableFace = function () {\n\n\tthis.id = 0;\n\n\tthis.v1 = new THREE.RenderableVertex();\n\tthis.v2 = new THREE.RenderableVertex();\n\tthis.v3 = new THREE.RenderableVertex();\n\n\tthis.normalModel = new THREE.Vector3();\n\n\tthis.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];\n\tthis.vertexNormalsLength = 0;\n\n\tthis.color = new THREE.Color();\n\tthis.material = null;\n\tthis.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];\n\n\tthis.z = 0;\n\n};\n\n//\n\nTHREE.RenderableVertex = function () {\n\n\tthis.position = new THREE.Vector3();\n\tthis.positionWorld = new THREE.Vector3();\n\tthis.positionScreen = new THREE.Vector4();\n\n\tthis.visible = true;\n\n};\n\nTHREE.RenderableVertex.prototype.copy = function ( vertex ) {\n\n\tthis.positionWorld.copy( vertex.positionWorld );\n\tthis.positionScreen.copy( vertex.positionScreen );\n\n};\n\n//\n\nTHREE.RenderableLine = function () {\n\n\tthis.id = 0;\n\n\tthis.v1 = new THREE.RenderableVertex();\n\tthis.v2 = new THREE.RenderableVertex();\n\n\tthis.vertexColors = [ new THREE.Color(), new THREE.Color() ];\n\tthis.material = null;\n\n\tthis.z = 0;\n\n};\n\n//\n\nTHREE.RenderableSprite = function () {\n\n\tthis.id = 0;\n\n\tthis.object = null;\n\n\tthis.x = 0;\n\tthis.y = 0;\n\tthis.z = 0;\n\n\tthis.rotation = 0;\n\tthis.scale = new THREE.Vector2();\n\n\tthis.material = null;\n\n};\n\n//\n\nTHREE.Projector = function () {\n\n\tvar _object, _objectCount, _objectPool = [], _objectPoolLength = 0,\n\t_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,\n\t_face, _faceCount, _facePool = [], _facePoolLength = 0,\n\t_line, _lineCount, _linePool = [], _linePoolLength = 0,\n\t_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,\n\n\t_renderData = { objects: [], lights: [], elements: [] },\n\n\t_vector3 = new THREE.Vector3(),\n\t_vector4 = new THREE.Vector4(),\n\n\t_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),\n\t_boundingBox = new THREE.Box3(),\n\t_points3 = new Array( 3 ),\n\t_points4 = new Array( 4 ),\n\n\t_viewMatrix = new THREE.Matrix4(),\n\t_viewProjectionMatrix = new THREE.Matrix4(),\n\n\t_modelMatrix,\n\t_modelViewProjectionMatrix = new THREE.Matrix4(),\n\n\t_normalMatrix = new THREE.Matrix3(),\n\n\t_frustum = new THREE.Frustum(),\n\n\t_clippedVertex1PositionScreen = new THREE.Vector4(),\n\t_clippedVertex2PositionScreen = new THREE.Vector4();\n\n\t//\n\n\tthis.projectVector = function ( vector, camera ) {\n\n\t\tconsole.warn( 'THREE.Projector: .projectVector() is now vector.project().' );\n\t\tvector.project( camera );\n\n\t};\n\n\tthis.unprojectVector = function ( vector, camera ) {\n\n\t\tconsole.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );\n\t\tvector.unproject( camera );\n\n\t};\n\n\tthis.pickingRay = function ( vector, camera ) {\n\n\t\tconsole.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );\n\n\t};\n\n\t//\n\n\tvar RenderList = function () {\n\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\tvar object = null;\n\t\tvar material = null;\n\n\t\tvar normalMatrix = new THREE.Matrix3();\n\n\t\tvar setObject = function ( value ) {\n\n\t\t\tobject = value;\n\t\t\tmaterial = object.material;\n\n\t\t\tnormalMatrix.getNormalMatrix( object.matrixWorld );\n\n\t\t\tnormals.length = 0;\n\t\t\tuvs.length = 0;\n\n\t\t};\n\n\t\tvar projectVertex = function ( vertex ) {\n\n\t\t\tvar position = vertex.position;\n\t\t\tvar positionWorld = vertex.positionWorld;\n\t\t\tvar positionScreen = vertex.positionScreen;\n\n\t\t\tpositionWorld.copy( position ).applyMatrix4( _modelMatrix );\n\t\t\tpositionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );\n\n\t\t\tvar invW = 1 / positionScreen.w;\n\n\t\t\tpositionScreen.x *= invW;\n\t\t\tpositionScreen.y *= invW;\n\t\t\tpositionScreen.z *= invW;\n\n\t\t\tvertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&\n\t\t\t\t\t positionScreen.y >= - 1 && positionScreen.y <= 1 &&\n\t\t\t\t\t positionScreen.z >= - 1 && positionScreen.z <= 1;\n\n\t\t};\n\n\t\tvar pushVertex = function ( x, y, z ) {\n\n\t\t\t_vertex = getNextVertexInPool();\n\t\t\t_vertex.position.set( x, y, z );\n\n\t\t\tprojectVertex( _vertex );\n\n\t\t};\n\n\t\tvar pushNormal = function ( x, y, z ) {\n\n\t\t\tnormals.push( x, y, z );\n\n\t\t};\n\n\t\tvar pushUv = function ( x, y ) {\n\n\t\t\tuvs.push( x, y );\n\n\t\t};\n\n\t\tvar checkTriangleVisibility = function ( v1, v2, v3 ) {\n\n\t\t\tif ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;\n\n\t\t\t_points3[ 0 ] = v1.positionScreen;\n\t\t\t_points3[ 1 ] = v2.positionScreen;\n\t\t\t_points3[ 2 ] = v3.positionScreen;\n\n\t\t\treturn _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) );\n\n\t\t};\n\n\t\tvar checkBackfaceCulling = function ( v1, v2, v3 ) {\n\n\t\t\treturn ( ( v3.positionScreen.x - v1.positionScreen.x ) *\n\t\t\t\t    ( v2.positionScreen.y - v1.positionScreen.y ) -\n\t\t\t\t    ( v3.positionScreen.y - v1.positionScreen.y ) *\n\t\t\t\t    ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;\n\n\t\t};\n\n\t\tvar pushLine = function ( a, b ) {\n\n\t\t\tvar v1 = _vertexPool[ a ];\n\t\t\tvar v2 = _vertexPool[ b ];\n\n\t\t\t_line = getNextLineInPool();\n\n\t\t\t_line.id = object.id;\n\t\t\t_line.v1.copy( v1 );\n\t\t\t_line.v2.copy( v2 );\n\t\t\t_line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;\n\n\t\t\t_line.material = object.material;\n\n\t\t\t_renderData.elements.push( _line );\n\n\t\t};\n\n\t\tvar pushTriangle = function ( a, b, c ) {\n\n\t\t\tvar v1 = _vertexPool[ a ];\n\t\t\tvar v2 = _vertexPool[ b ];\n\t\t\tvar v3 = _vertexPool[ c ];\n\n\t\t\tif ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;\n\n\t\t\tif ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {\n\n\t\t\t\t_face = getNextFaceInPool();\n\n\t\t\t\t_face.id = object.id;\n\t\t\t\t_face.v1.copy( v1 );\n\t\t\t\t_face.v2.copy( v2 );\n\t\t\t\t_face.v3.copy( v3 );\n\t\t\t\t_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;\n\n\t\t\t\tfor ( var i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tvar offset = arguments[ i ] * 3;\n\t\t\t\t\tvar normal = _face.vertexNormalsModel[ i ];\n\n\t\t\t\t\tnormal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] );\n\t\t\t\t\tnormal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\t\tvar offset2 = arguments[ i ] * 2;\n\n\t\t\t\t\tvar uv = _face.uvs[ i ];\n\t\t\t\t\tuv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] );\n\n\t\t\t\t}\n\n\t\t\t\t_face.vertexNormalsLength = 3;\n\n\t\t\t\t_face.material = object.material;\n\n\t\t\t\t_renderData.elements.push( _face );\n\n\t\t\t}\n\n\t\t};\n\n\t\treturn {\n\t\t\tsetObject: setObject,\n\t\t\tprojectVertex: projectVertex,\n\t\t\tcheckTriangleVisibility: checkTriangleVisibility,\n\t\t\tcheckBackfaceCulling: checkBackfaceCulling,\n\t\t\tpushVertex: pushVertex,\n\t\t\tpushNormal: pushNormal,\n\t\t\tpushUv: pushUv,\n\t\t\tpushLine: pushLine,\n\t\t\tpushTriangle: pushTriangle\n\t\t}\n\n\t};\n\n\tvar renderList = new RenderList();\n\n\tthis.projectScene = function ( scene, camera, sortObjects, sortElements ) {\n\n\t\t_faceCount = 0;\n\t\t_lineCount = 0;\n\t\t_spriteCount = 0;\n\n\t\t_renderData.elements.length = 0;\n\n\t\tif ( scene.autoUpdate === true ) scene.updateMatrixWorld();\n\t\tif ( camera.parent === undefined ) camera.updateMatrixWorld();\n\n\t\t_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );\n\t\t_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );\n\n\t\t_frustum.setFromMatrix( _viewProjectionMatrix );\n\n\t\t//\n\n\t\t_objectCount = 0;\n\n\t\t_renderData.objects.length = 0;\n\t\t_renderData.lights.length = 0;\n\n\t\tscene.traverseVisible( function ( object ) {\n\n\t\t\tif ( object instanceof THREE.Light ) {\n\n\t\t\t\t_renderData.lights.push( object );\n\n\t\t\t} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {\n\n\t\t\t\tif ( object.material.visible === false ) return;\n\n\t\t\t\tif ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {\n\n\t\t\t\t\t_object = getNextObjectInPool();\n\t\t\t\t\t_object.id = object.id;\n\t\t\t\t\t_object.object = object;\n\n\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld );\n\t\t\t\t\t_vector3.applyProjection( _viewProjectionMatrix );\n\t\t\t\t\t_object.z = _vector3.z;\n\n\t\t\t\t\t_renderData.objects.push( _object );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t\tif ( sortObjects === true ) {\n\n\t\t\t_renderData.objects.sort( painterSort );\n\n\t\t}\n\n\t\t//\n\n\t\tfor ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {\n\n\t\t\tvar object = _renderData.objects[ o ].object;\n\t\t\tvar geometry = object.geometry;\n\n\t\t\trenderList.setObject( object );\n\n\t\t\t_modelMatrix = object.matrixWorld;\n\n\t\t\t_vertexCount = 0;\n\n\t\t\tif ( object instanceof THREE.Mesh ) {\n\n\t\t\t\tif ( geometry instanceof THREE.BufferGeometry ) {\n\n\t\t\t\t\tvar attributes = geometry.attributes;\n\t\t\t\t\tvar offsets = geometry.offsets;\n\n\t\t\t\t\tif ( attributes.position === undefined ) continue;\n\n\t\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\t\tfor ( var i = 0, l = positions.length; i < l; i += 3 ) {\n\n\t\t\t\t\t\trenderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( attributes.normal !== undefined ) {\n\n\t\t\t\t\t\tvar normals = attributes.normal.array;\n\n\t\t\t\t\t\tfor ( var i = 0, l = normals.length; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\trenderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( attributes.uv !== undefined ) {\n\n\t\t\t\t\t\tvar uvs = attributes.uv.array;\n\n\t\t\t\t\t\tfor ( var i = 0, l = uvs.length; i < l; i += 2 ) {\n\n\t\t\t\t\t\t\trenderList.pushUv( uvs[ i ], uvs[ i + 1 ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( attributes.index !== undefined ) {\n\n\t\t\t\t\t\tvar indices = attributes.index.array;\n\n\t\t\t\t\t\tif ( offsets.length > 0 ) {\n\n\t\t\t\t\t\t\tfor ( var o = 0; o < offsets.length; o ++ ) {\n\n\t\t\t\t\t\t\t\tvar offset = offsets[ o ];\n\t\t\t\t\t\t\t\tvar index = offset.index;\n\n\t\t\t\t\t\t\t\tfor ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\t\t\trenderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( var i = 0, l = indices.length; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\t\trenderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfor ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\trenderList.pushTriangle( i, i + 1, i + 2 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( geometry instanceof THREE.Geometry ) {\n\n\t\t\t\t\tvar vertices = geometry.vertices;\n\t\t\t\t\tvar faces = geometry.faces;\n\t\t\t\t\tvar faceVertexUvs = geometry.faceVertexUvs[ 0 ];\n\n\t\t\t\t\t_normalMatrix.getNormalMatrix( _modelMatrix );\n\n\t\t\t\t\tvar material = object.material;\n\t\t\t\t\t\n\t\t\t\t\tvar isFaceMaterial = material instanceof THREE.MeshFaceMaterial;\n\t\t\t\t\tvar objectMaterials = isFaceMaterial === true ? object.material : null;\n\n\t\t\t\t\tfor ( var v = 0, vl = vertices.length; v < vl; v ++ ) {\n\n\t\t\t\t\t\tvar vertex = vertices[ v ];\n\n\t\t\t\t\t\t_vector3.copy( vertex );\n\n\t\t\t\t\t\tif ( material.morphTargets === true ) {\n\n\t\t\t\t\t\t\tvar morphTargets = geometry.morphTargets;\n\t\t\t\t\t\t\tvar morphInfluences = object.morphTargetInfluences;\n\n\t\t\t\t\t\t\tfor ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {\n\n\t\t\t\t\t\t\t\tvar influence = morphInfluences[ t ];\n\n\t\t\t\t\t\t\t\tif ( influence === 0 ) continue;\n\n\t\t\t\t\t\t\t\tvar target = morphTargets[ t ];\n\t\t\t\t\t\t\t\tvar targetVertex = target.vertices[ v ];\n\n\t\t\t\t\t\t\t\t_vector3.x += ( targetVertex.x - vertex.x ) * influence;\n\t\t\t\t\t\t\t\t_vector3.y += ( targetVertex.y - vertex.y ) * influence;\n\t\t\t\t\t\t\t\t_vector3.z += ( targetVertex.z - vertex.z ) * influence;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trenderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( var f = 0, fl = faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\t\tvar face = faces[ f ];\n\n\t\t\t\t\t\tvar material = isFaceMaterial === true\n\t\t\t\t\t\t\t ? objectMaterials.materials[ face.materialIndex ]\n\t\t\t\t\t\t\t : object.material;\n\n\t\t\t\t\t\tif ( material === undefined ) continue;\n\n\t\t\t\t\t\tvar side = material.side;\n\n\t\t\t\t\t\tvar v1 = _vertexPool[ face.a ];\n\t\t\t\t\t\tvar v2 = _vertexPool[ face.b ];\n\t\t\t\t\t\tvar v3 = _vertexPool[ face.c ];\n\n\t\t\t\t\t\tif ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;\n\n\t\t\t\t\t\tvar visible = renderList.checkBackfaceCulling( v1, v2, v3 );\n\n\t\t\t\t\t\tif ( side !== THREE.DoubleSide ) {\n\t\t\t\t\t\t\tif ( side === THREE.FrontSide && visible === false ) continue;\n\t\t\t\t\t\t\tif ( side === THREE.BackSide && visible === true ) continue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_face = getNextFaceInPool();\n\n\t\t\t\t\t\t_face.id = object.id;\n\t\t\t\t\t\t_face.v1.copy( v1 );\n\t\t\t\t\t\t_face.v2.copy( v2 );\n\t\t\t\t\t\t_face.v3.copy( v3 );\n\n\t\t\t\t\t\t_face.normalModel.copy( face.normal );\n\n\t\t\t\t\t\tif ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {\n\n\t\t\t\t\t\t\t_face.normalModel.negate();\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_face.normalModel.applyMatrix3( _normalMatrix ).normalize();\n\n\t\t\t\t\t\tvar faceVertexNormals = face.vertexNormals;\n\n\t\t\t\t\t\tfor ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {\n\n\t\t\t\t\t\t\tvar normalModel = _face.vertexNormalsModel[ n ];\n\t\t\t\t\t\t\tnormalModel.copy( faceVertexNormals[ n ] );\n\n\t\t\t\t\t\t\tif ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {\n\n\t\t\t\t\t\t\t\tnormalModel.negate();\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnormalModel.applyMatrix3( _normalMatrix ).normalize();\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_face.vertexNormalsLength = faceVertexNormals.length;\n\n\t\t\t\t\t\tvar vertexUvs = faceVertexUvs[ f ];\n\n\t\t\t\t\t\tif ( vertexUvs !== undefined ) {\n\n\t\t\t\t\t\t\tfor ( var u = 0; u < 3; u ++ ) {\n\n\t\t\t\t\t\t\t\t_face.uvs[ u ].copy( vertexUvs[ u ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_face.color = face.color;\n\t\t\t\t\t\t_face.material = material;\n\n\t\t\t\t\t\t_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;\n\n\t\t\t\t\t\t_renderData.elements.push( _face );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( object instanceof THREE.Line ) {\n\n\t\t\t\tif ( geometry instanceof THREE.BufferGeometry ) {\n\n\t\t\t\t\tvar attributes = geometry.attributes;\n\n\t\t\t\t\tif ( attributes.position !== undefined ) {\n\n\t\t\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\t\t\tfor ( var i = 0, l = positions.length; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\trenderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( attributes.index !== undefined ) {\n\n\t\t\t\t\t\t\tvar indices = attributes.index.array;\n\n\t\t\t\t\t\t\tfor ( var i = 0, l = indices.length; i < l; i += 2 ) {\n\n\t\t\t\t\t\t\t\trenderList.pushLine( indices[ i ], indices[ i + 1 ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tvar step = object.mode === THREE.LinePieces ? 2 : 1;\n\n\t\t\t\t\t\t\tfor ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {\n\n\t\t\t\t\t\t\t\trenderList.pushLine( i, i + 1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( geometry instanceof THREE.Geometry ) {\n\n\t\t\t\t\t_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );\n\n\t\t\t\t\tvar vertices = object.geometry.vertices;\n\n\t\t\t\t\tif ( vertices.length === 0 ) continue;\n\n\t\t\t\t\tv1 = getNextVertexInPool();\n\t\t\t\t\tv1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );\n\n\t\t\t\t\t// Handle LineStrip and LinePieces\n\t\t\t\t\tvar step = object.mode === THREE.LinePieces ? 2 : 1;\n\n\t\t\t\t\tfor ( var v = 1, vl = vertices.length; v < vl; v ++ ) {\n\n\t\t\t\t\t\tv1 = getNextVertexInPool();\n\t\t\t\t\t\tv1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );\n\n\t\t\t\t\t\tif ( ( v + 1 ) % step > 0 ) continue;\n\n\t\t\t\t\t\tv2 = _vertexPool[ _vertexCount - 2 ];\n\n\t\t\t\t\t\t_clippedVertex1PositionScreen.copy( v1.positionScreen );\n\t\t\t\t\t\t_clippedVertex2PositionScreen.copy( v2.positionScreen );\n\n\t\t\t\t\t\tif ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {\n\n\t\t\t\t\t\t\t// Perform the perspective divide\n\t\t\t\t\t\t\t_clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );\n\t\t\t\t\t\t\t_clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );\n\n\t\t\t\t\t\t\t_line = getNextLineInPool();\n\n\t\t\t\t\t\t\t_line.id = object.id;\n\t\t\t\t\t\t\t_line.v1.positionScreen.copy( _clippedVertex1PositionScreen );\n\t\t\t\t\t\t\t_line.v2.positionScreen.copy( _clippedVertex2PositionScreen );\n\n\t\t\t\t\t\t\t_line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );\n\n\t\t\t\t\t\t\t_line.material = object.material;\n\n\t\t\t\t\t\t\tif ( object.material.vertexColors === THREE.VertexColors ) {\n\n\t\t\t\t\t\t\t\t_line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );\n\t\t\t\t\t\t\t\t_line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_renderData.elements.push( _line );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( object instanceof THREE.Sprite ) {\n\n\t\t\t\t_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );\n\t\t\t\t_vector4.applyMatrix4( _viewProjectionMatrix );\n\n\t\t\t\tvar invW = 1 / _vector4.w;\n\n\t\t\t\t_vector4.z *= invW;\n\n\t\t\t\tif ( _vector4.z >= - 1 && _vector4.z <= 1 ) {\n\n\t\t\t\t\t_sprite = getNextSpriteInPool();\n\t\t\t\t\t_sprite.id = object.id;\n\t\t\t\t\t_sprite.x = _vector4.x * invW;\n\t\t\t\t\t_sprite.y = _vector4.y * invW;\n\t\t\t\t\t_sprite.z = _vector4.z;\n\t\t\t\t\t_sprite.object = object;\n\n\t\t\t\t\t_sprite.rotation = object.rotation;\n\n\t\t\t\t\t_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );\n\t\t\t\t\t_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );\n\n\t\t\t\t\t_sprite.material = object.material;\n\n\t\t\t\t\t_renderData.elements.push( _sprite );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( sortElements === true ) {\n\n\t\t\t_renderData.elements.sort( painterSort );\n\n\t\t}\n\n\t\treturn _renderData;\n\n\t};\n\n\t// Pools\n\n\tfunction getNextObjectInPool() {\n\n\t\tif ( _objectCount === _objectPoolLength ) {\n\n\t\t\tvar object = new THREE.RenderableObject();\n\t\t\t_objectPool.push( object );\n\t\t\t_objectPoolLength ++;\n\t\t\t_objectCount ++;\n\t\t\treturn object;\n\n\t\t}\n\n\t\treturn _objectPool[ _objectCount ++ ];\n\n\t}\n\n\tfunction getNextVertexInPool() {\n\n\t\tif ( _vertexCount === _vertexPoolLength ) {\n\n\t\t\tvar vertex = new THREE.RenderableVertex();\n\t\t\t_vertexPool.push( vertex );\n\t\t\t_vertexPoolLength ++;\n\t\t\t_vertexCount ++;\n\t\t\treturn vertex;\n\n\t\t}\n\n\t\treturn _vertexPool[ _vertexCount ++ ];\n\n\t}\n\n\tfunction getNextFaceInPool() {\n\n\t\tif ( _faceCount === _facePoolLength ) {\n\n\t\t\tvar face = new THREE.RenderableFace();\n\t\t\t_facePool.push( face );\n\t\t\t_facePoolLength ++;\n\t\t\t_faceCount ++;\n\t\t\treturn face;\n\n\t\t}\n\n\t\treturn _facePool[ _faceCount ++ ];\n\n\n\t}\n\n\tfunction getNextLineInPool() {\n\n\t\tif ( _lineCount === _linePoolLength ) {\n\n\t\t\tvar line = new THREE.RenderableLine();\n\t\t\t_linePool.push( line );\n\t\t\t_linePoolLength ++;\n\t\t\t_lineCount ++\n\t\t\treturn line;\n\n\t\t}\n\n\t\treturn _linePool[ _lineCount ++ ];\n\n\t}\n\n\tfunction getNextSpriteInPool() {\n\n\t\tif ( _spriteCount === _spritePoolLength ) {\n\n\t\t\tvar sprite = new THREE.RenderableSprite();\n\t\t\t_spritePool.push( sprite );\n\t\t\t_spritePoolLength ++;\n\t\t\t_spriteCount ++\n\t\t\treturn sprite;\n\n\t\t}\n\n\t\treturn _spritePool[ _spriteCount ++ ];\n\n\t}\n\n\t//\n\n\tfunction painterSort( a, b ) {\n\n\t\tif ( a.z !== b.z ) {\n\n\t\t\treturn b.z - a.z;\n\n\t\t} else if ( a.id !== b.id ) {\n\n\t\t\treturn a.id - b.id;\n\n\t\t} else {\n\n\t\t\treturn 0;\n\n\t\t}\n\n\t}\n\n\tfunction clipLine( s1, s2 ) {\n\n\t\tvar alpha1 = 0, alpha2 = 1,\n\n\t\t// Calculate the boundary coordinate of each vertex for the near and far clip planes,\n\t\t// Z = -1 and Z = +1, respectively.\n\t\tbc1near =  s1.z + s1.w,\n\t\tbc2near =  s2.z + s2.w,\n\t\tbc1far =  - s1.z + s1.w,\n\t\tbc2far =  - s2.z + s2.w;\n\n\t\tif ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {\n\n\t\t\t// Both vertices lie entirely within all clip planes.\n\t\t\treturn true;\n\n\t\t} else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {\n\n\t\t\t// Both vertices lie entirely outside one of the clip planes.\n\t\t\treturn false;\n\n\t\t} else {\n\n\t\t\t// The line segment spans at least one clip plane.\n\n\t\t\tif ( bc1near < 0 ) {\n\n\t\t\t\t// v1 lies outside the near plane, v2 inside\n\t\t\t\talpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );\n\n\t\t\t} else if ( bc2near < 0 ) {\n\n\t\t\t\t// v2 lies outside the near plane, v1 inside\n\t\t\t\talpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );\n\n\t\t\t}\n\n\t\t\tif ( bc1far < 0 ) {\n\n\t\t\t\t// v1 lies outside the far plane, v2 inside\n\t\t\t\talpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );\n\n\t\t\t} else if ( bc2far < 0 ) {\n\n\t\t\t\t// v2 lies outside the far plane, v2 inside\n\t\t\t\talpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );\n\n\t\t\t}\n\n\t\t\tif ( alpha2 < alpha1 ) {\n\n\t\t\t\t// The line segment spans two boundaries, but is outside both of them.\n\t\t\t\t// (This can't happen when we're only clipping against just near/far but good\n\t\t\t\t//  to leave the check here for future usage if other clip planes are added.)\n\t\t\t\treturn false;\n\n\t\t\t} else {\n\n\t\t\t\t// Update the s1 and s2 vertices to match the clipped line segment.\n\t\t\t\ts1.lerp( s2, alpha1 );\n\t\t\t\ts2.lerp( s1, 1 - alpha2 );\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n};\n"
  }
]