Ver Fonte

Merge remote branch 'upstream/master'

Conflicts:
	src/renderers/Renderer.js
	src/renderers/WebGLRenderer.js
Julian Walker há 15 anos atrás
pai
commit
69287b8d10
61 ficheiros alterados com 1830 adições e 498 exclusões
  1. 11 0
      AUTHORS
  2. 1 1
      LICENSE
  3. 15 5
      README.md
  4. 19 15
      TODO
  5. 0 1
      build/Three.js
  6. 0 1
      build/ThreeDebug.js
  7. 39 18
      examples/camera_free.html
  8. 1 0
      examples/geometry/Qrcode.js
  9. 47 0
      examples/geometry/primitives/ClickCube.js
  10. 1 0
      examples/geometry/primitives/Cube.js
  11. 1 0
      examples/geometry/primitives/Cylinder.js
  12. 1 0
      examples/geometry/primitives/Plane.js
  13. 3 0
      examples/geometry/primitives/Sphere.js
  14. 1 1
      examples/geometry_birds.html
  15. 26 26
      examples/geometry_cube.html
  16. 1 1
      examples/geometry_earth.html
  17. 1 1
      examples/geometry_terrain.html
  18. 187 0
      examples/hci_clickcube.html
  19. 1 0
      examples/js/Stats.js
  20. 1 1
      examples/materials_video.html
  21. 1 1
      examples/particles_floor.html
  22. 20 20
      examples/particles_random.html
  23. 32 32
      examples/particles_waves.html
  24. 21 13
      examples/test.html
  25. 2 0
      src/cameras/Camera.js
  26. 50 9
      src/core/Color.js
  27. 10 2
      src/core/Face3.js
  28. 9 8
      src/core/Face4.js
  29. 40 10
      src/core/Geometry.js
  30. 19 8
      src/core/Matrix4.js
  31. 13 1
      src/core/Vector2.js
  32. 18 0
      src/core/Vector3.js
  33. 8 0
      src/core/Vector4.js
  34. 5 1
      src/core/Vertex.js
  35. 202 0
      src/hci/ClickResolver.js
  36. 10 0
      src/hci/SelectableFace3.js
  37. 11 0
      src/hci/SelectableFace4.js
  38. 4 4
      src/lights/AmbientLight.js
  39. 7 8
      src/lights/DirectionalLight.js
  40. 3 3
      src/lights/Light.js
  41. 11 0
      src/lights/PointLight.js
  42. 14 6
      src/objects/Object3D.js
  43. 279 26
      src/renderers/CanvasRenderer.js
  44. 6 7
      src/renderers/DOMRenderer.js
  45. 230 0
      src/renderers/Projector.js
  46. 0 225
      src/renderers/Renderer.js
  47. 150 13
      src/renderers/SVGRenderer.js
  48. 5 3
      src/renderers/WebGLRenderer.js
  49. 3 0
      src/renderers/renderables/RenderableFace3.js
  50. 3 0
      src/renderers/renderables/RenderableFace4.js
  51. 6 5
      utils/Builder.py
  52. 6 5
      utils/BuilderCanvas.py
  53. 1 1
      utils/BuilderDOM.py
  54. 6 5
      utils/BuilderDebug.py
  55. 6 6
      utils/BuilderSVG.py
  56. 5 4
      utils/BuilderWebGL.py
  57. 1 1
      utils/REVISION
  58. 80 0
      utils/exporters/blender/2.54/scripts/op/io_mesh_threejs/__init__.py
  59. 176 0
      utils/exporters/blender/2.54/scripts/op/io_mesh_threejs/export_threejs.py
  60. 0 0
      utils/exporters/blender/export_threejs_2.53b.py
  61. 0 0
      utils/exporters/blender/export_threejs_2.5a2.py

+ 11 - 0
AUTHORS

@@ -0,0 +1,11 @@
+Authors ordered by first contribution.
+
+http://github.com/mrdoob
+http://github.com/supereggbert
+http://github.com/sole
+http://kile.stravaganza.org
+http://github.com/kikko
+http://github.com/philogb
+http://github.com/julianwa
+http://github.com/mindlapse
+http://github.com/alteredq

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 The MIT License
 
-Copyright (c) 2010 Mr.doob
+Copyright (c) 2010 Mr.doob, http://mrdoob.com
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 15 - 5
README.md

@@ -101,13 +101,14 @@ For creating a customised version of the library, including the source files in
 	<script type="text/javascript" src="js/three/core/UV.js"></script>
 	<script type="text/javascript" src="js/three/core/Geometry.js"></script>
 	<script type="text/javascript" src="js/three/cameras/Camera.js"></script>
-	<script type="text/javascript" src="js/three/objects/Object3D.js"></script>
-	<script type="text/javascript" src="js/three/objects/Line.js"></script>
-	<script type="text/javascript" src="js/three/objects/Mesh.js"></script>
-	<script type="text/javascript" src="js/three/objects/Particle.js"></script>
 	<script type="text/javascript" src="js/three/lights/Light.js"></script>
 	<script type="text/javascript" src="js/three/lights/AmbientLight.js"></script>
 	<script type="text/javascript" src="js/three/lights/DirectionalLight.js"></script>
+	<script type="text/javascript" src="js/three/lights/PointLight.js"></script>
+	<script type="text/javascript" src="js/three/objects/Object3D.js"></script>
+	<script type="text/javascript" src="js/three/objects/Particle.js"></script>
+	<script type="text/javascript" src="js/three/objects/Line.js"></script>
+	<script type="text/javascript" src="js/three/objects/Mesh.js"></script>
 	<script type="text/javascript" src="js/three/materials/LineColorMaterial.js"></script>
 	<script type="text/javascript" src="js/three/materials/MeshBitmapUVMappingMaterial.js"></script>
 	<script type="text/javascript" src="js/three/materials/MeshColorFillMaterial.js"></script>
@@ -117,7 +118,7 @@ For creating a customised version of the library, including the source files in
 	<script type="text/javascript" src="js/three/materials/ParticleBitmapMaterial.js"></script>
 	<script type="text/javascript" src="js/three/materials/ParticleCircleMaterial.js"></script>
 	<script type="text/javascript" src="js/three/scenes/Scene.js"></script>
-	<script type="text/javascript" src="js/three/renderers/Renderer.js"></script>
+	<script type="text/javascript" src="js/three/renderers/Projector.js"></script>
 	<script type="text/javascript" src="js/three/renderers/CanvasRenderer.js"></script>
 	<script type="text/javascript" src="js/three/renderers/SVGRenderer.js"></script>
 	<script type="text/javascript" src="js/three/renderers/WebGLRenderer.js"></script>
@@ -136,6 +137,15 @@ Thanks to the power of the internets (and github <3) these people have kindly he
 
 ### Change Log ###
 
+2010 10 06 - **r18** (44.420 kb)
+
+* Added `PointLight`
+* `CanvasRenderer` and `SVGRenderer` basic lighting support (ColorStroke/ColorFill only)
+* `Renderer` > `Projector`. `CanvasRenderer`, `SVGRenderer` and `DOMRenderer` do not extend anymore
+* Interactivity base code (hdi folder). To be refactored... ([mindlapse](http://github.com/mindlapse))
+* Added `computeCentroids` method to `Geometry`
+
+
 2010 09 17 - **r17** (39.487 kb)
 
 * Added `Light`, `AmbientLight` and `DirectionalLight` ([philogb](http://github.com/philogb))

+ 19 - 15
TODO

@@ -1,16 +1,20 @@
-- Core
-	- Simple hierarchy system (look at D1plo1d and tamask branches)
-	- Interaction, 2D to 3D projection.
-- Examples
-	- DOMRenderer example
-- Materials
-	- MeshBitmapSphereMappingMaterial. http://en.wikipedia.org/wiki/Sphere_mapping
-	- MeshBitmapCubeMappingMaterial. http://en.wikipedia.org/wiki/Cube_mapping
-	- MeshShaderMaterial for WebGLRenderer
-	- Add MeshBitmapUVMappingMaterial to WebGLRenderer
-- Renderers
-	- Add Lights to Renderer (CanvasRenderer and SVGRenderer)
-	- FrustrumClipping near to Renderer (CanvasRenderer and SVGRenderer)
-- Utils
-	- Blender 2.5b4 plugin system has change considerably :/
+Core
+* Simple hierarchy system (look at D1plo1d and tamask branches)
+* Interaction, 2D to 3D projection. (look at mindlapse branch)
 
+Examples
+* DOMRenderer example
+
+Materials
+* MeshFaceMaterial? (Renderer would use face materials instead, MeshFaceColorFillFaceMaterial/MeshFaceColorStrokeMaterial wouldn't be needed?)
+* MeshBitmapSphereMappingMaterial. http://en.wikipedia.org/wiki/Sphere_mapping
+* MeshBitmapCubeMappingMaterial. http://en.wikipedia.org/wiki/Cube_mapping
+* MeshBitmapMaterial? (Merge all MeshBitmap*Materials and have a mode parameter like... MeshBitmapMaterial.UV_MAPPING)
+* MeshShaderMaterial for WebGLRenderer
+* Add MeshBitmapUVMappingMaterial to WebGLRenderer
+
+Renderers
+* Add PointLight to WebGLRenderer
+* WebGLRenderer support MeshBitmapUVMappingMaterial (look at alteredq branch)
+* Double check DirectionalLight WebGLRenderer code (doesn't seem correct)
+* FrustrumClipping near to Renderer (CanvasRenderer and SVGRenderer)

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 1
build/Three.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 1
build/ThreeDebug.js


+ 39 - 18
examples/camera_free.html

@@ -30,6 +30,10 @@
 		<script type="text/javascript" src="../src/core/UV.js"></script>
 		<script type="text/javascript" src="../src/core/Geometry.js"></script>
 		<script type="text/javascript" src="../src/cameras/Camera.js"></script>
+		<script type="text/javascript" src="../src/lights/Light.js"></script>
+		<script type="text/javascript" src="../src/lights/AmbientLight.js"></script>
+		<script type="text/javascript" src="../src/lights/DirectionalLight.js"></script>
+		<script type="text/javascript" src="../src/lights/PointLight.js"></script>
 		<script type="text/javascript" src="../src/objects/Object3D.js"></script>
 		<script type="text/javascript" src="../src/objects/Mesh.js"></script>
 		<script type="text/javascript" src="../src/objects/Particle.js"></script>
@@ -43,7 +47,7 @@
 		<script type="text/javascript" src="../src/materials/ParticleCircleMaterial.js"></script>
 		<script type="text/javascript" src="../src/materials/ParticleBitmapMaterial.js"></script>
 		<script type="text/javascript" src="../src/scenes/Scene.js"></script>
-		<script type="text/javascript" src="../src/renderers/Renderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/Projector.js"></script>
 		<script type="text/javascript" src="../src/renderers/CanvasRenderer.js"></script>
 		<script type="text/javascript" src="../src/renderers/SVGRenderer.js"></script>
 		<script type="text/javascript" src="../src/renderers/WebGLRenderer.js"></script>
@@ -54,10 +58,10 @@
 
 		<script type="text/javascript" src="cameras/FreeCamera.js"></script>
 
-		<script type="text/javascript" src="geometry/primitives/Cube.js"></script>
+		<script type="text/javascript" src="geometry/primitives/Sphere.js"></script>
 		<script type="text/javascript" src="geometry/primitives/Plane.js"></script>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 
@@ -99,6 +103,7 @@
 			var debugContext;
 
 			init();
+			loop();
 			setInterval(loop, 1000/60);
 
 			function init() {
@@ -113,18 +118,21 @@
 
 				scene = new THREE.Scene();
 
-				// Cube
+				// Plane
 
-				geometry = new Cube(200, 200, 200);
+				plane = new THREE.Mesh( new Plane( 1000, 1000, 10, 10 ), new THREE.MeshColorStrokeMaterial( 0x000000, 0.5, 1 ) );
+				plane.rotation.x = - 90 * ( Math.PI / 180 );
+				plane.doubleSided = true;
+				scene.add( plane );
 
-				for (var i = 0; i < geometry.faces.length; i++) {
+				// Spheres
 
-					geometry.faces[i].color.setRGBA( Math.random() * 0.5, Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 1 );
-				}
+				geometry = new Sphere( 100, 16, 8 );
 
 				for (var i = 0; i < 10; i ++ ) {
 
-					cube = new THREE.Mesh(geometry, new THREE.MeshFaceColorFillMaterial() );
+					cube = new THREE.Mesh(geometry, new THREE.MeshColorFillMaterial( 0xffffff ) );
+					cube.overdraw = true;
 
 					cube.position.x = Math.random() * 1000 - 500;
 					cube.position.y = Math.random() * 1000 - 500;
@@ -140,16 +148,26 @@
 
 				}
 
-				// Plane
+				// Lights
+
+				var ambientLight = new THREE.AmbientLight( Math.random() * 0x202020 );
+				scene.addLight( ambientLight );
+
+				var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff );
+				directionalLight.position.x = Math.random() - 0.5;
+				directionalLight.position.y = Math.random() - 0.5;
+				directionalLight.position.z = Math.random() - 0.5;
+				directionalLight.position.normalize();
+				scene.addLight( directionalLight );
+
+				var pointLight = new THREE.PointLight( 0xff0000, 1 );
+				scene.addLight( pointLight );
 
-				plane = new THREE.Mesh( new Plane( 1000, 1000, 10, 10 ), new THREE.MeshColorStrokeMaterial( 0x000000, 0.5, 1 ) );
-				plane.rotation.x = -90 * (Math.PI / 180);
-				scene.add(plane);
 
 				renderer = new THREE.CanvasRenderer();
-				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 
-				container.appendChild(renderer.domElement);
+				container.appendChild( renderer.domElement );
 
 				var debugCanvas = document.createElement( 'canvas' );
 				debugCanvas.width = 512;
@@ -169,8 +187,8 @@
 				stats.domElement.style.top = '0px';
 				container.appendChild(stats.domElement);
 
-				document.addEventListener('keydown', onDocumentKeyDown, false);
-				document.addEventListener('keyup', onDocumentKeyUp, false);
+				document.addEventListener( 'keydown', onDocumentKeyDown, false );
+				document.addEventListener( 'keyup', onDocumentKeyUp, false );
 			}
 
 			function onDocumentKeyDown( event ) {
@@ -251,9 +269,12 @@
 				debugContext.rect( camera.target.position.x * 0.1 - 5, camera.target.position.z * 0.1 - 5, 10, 10 );
 				debugContext.rect( - 50, - 50, 100, 100 );
 
-				for ( var i = 0; i < scene.objects.length; i++ ) {
+				for ( var i = 1; i < scene.objects.length; i++ ) {
 
 					var object = scene.objects[i];
+					object.rotation.x += 0.01;
+					object.rotation.y += 0.005;
+					object.position.y = Math.sin( object.rotation.x ) * 200;
 
 					debugContext.rect( object.position.x * 0.1 - 5, object.position.z * 0.1 - 5, 10, 10 );
 

+ 1 - 0
examples/geometry/Qrcode.js

@@ -1431,6 +1431,7 @@ var Qrcode = function () {
 	f4(20,21,363,362,0xffc0c0c0);
 	f4(19,20,362,361,0xffc0c0c0);
 
+	this.computeCentroids();
 	this.computeNormals();
 
 	function v( x, y, z ) {

+ 47 - 0
examples/geometry/primitives/ClickCube.js

@@ -0,0 +1,47 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+var ClickCube = function (width, height, depth, onSelect) {
+
+	THREE.Geometry.call(this);
+
+	var scope = this,
+	width_half = width / 2,
+	height_half = height / 2,
+	depth_half = depth / 2;
+
+	v(  width_half,  height_half, -depth_half );
+	v(  width_half, -height_half, -depth_half );
+	v( -width_half, -height_half, -depth_half );
+	v( -width_half,  height_half, -depth_half );
+	v(  width_half,  height_half,  depth_half );
+	v(  width_half, -height_half,  depth_half );
+	v( -width_half, -height_half,  depth_half );
+	v( -width_half,  height_half,  depth_half );
+
+	f4( 0, 1, 2, 3 );
+	
+	f4( 4, 7, 6, 5 );
+	f4( 0, 4, 5, 1 );
+	f4( 2, 6, 7, 3 );
+	f4( 1, 5, 6, 2 );
+	f4( 4, 0, 3, 7 );
+
+	function v(x, y, z) {
+
+		scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
+	}
+
+	function f4(a, b, c, d) {
+		var f = new THREE.SelectableFace4( a, b, c, d, onSelect );
+		scope.faces.push(f);
+	}
+
+	this.computeCentroids();
+	this.computeNormals();
+
+};
+
+ClickCube.prototype = new THREE.Geometry();
+ClickCube.prototype.constructor = ClickCube;

+ 1 - 0
examples/geometry/primitives/Cube.js

@@ -37,6 +37,7 @@ var Cube = function (width, height, depth) {
 		scope.faces.push( new THREE.Face4( a, b, c, d ) );
 	}
 
+	this.computeCentroids();
 	this.computeNormals();
 
 }

+ 1 - 0
examples/geometry/primitives/Cylinder.js

@@ -65,6 +65,7 @@ var Cylinder = function (numSegs, topRad, botRad, height, topOffset, botOffset)
 		}
 	}
 
+	this.computeCentroids();
 	this.computeNormals();
 
 	function v(x, y, z) {

+ 1 - 0
examples/geometry/primitives/Plane.js

@@ -52,6 +52,7 @@ var Plane = function ( width, height, segments_width, segments_height ) {
 
 	}
 
+	this.computeCentroids();
 	this.computeNormals();
 
 }

+ 3 - 0
examples/geometry/primitives/Sphere.js

@@ -86,6 +86,9 @@ var Sphere = function ( radius, segments_width, segments_height ) {
 			}
 		}
 	}
+
+	this.computeCentroids();
+	this.computeNormals();
 }
 
 Sphere.prototype = new THREE.Geometry();

+ 1 - 1
examples/geometry_birds.html

@@ -26,7 +26,7 @@
 		<div id="container"></div>
 		<div id="info"><a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - birds demo</div>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript" src="../build/Three.js"></script>
 		<script type="text/javascript" src="geometry/Bird.js"></script>

+ 26 - 26
examples/geometry_cube.html

@@ -20,7 +20,7 @@
 		<script type="text/javascript" src="geometry/primitives/Cube.js"></script>
 		<script type="text/javascript" src="geometry/primitives/Plane.js"></script>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 
@@ -79,27 +79,27 @@
 
 				cube = new THREE.Mesh(geometry, new THREE.MeshFaceColorFillMaterial() );
 				cube.position.y = 150;
-				scene.addObject(cube);
+				scene.addObject( cube );
 
 				// Plane
 
-				plane = new THREE.Mesh( new Plane( 200, 200, 4, 4 ), new THREE.MeshColorFillMaterial( 0xe0e0e0 ) );
+				plane = new THREE.Mesh( new Plane( 200, 200 ), new THREE.MeshColorFillMaterial( 0xe0e0e0 ) );
 				plane.rotation.x = -90 * ( Math.PI / 180 );
-				scene.addObject(plane);
+				scene.addObject( plane );
 
 				renderer = new THREE.CanvasRenderer();
-				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 
-				container.appendChild(renderer.domElement);
+				container.appendChild( renderer.domElement );
 
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
 				stats.domElement.style.top = '0px';
-				container.appendChild(stats.domElement);
+				container.appendChild( stats.domElement );
 
-				document.addEventListener('mousedown', onDocumentMouseDown, false);
-				document.addEventListener('touchstart', onDocumentTouchStart, false);
-				document.addEventListener('touchmove', onDocumentTouchMove, false);
+				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
+				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
 			}
 
 			//
@@ -108,9 +108,9 @@
 
 				event.preventDefault();
 
-				document.addEventListener('mousemove', onDocumentMouseMove, false);
-				document.addEventListener('mouseup', onDocumentMouseUp, false);
-				document.addEventListener('mouseout', onDocumentMouseOut, false);
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
+				document.addEventListener( 'mouseout', onDocumentMouseOut, false );
 
 				mouseXOnMouseDown = event.clientX - windowHalfX;
 				targetRotationOnMouseDown = targetRotation;
@@ -120,30 +120,30 @@
 
 				mouseX = event.clientX - windowHalfX;
 
-				targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
+				targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
 			}
 
 			function onDocumentMouseUp( event ) {
 
-				document.removeEventListener('mousemove', onDocumentMouseMove, false);
-				document.removeEventListener('mouseup', onDocumentMouseUp, false);
-				document.removeEventListener('mouseout', onDocumentMouseOut, false);
+				document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+				document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
 			}
 
 			function onDocumentMouseOut( event ) {
 
-				document.removeEventListener('mousemove', onDocumentMouseMove, false);
-				document.removeEventListener('mouseup', onDocumentMouseUp, false);
-				document.removeEventListener('mouseout', onDocumentMouseOut, false);
+				document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+				document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
 			}
 
 			function onDocumentTouchStart( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
+					mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
 					targetRotationOnMouseDown = targetRotation;
 
 				}
@@ -151,12 +151,12 @@
 
 			function onDocumentTouchMove( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseX = event.touches[0].pageX - windowHalfX;
-					targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
 
 				}
 			}
@@ -165,7 +165,7 @@
 
 			function loop() {
 
-				plane.rotation.z = cube.rotation.y += (targetRotation - cube.rotation.y) * 0.05;
+				plane.rotation.z = cube.rotation.y += ( targetRotation - cube.rotation.y ) * 0.05;
 
 				renderer.render(scene, camera);
 				stats.update();

+ 1 - 1
examples/geometry_earth.html

@@ -33,7 +33,7 @@
 		<div id="container"></div> 
 		<div id="info"><a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - earth demo</div>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript" src="../build/Three.js"></script>
 

+ 1 - 1
examples/geometry_terrain.html

@@ -33,7 +33,7 @@
 		<div id="container"><br /><br /><br /><br /><br />Generating...</div> 
 		<div id="info"><a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - terrain demo. <a href="geometry_terrain.html">generate another</a></div> 
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript" src="../build/Three.js"></script>
 

+ 187 - 0
examples/hci_clickcube.html

@@ -0,0 +1,187 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js - geometry - cube</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
+		<style type="text/css">
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+
+		<script type="text/javascript" src="../src/Three.js"></script>
+		<script type="text/javascript" src="../src/core/Color.js"></script>
+		<script type="text/javascript" src="../src/core/Vector2.js"></script>
+		<script type="text/javascript" src="../src/core/Vector3.js"></script>
+		<script type="text/javascript" src="../src/core/Vector4.js"></script>
+		<script type="text/javascript" src="../src/core/Rectangle.js"></script>
+		<script type="text/javascript" src="../src/core/Matrix4.js"></script>
+		<script type="text/javascript" src="../src/core/Vertex.js"></script>
+		<script type="text/javascript" src="../src/core/Face3.js"></script>
+		<script type="text/javascript" src="../src/core/Face4.js"></script>
+		<script type="text/javascript" src="../src/core/UV.js"></script>
+		<script type="text/javascript" src="../src/core/Geometry.js"></script>
+		<script type="text/javascript" src="../src/cameras/Camera.js"></script>
+		<script type="text/javascript" src="../src/objects/Object3D.js"></script>
+		<script type="text/javascript" src="../src/objects/Line.js"></script>
+		<script type="text/javascript" src="../src/objects/Mesh.js"></script>
+		<script type="text/javascript" src="../src/objects/Particle.js"></script>
+		<script type="text/javascript" src="../src/lights/Light.js"></script>
+		<script type="text/javascript" src="../src/lights/AmbientLight.js"></script>
+		<script type="text/javascript" src="../src/lights/DirectionalLight.js"></script>
+		<script type="text/javascript" src="../src/materials/LineColorMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshBitmapUVMappingMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshColorFillMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshColorStrokeMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshFaceColorFillMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshFaceColorStrokeMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/ParticleBitmapMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/ParticleCircleMaterial.js"></script>
+		<script type="text/javascript" src="../src/scenes/Scene.js"></script>
+		<script type="text/javascript" src="../src/renderers/Projector.js"></script>
+		<script type="text/javascript" src="../src/renderers/CanvasRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/SVGRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/WebGLRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableFace3.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableFace4.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableParticle.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableLine.js"></script>
+		<script type="text/javascript" src="../src/hci/ClickResolver.js"></script>
+		<script type="text/javascript" src="../src/hci/SelectableFace3.js"></script>
+		<script type="text/javascript" src="../src/hci/SelectableFace4.js"></script>
+		<script type="text/javascript" src="geometry/primitives/ClickCube.js"></script>
+		<script type="text/javascript" src="geometry/primitives/Plane.js"></script>
+
+		<script type="text/javascript" src="js/Stats.js"></script>
+
+		<script type="text/javascript">
+
+			var SCREEN_WIDTH = window.innerWidth;
+			var SCREEN_HEIGHT = window.innerHeight;
+
+			var container;
+			var stats;
+
+			var camera;
+			var scene;
+			var renderer;
+
+			var cube, plane;
+
+			var targetRotation = 0;
+			var targetRotationOnMouseDown = 0;
+
+			var mouseX = 0;
+			var mouseXOnMouseDown = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+			var clickResolver;
+
+			init();
+			setInterval(loop, 1000/60);
+
+			function init() {
+
+				container = document.createElement('div');
+				document.body.appendChild(container);
+
+				var info = document.createElement('div');
+				info.id = 'msg';
+				info.style.position = 'absolute';
+				info.style.top = '10px';
+				info.style.width = '100%';
+				info.style.textAlign = 'center';
+				info.innerHTML = 'No click detected';
+				container.appendChild(info);
+
+				camera = new THREE.Camera( 70, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
+				camera.position.y = 300;
+				camera.position.z = 500;
+				camera.target.position.y = 150;
+
+				scene = new THREE.Scene();
+				clickResolver = new THREE.ClickResolver( camera, scene );
+
+				// Click Cube
+				var opacity = 0.8;
+
+				geometry = new ClickCube( 200, 200, 200, 
+					function ( s, c, o, f, p ) {
+						f.color.setRGBA( Math.random() * 0.5, Math.random() * 0.5, Math.random() * 0.5, opacity );
+						document.getElementById( "msg" ).innerHTML = "Click detected at " + p; 
+					});
+
+				for (var i = 0; i < geometry.faces.length; i++) {
+					geometry.faces[i].color.setRGBA( Math.random() * 0.5, Math.random() * 0.5, Math.random() * 0.5, opacity );
+				}
+
+				cube = new THREE.Mesh( geometry, new THREE.MeshFaceColorFillMaterial() );
+				cube.position.y = 150;
+				scene.addObject(cube);
+
+				geometry2 = new ClickCube( 100, 100, 100, 
+						function ( s, c, o, f, p ) {
+							f.color.setRGBA( Math.random() * 0.5, Math.random() * 0.5, Math.random() * 0.5, opacity );
+							document.getElementById( "msg" ).innerHTML = "Click detected at " + p; 
+						});
+
+				for (var i = 0; i < geometry2.faces.length; i++) {
+					geometry2.faces[i].color.setRGBA( Math.random() * 0.5, Math.random() * 0.5, Math.random() * 0.5, opacity );
+				}
+				
+				cube2 = new THREE.Mesh( geometry2, new THREE.MeshFaceColorFillMaterial() );
+				cube2.position.y = 150;
+				cube2.position.z = 200;
+				scene.addObject(cube2);
+				
+				// Plane
+				renderer = new THREE.CanvasRenderer();
+				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+				container.appendChild(renderer.domElement);
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild(stats.domElement);
+
+				document.addEventListener('mousedown', onDocumentMouseDown, false);
+			}
+
+			function onDocumentMouseDown( event ) {
+
+				event.preventDefault();
+
+				document.getElementById("msg").innerHTML = ""; 
+				
+				clickResolver.findIntersectInScene(
+						event.clientX/window.innerWidth,
+						event.clientY/window.innerHeight);
+					
+			}
+
+			var radius = 600;
+			var theta = 0;
+			
+			function loop() {
+
+				theta += 1;
+				camera.position.x = radius * Math.sin( theta * Math.PI / 360 );
+				camera.position.z = radius * Math.cos( theta * Math.PI / 360 );
+
+				renderer.render(scene, camera);
+				stats.update();
+			}
+
+		</script>
+
+	</body>
+</html>

Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
examples/js/Stats.js


+ 1 - 1
examples/materials_video.html

@@ -15,7 +15,7 @@
 	</head>
 	<body>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 		<script type="text/javascript" src="../build/Three.js"></script>
 
 		<script type="text/javascript" src="geometry/primitives/Plane.js"></script>

+ 1 - 1
examples/particles_floor.html

@@ -19,7 +19,7 @@
 	<body>
 
 		<script type="text/javascript" src="../build/Three.js"></script>
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 

+ 20 - 20
examples/particles_random.html

@@ -20,7 +20,7 @@
 
 		<script type="text/javascript" src="../build/Three.js"></script>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 
@@ -44,7 +44,7 @@
 
 
 			init();
-			setInterval(loop, 1000 / 60);
+			setInterval( loop, 1000 / 60 );
 
 			function init() {
 
@@ -66,48 +66,48 @@
 					particle.position.y = Math.random() * 2000 - 1000;
 					particle.position.z = Math.random() * 2000 - 1000;
 					particle.scale.x = particle.scale.y = Math.random() * 10 + 5;
-					scene.add(particle);
+					scene.add( particle );
 				}
 
-				container.appendChild(renderer.domElement);
+				container.appendChild( renderer.domElement );
 
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
 				stats.domElement.style.top = '0px';
-				container.appendChild(stats.domElement);
+				container.appendChild( stats.domElement );
 
-				document.addEventListener('mousemove', onDocumentMouseMove, false);
-				document.addEventListener('touchstart', onDocumentTouchStart, false);
-				document.addEventListener('touchmove', onDocumentTouchMove, false);
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
 			}
 
 			//
 
-			function onDocumentMouseMove(event) {
+			function onDocumentMouseMove( event ) {
 
 				mouseX = event.clientX - windowHalfX;
 				mouseY = event.clientY - windowHalfY;
 			}
 
-			function onDocumentTouchStart(event) {
+			function onDocumentTouchStart( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseX = event.touches[0].pageX - windowHalfX;
-					mouseY = event.touches[0].pageY - windowHalfY;
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					mouseY = event.touches[ 0 ].pageY - windowHalfY;
 				}
 			}
 
-			function onDocumentTouchMove(event) {
+			function onDocumentTouchMove( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseX = event.touches[0].pageX - windowHalfX;
-					mouseY = event.touches[0].pageY - windowHalfY;
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					mouseY = event.touches[ 0 ].pageY - windowHalfY;
 				}
 			}
 
@@ -115,10 +115,10 @@
 
 			function loop() {
 
-				camera.position.x += (mouseX - camera.position.x) * .05;
-				camera.position.y += (-mouseY - camera.position.y) * .05;
+				camera.position.x += ( mouseX - camera.position.x ) * 0.05;
+				camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
 
-				renderer.render(scene, camera);
+				renderer.render( scene, camera );
 
 				stats.update();
 			}

+ 32 - 32
examples/particles_waves.html

@@ -18,7 +18,7 @@
 	</head>
 	<body>
 		<script type="text/javascript" src="../build/Three.js"></script>
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 
@@ -50,8 +50,8 @@
 
 			function init() {
 
-				container = document.createElement('div');
-				document.body.appendChild(container);
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
 
 				camera = new THREE.Camera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
 				camera.position.z = 1000;
@@ -59,67 +59,67 @@
 				scene = new THREE.Scene();
 
 				renderer = new THREE.CanvasRenderer();
-				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 
 				particles = new Array();
 
 				var i = 0;
-				var material = new THREE.ParticleCircleMaterial(0xffffff, 1);
+				var material = new THREE.ParticleCircleMaterial( 0xffffff, 1 );
 
-				for (var ix = 0; ix < AMOUNTX; ix++) {
+				for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
 
-					for(var iy = 0; iy < AMOUNTY; iy++) {
+					for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
 
-						particle = particles[i++] = new THREE.Particle( material );
-						particle.position.x = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2);
-						particle.position.z = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2);
+						particle = particles[ i ++ ] = new THREE.Particle( material );
+						particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 );
+						particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 );
 						scene.add( particle );
 					}
 				}
 
 				count = 0;
 
-				container.appendChild(renderer.domElement);
+				container.appendChild( renderer.domElement );
 
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
 				stats.domElement.style.top = '0px';
-				container.appendChild(stats.domElement);
+				container.appendChild( stats.domElement );
 
-				document.addEventListener('mousemove', onDocumentMouseMove, false);
-				document.addEventListener('touchstart', onDocumentTouchStart, false);
-				document.addEventListener('touchmove', onDocumentTouchMove, false);
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
 			}
 
 			//
 
-			function onDocumentMouseMove(event) {
+			function onDocumentMouseMove( event ) {
 
 				mouseX = event.clientX - windowHalfX;
 				mouseY = event.clientY - windowHalfY;
 
 			}
 
-			function onDocumentTouchStart(event) {
+			function onDocumentTouchStart( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseX = event.touches[0].pageX - windowHalfX;
-					mouseY = event.touches[0].pageY - windowHalfY;
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					mouseY = event.touches[ 0 ].pageY - windowHalfY;
 
 				}
 			}
 
-			function onDocumentTouchMove(event) {
+			function onDocumentTouchMove( event ) {
 
-				if(event.touches.length == 1) {
+				if ( event.touches.length == 1 ) {
 
 					event.preventDefault();
 
-					mouseX = event.touches[0].pageX - windowHalfX;
-					mouseY = event.touches[0].pageY - windowHalfY;
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					mouseY = event.touches[ 0 ].pageY - windowHalfY;
 
 				}
 			}
@@ -128,23 +128,23 @@
 
 			function loop() {
 
-				camera.position.x += (mouseX - camera.position.x) * .05;
-				camera.position.y += (-mouseY - camera.position.y) * .05;
+				camera.position.x += ( mouseX - camera.position.x ) * .05;
+				camera.position.y += ( - mouseY - camera.position.y ) * .05;
 
 				var i = 0;
 
-				for (var ix = 0; ix < AMOUNTX; ix++) {
+				for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
 
-					for(var iy = 0; iy < AMOUNTY; iy++) {
+					for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
 
-						particle = particles[i++];
-						particle.position.y = (Math.sin((ix + count) * .3) * 50) + (Math.sin((iy + count) * .5) * 50);
-						particle.scale.x = particle.scale.y = (Math.sin((ix + count) * .3) + 1) * 2 + (Math.sin((iy + count) * .5) + 1) * 2;
+						particle = particles[ i++ ];
+						particle.position.y = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) + ( Math.sin( ( iy + count ) * 0.5 ) * 50 );
+						particle.scale.x = particle.scale.y = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 2 + ( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 2;
 
 					}
 				}
 
-				renderer.render(scene, camera);
+				renderer.render( scene, camera );
 
 				stats.update();
 

+ 21 - 13
examples/test.html

@@ -28,13 +28,14 @@
 		<script type="text/javascript" src="../src/core/UV.js"></script>
 		<script type="text/javascript" src="../src/core/Geometry.js"></script>
 		<script type="text/javascript" src="../src/cameras/Camera.js"></script>
+		<script type="text/javascript" src="../src/lights/Light.js"></script>
+		<script type="text/javascript" src="../src/lights/AmbientLight.js"></script>
+		<script type="text/javascript" src="../src/lights/DirectionalLight.js"></script>
+		<script type="text/javascript" src="../src/lights/PointLight.js"></script>
 		<script type="text/javascript" src="../src/objects/Object3D.js"></script>
 		<script type="text/javascript" src="../src/objects/Mesh.js"></script>
 		<script type="text/javascript" src="../src/objects/Particle.js"></script>
 		<script type="text/javascript" src="../src/objects/Line.js"></script>
-    <script type="text/javascript" src="../src/lights/Light.js"></script>
-    <script type="text/javascript" src="../src/lights/AmbientLight.js"></script>
-    <script type="text/javascript" src="../src/lights/DirectionalLight.js"></script>
 		<script type="text/javascript" src="../src/materials/LineColorMaterial.js"></script>
 		<script type="text/javascript" src="../src/materials/MeshBitmapUVMappingMaterial.js"></script>
 		<script type="text/javascript" src="../src/materials/MeshColorFillMaterial.js"></script>
@@ -44,7 +45,7 @@
 		<script type="text/javascript" src="../src/materials/ParticleCircleMaterial.js"></script>
 		<script type="text/javascript" src="../src/materials/ParticleBitmapMaterial.js"></script>
 		<script type="text/javascript" src="../src/scenes/Scene.js"></script>
-		<script type="text/javascript" src="../src/renderers/Renderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/Projector.js"></script>
 		<script type="text/javascript" src="../src/renderers/CanvasRenderer.js"></script>
 		<script type="text/javascript" src="../src/renderers/SVGRenderer.js"></script>
 		<script type="text/javascript" src="../src/renderers/WebGLRenderer.js"></script>
@@ -58,7 +59,7 @@
 		<script type="text/javascript" src="geometry/primitives/Plane.js"></script>
 		<script type="text/javascript" src="geometry/primitives/Cylinder.js"></script>
 
-		<script type="text/javascript" src="http://github.com/mrdoob/stats.js/raw/master/build/Stats.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
 
 		<script type="text/javascript">
 
@@ -73,7 +74,7 @@
 			var scene;
 			var canvasRenderer, svgRenderer, webglRenderer;
 
-			var mesh;
+			var mesh, qrcode;
 
 			var mouseX = 0;
 			var mouseY = 0;
@@ -103,7 +104,7 @@
 
 				// QRCODE
 
-				mesh = new THREE.Mesh(new Qrcode(), new THREE.MeshFaceColorFillMaterial());
+				qrcode = mesh = new THREE.Mesh(new Qrcode(), new THREE.MeshFaceColorFillMaterial());
 				mesh.scale.x = mesh.scale.y = mesh.scale.z = 2;
 				mesh.updateMatrix();
 				scene.add(mesh);
@@ -167,6 +168,8 @@
 					geometry.faces.push( face );
 				}
 
+				geometry.computeNormals();
+
 				mesh = new THREE.Mesh( geometry, new THREE.MeshFaceColorFillMaterial() );
 				mesh.doubleSided = true;
 				mesh.scale.x = mesh.scale.y = mesh.scale.z = 2;
@@ -186,12 +189,12 @@
 				}
 
 				// LIGHTS
-				
-				var ambient = new THREE.AmbientLight( new THREE.Color( Math.random() * 0xffffff ) );
-        scene.addLight(ambient);
-				var directional = new THREE.DirectionalLight( new THREE.Color( Math.random() * 0xffffff ), 
-						new THREE.Vector3( 600, 0, 0 ) );
-        scene.addLight(directional);
+
+				var ambient = new THREE.AmbientLight( 0x80ffff );
+				scene.addLight( ambient );
+
+				var directional = new THREE.DirectionalLight( 0xffff00 );
+				scene.addLight( directional );
 
 				canvasRenderer = new THREE.CanvasRenderer();
 				canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
@@ -229,6 +232,11 @@
 				mesh.rotation.y += 0.01;
 				mesh.updateMatrix();
 
+				/*
+				qrcode.rotation.x += 0.01;
+				qrcode.rotation.z += 0.02;
+				*/
+
 				canvasRenderer.render( scene, camera );
 				svgRenderer.render( scene, camera );
 				webglRenderer.render( scene, camera );

+ 2 - 0
src/cameras/Camera.js

@@ -4,6 +4,8 @@
 
 THREE.Camera = function ( fov, aspect, near, far ) {
 
+	this.fov = fov;
+	this.aspect = aspect;
 	this.position = new THREE.Vector3( 0, 0, 0 );
 	this.target = { position: new THREE.Vector3( 0, 0, 0 ) };
 

+ 50 - 9
src/core/Color.js

@@ -4,29 +4,70 @@
 
 THREE.Color = function ( hex ) {
 
+	/*
+	this.r; this.g; this.b; this.a;
+	this.hex;
+	this.__styleString;
+	*/
+
+	this.autoUpdate = true;
 	this.setHex( hex );
 
 }
 
 THREE.Color.prototype = {
 
+	setRGBA: function ( r, g, b, a ) {
+
+		this.r = r;
+		this.g = g;
+		this.b = b;
+		this.a = a;
+
+		if ( this.autoUpdate ) {
+
+			this.updateHex();
+			this.updateStyleString();
+
+		}
+
+	},
+
 	setHex: function ( hex ) {
 
 		this.hex = hex;
-		this.updateRGBA();
-		this.updateStyleString();
+
+		if ( this.autoUpdate ) {
+
+			this.updateRGBA();
+			this.updateStyleString();
+
+		}
 
 	},
 
-	setRGBA: function ( r, g, b, a ) {
+	copyRGB: function ( color ) {
 
-		this.r = r;
-		this.g = g;
-		this.b = b;
-		this.a = a;
+		this.r = color.r;
+		this.g = color.g;
+		this.b = color.b;
+
+	},
+
+	copyRGBA: function ( color ) {
+
+		this.r = color.r;
+		this.g = color.g;
+		this.b = color.b;
+		this.a = color.a;
+
+	},
+
+	multiplySelfRGB: function ( color ) {
 
-		this.updateHex();
-		this.updateStyleString();
+		this.r *= color.r;
+		this.g *= color.g;
+		this.b *= color.b;
 
 	},
 

+ 10 - 2
src/core/Face3.js

@@ -8,15 +8,23 @@ THREE.Face3 = function ( a, b, c, normal, color ) {
 	this.b = b;
 	this.c = c;
 
+	this.centroid = new THREE.Vector3();
 	this.normal = normal || new THREE.Vector3();
-	this.screen = new THREE.Vector3();
 
-	this.color = color || new THREE.Color( 0x000000 );
+	this.color = color || new THREE.Color( 0xff000000 );
 
 };
 
 THREE.Face3.prototype = {
 
+	// TODO: Dupe? (Geometry/computeCentroid)
+
+	getCenter : function(){
+
+		return this.a.clone().addSelf( this.b ).addSelf( this.c ).divideScalar( 3 );
+
+	},
+
 	toString: function () {
 
 		return 'THREE.Face3 ( ' + this.a + ', ' + this.b + ', ' + this.c + ' )';

+ 9 - 8
src/core/Face4.js

@@ -9,26 +9,27 @@ THREE.Face4 = function ( a, b, c, d, normal, color ) {
 	this.c = c;
 	this.d = d;
 
+	this.centroid = new THREE.Vector3();
 	this.normal = normal || new THREE.Vector3();
-	this.screen = new THREE.Vector3();
 
-	this.color = color || new THREE.Color( 0x000000 );
+	this.color = color || new THREE.Color( 0xff000000 );
 
 };
 
 THREE.Face4.prototype = {
 
-	toString: function () {
+	// TODO: Dupe? (Geometry/computeCentroid)
 
-		return 'THREE.Face4 ( ' + this.a + ', ' + this.b + ', ' + this.c + ' ' + this.d + ' )';
+	getCenter : function(){
+
+		return this.a.clone().addSelf( this.b ).addSelf( this.c ).addSelf( this.d ).divideScalar( 4 );
 
 	},
-	
-	getCenter : function(){
 
-	  return this.a.clone().addSelf(this.b).addSelf(this.c).addSelf(this.d).divideScalar(4);
+	toString: function () {
+
+		return 'THREE.Face4 ( ' + this.a + ', ' + this.b + ', ' + this.c + ' ' + this.d + ' )';
 
 	}
 
-  
 }

+ 40 - 10
src/core/Geometry.js

@@ -13,24 +13,54 @@ THREE.Geometry = function () {
 
 THREE.Geometry.prototype = {
 
+	computeCentroids: function () {
+
+		var f, fl, face;
+
+		for ( f = 0, fl = this.faces.length; f < fl; f++ ) {
+
+			face = this.faces[ f ];
+			face.centroid.set( 0, 0, 0 );
+
+			if ( face instanceof THREE.Face3 ) {
+
+				face.centroid.addSelf( this.vertices[ face.a ].position );
+				face.centroid.addSelf( this.vertices[ face.b ].position );
+				face.centroid.addSelf( this.vertices[ face.c ].position );
+				face.centroid.divideScalar( 3 );
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				face.centroid.addSelf( this.vertices[ face.a ].position );
+				face.centroid.addSelf( this.vertices[ face.b ].position );
+				face.centroid.addSelf( this.vertices[ face.c ].position );
+				face.centroid.addSelf( this.vertices[ face.d ].position );
+				face.centroid.divideScalar( 4 );
+
+			}
+
+		}
+
+	},
+
 	computeNormals: function () {
 
-		var v, f, vA, vB, vC, cb, ab;
+		var v, vl, vertex, f, fl, face, vA, vB, vC, cb = new THREE.Vector3(), ab = new THREE.Vector3();
 
-		for ( v = 0; v < this.vertices.length; v++ ) {
+		for ( v = 0, vl = this.vertices.length; v < vl; v++ ) {
 
-			this.vertices[ v ].normal.set( 0, 0, 0 );
+			vertex = this.vertices[ v ];
+			vertex.normal.set( 0, 0, 0 );
 
 		}
 
-		for ( f = 0; f < this.faces.length; f++ ) {
+		for ( f = 0, fl = this.faces.length; f < fl; f++ ) {
 
-			vA = this.vertices[ this.faces[ f ].a ];
-			vB = this.vertices[ this.faces[ f ].b ];
-			vC = this.vertices[ this.faces[ f ].c ];
+			face = this.faces[ f ];
 
-			cb = new THREE.Vector3();
-			ab = new THREE.Vector3();
+			vA = this.vertices[ face.a ];
+			vB = this.vertices[ face.b ];
+			vC = this.vertices[ face.c ];
 
 			cb.sub( vC.position, vB.position );
 			ab.sub( vA.position, vB.position );
@@ -42,7 +72,7 @@ THREE.Geometry.prototype = {
 
 			}
 
-			this.faces[ f ].normal = cb;
+			face.normal.copy( cb );
 
 		}
 

+ 19 - 8
src/core/Matrix4.js

@@ -30,6 +30,15 @@ THREE.Matrix4.prototype = {
 
 	},
 
+	copy: function ( m ) {
+
+		this.n11 = m.n11; this.n12 = m.n12; this.n13 = m.n13; this.n14 = m.n14;
+		this.n21 = m.n21; this.n22 = m.n22; this.n23 = m.n23; this.n24 = m.n24;
+		this.n31 = m.n31; this.n32 = m.n32; this.n33 = m.n33; this.n34 = m.n34;
+		this.n41 = m.n41; this.n42 = m.n42; this.n43 = m.n43; this.n44 = m.n44;
+
+	},
+
 	lookAt: function ( eye, center, up ) {
 
 		var x = this._x, y = this._y, z = this._z;
@@ -71,6 +80,8 @@ THREE.Matrix4.prototype = {
 
 		}
 
+		return v;
+
 	},
 
 	crossVector: function ( a ) {
@@ -220,19 +231,19 @@ THREE.Matrix4.prototype = {
 
 	flatten: function() {
 
-	  return [this.n11, this.n21, this.n31, this.n41,
-	      this.n12, this.n22, this.n32, this.n42,
-	      this.n13, this.n23, this.n33, this.n43,
-	      this.n14, this.n24, this.n34, this.n44];
+		return [this.n11, this.n21, this.n31, this.n41,
+			this.n12, this.n22, this.n32, this.n42,
+			this.n13, this.n23, this.n33, this.n43,
+			this.n14, this.n24, this.n34, this.n44];
 
 	},
 
 	toString: function() {
 
-		return "| " + this.n11 + " " + this.n12 + " " + this.n13 + " " + this.n14 + " |\n" +
-		"| " + this.n21 + " " + this.n22 + " " + this.n23 + " " + this.n24 + " |\n" +
-		"| " + this.n31 + " " + this.n32 + " " + this.n33 + " " + this.n34 + " |\n" +
-		"| " + this.n41 + " " + this.n42 + " " + this.n43 + " " + this.n44 + " |";
+		return  "| " + this.n11 + " " + this.n12 + " " + this.n13 + " " + this.n14 + " |\n" +
+			"| " + this.n21 + " " + this.n22 + " " + this.n23 + " " + this.n24 + " |\n" +
+			"| " + this.n31 + " " + this.n32 + " " + this.n33 + " " + this.n34 + " |\n" +
+			"| " + this.n41 + " " + this.n42 + " " + this.n43 + " " + this.n44 + " |";
 
 	}
 

+ 13 - 1
src/core/Vector2.js

@@ -17,6 +17,8 @@ THREE.Vector2.prototype = {
 		this.x = x;
 		this.y = y;
 
+		return this;
+
 	},
 
 	copy: function ( v ) {
@@ -24,13 +26,15 @@ THREE.Vector2.prototype = {
 		this.x = v.x;
 		this.y = v.y;
 
+		return this;
+
 	},
 
 	addSelf: function ( v ) {
 
 		this.x += v.x;
 		this.y += v.y;
-		
+
 		return this;
 
 	},
@@ -40,6 +44,8 @@ THREE.Vector2.prototype = {
 		this.x = v1.x + v2.x;
 		this.y = v1.y + v2.y;
 
+		return this;
+
 	},
 
 	subSelf: function ( v ) {
@@ -56,6 +62,8 @@ THREE.Vector2.prototype = {
 		this.x = v1.x - v2.x;
 		this.y = v1.y - v2.y;
 
+		return this;
+
 	},
 
 	multiplyScalar: function ( s ) {
@@ -71,6 +79,8 @@ THREE.Vector2.prototype = {
 
 		this.multiplyScalar( 1 / this.length() );
 
+		return this;
+
 	},
 
 	length: function () {
@@ -90,6 +100,8 @@ THREE.Vector2.prototype = {
 		this.x = - this.x;
 		this.y = - this.y;
 
+		return this;
+
 	},
 
 	clone: function () {

+ 18 - 0
src/core/Vector3.js

@@ -20,6 +20,8 @@ THREE.Vector3.prototype = {
 		this.y = y;
 		this.z = z;
 
+		return this;
+
 	},
 
 	copy: function ( v ) {
@@ -28,6 +30,8 @@ THREE.Vector3.prototype = {
 		this.y = v.y;
 		this.z = v.z;
 
+		return this;
+
 	},
 
 	add: function( v1, v2 ) {
@@ -36,6 +40,8 @@ THREE.Vector3.prototype = {
 		this.y = v1.y + v2.y;
 		this.z = v1.z + v2.z;
 
+		return this;
+
 	},
 
 	addSelf: function ( v ) {
@@ -64,6 +70,8 @@ THREE.Vector3.prototype = {
 		this.y = v1.y - v2.y;
 		this.z = v1.z - v2.z;
 
+		return this;
+
 	},
 
 	subSelf: function ( v ) {
@@ -82,6 +90,8 @@ THREE.Vector3.prototype = {
 		this.y = v1.z * v2.x - v1.x * v2.z;
 		this.z = v1.x * v2.y - v1.y * v2.x;
 
+		return this;
+
 	},
 
 	crossSelf: function ( v ) {
@@ -179,6 +189,14 @@ THREE.Vector3.prototype = {
 
 		}
 
+		return this;
+
+	},
+
+	setLength: function( len ) {
+
+		return this.normalize().multiplyScalar( len );
+
 	},
 
 	isZero: function () {

+ 8 - 0
src/core/Vector4.js

@@ -20,6 +20,8 @@ THREE.Vector4.prototype = {
 		this.y = y;
 		this.z = z;
 		this.w = w;
+		
+		return this;
 
 	},
 
@@ -30,6 +32,8 @@ THREE.Vector4.prototype = {
 		this.z = v.z;
 		this.w = v.w;
 
+		return this;
+
 	},
 
 	add: function ( v1, v2 ) {
@@ -39,6 +43,8 @@ THREE.Vector4.prototype = {
 		this.z = v1.z + v2.z;
 		this.w = v1.w + v2.w;
 
+		return this;
+
 	},
 
 	addSelf: function ( v ) {
@@ -59,6 +65,8 @@ THREE.Vector4.prototype = {
 		this.z = v1.z - v2.z;
 		this.w = v1.w - v2.w;
 
+		return this;
+
 	},
 
 	subSelf: function ( v ) {

+ 5 - 1
src/core/Vertex.js

@@ -5,8 +5,12 @@
 THREE.Vertex = function ( position, normal ) {
 
 	this.position = position || new THREE.Vector3();
+	this.positionWorld = new THREE.Vector3();
+	this.positionScreen = new THREE.Vector3();
+
 	this.normal = normal || new THREE.Vector3();
-	this.screen = new THREE.Vector3();
+	this.normalWorld = new THREE.Vector3();
+	this.normalScreen = new THREE.Vector3();
 
 	this.__visible = true;
 

+ 202 - 0
src/hci/ClickResolver.js

@@ -0,0 +1,202 @@
+
+THREE.ClickResolver = function( camera, scene ) {
+
+	this.camera = camera;
+	this.scene  = scene;
+	this._debug = false;
+	
+};
+
+THREE.ClickResolver.prototype = {
+	
+	findIntersectInScene : function ( xPercent, yPercent ) {
+	
+		var objects = this.scene.objects;
+		var intersects = [];
+		
+		var mouseRayStart = this.translateScreenCoordsToZIndex( xPercent, yPercent, 300 );
+		var mouseRayEnd =   this.translateScreenCoordsToZIndex( xPercent, yPercent, 800 );
+		
+		var mouseRayDir = new THREE.Vector3().sub( mouseRayEnd, mouseRayStart );
+		
+		var closestIntersect = null;
+		
+		for ( var i = 0; i < objects.length; i++ ) {
+			
+			var o = objects[i];
+			var intersect = this.getIntersectingFaces( this.scene, camera, o, mouseRayStart, mouseRayDir );
+			
+			if ( intersect.face != null &&
+					(closestIntersect == null ||
+					 closestIntersect.distance > intersect.distance)
+					 ) {
+				
+				closestIntersect = intersect;
+			}
+		}
+		
+		if ( closestIntersect != null && closestIntersect.face.onSelect ) {
+			
+			closestIntersect.face.onSelect( scene, camera, o, closestIntersect.face, closestIntersect.point );
+		}
+	},
+		
+	
+	translateScreenCoordsToZIndex : function ( xPercent, yPercent, targetZIndex ) {
+
+		var maxVisibleXatZIndex, maxVisibleYatZIndex;
+		var rayToZIndex   = new THREE.Vector3();
+		var left          = new THREE.Vector3();
+		var up            = new THREE.Vector3();
+		var coordAtZIndex = new THREE.Vector3();
+
+		rayToZIndex.sub( this.camera.target.position, this.camera.position ).setLength( targetZIndex );
+		
+		maxVisibleYatZIndex = rayToZIndex.length() * Math.tan( this.camera.fov * Math.PI / 360 );
+		maxVisibleXatZIndex = maxVisibleYatZIndex  * this.camera.aspect;
+		
+		left.cross( this.camera.up, rayToZIndex );
+		up  .cross( rayToZIndex, left );
+		
+		return coordAtZIndex.add( this.camera.position, rayToZIndex ).
+			addSelf( left.setLength( maxVisibleXatZIndex * ( 1 - 2 * xPercent ))).
+			addSelf( up  .setLength( maxVisibleYatZIndex * ( 1 - 2 * yPercent )));
+	},
+	
+	
+	logPoint: function( scene, v, hex ) {
+		
+		if ( this._debug ) {
+			
+			var vg = new THREE.Geometry();
+			
+			vg.vertices[ 0 ] = new THREE.Vertex( v );
+			vg.vertices[ 1 ] = new THREE.Vertex( v );
+			
+			scene.addObject( new THREE.Line( vg, new THREE.LineColorMaterial( hex, 1, 10 )));
+		}
+	},
+	
+	
+	logLine: function( scene, s, e, hex ) {
+
+		if ( this._debug ) {
+
+			this.logPoint( scene, s.clone(), 0x000000 );
+			
+			var lg = new THREE.Geometry();
+			
+			lg.vertices[0] = new THREE.Vertex( s.clone() );
+			lg.vertices[1] = new THREE.Vertex( e.clone() );
+			
+			scene.addObject(new THREE.Line( lg, new THREE.LineColorMaterial( hex, 1, 4 ) ));
+		}
+
+	},
+	
+	
+	getIntersectingFaces: function( scene, camera, object3d, linePoint, lineDir ) {
+		
+		var intersect = {
+			face     : null,
+			point    : null,
+			distance : Number.MAX_VALUE
+		};
+		
+		var geo    = object3d.geometry;
+		var matrix = object3d.matrix;
+		
+		for ( f = 0; f < geo.faces.length; f++ ) {
+			
+			var face = geo.faces[ f ];
+			
+			if ( !face.selectable ) continue;
+			
+			var a = matrix.transform( geo.vertices[ face.a ].position.clone() );
+			var b = matrix.transform( geo.vertices[ face.b ].position.clone() );
+			var c = matrix.transform( geo.vertices[ face.c ].position.clone() );
+			var d = null;
+			
+			if ( face.d ) {
+				
+				d = matrix.transform( geo.vertices[ face.d ].position.clone() );
+			}
+			
+			var lineStart = linePoint.clone();
+			var lineDirection = lineDir.clone();
+			var dot = face.normal.dot( lineDirection );
+			
+			if ( this._debug ) {
+
+				this.logLine( scene, a, new THREE.Vector3().add( a, new THREE.Vector3().addSelf( face.normal ).multiplyScalar( 100 )), 0x0000FF );
+				this.logLine( scene, lineStart, lineStart.clone().addSelf(lineDirection), 0x55FF88 );
+				this.logPoint( scene, a, 0xFF0000 ); // r
+				this.logPoint( scene, b, 0x00FF00 ); // g
+				this.logPoint( scene, c, 0x0000FF ); // b
+				this.logPoint( scene, d, 0xFFFF00 ); // y
+			}
+				
+			if ( Math.abs(dot) > .0001 ) {
+				
+				var s = face.normal.dot( new THREE.Vector3().sub( a, lineStart ) ) / dot;
+				var planeIntersect = lineStart.addSelf( lineDirection.multiplyScalar( s ) );
+				
+				if ( this._debug ) this.logPoint( scene, planeIntersect, 0xFFCCAA );
+				
+				if ( d == null ) {
+					
+					var ab = isInsideBoundary( planeIntersect, a, b, c );
+					var bc = isInsideBoundary( planeIntersect, b, c, a );
+					var ca = isInsideBoundary( planeIntersect, c, a, b );
+					
+					if ( ab && bc && ca ) {
+						
+						if ( this._debug ) this.logPoint( scene, planeIntersect, 0xFF0000 );
+						logIntersect( planeIntersect, face );
+						
+					}
+				} else {
+					
+					var ab = isInsideBoundary( planeIntersect, a, b, c );
+					var bc = isInsideBoundary( planeIntersect, b, c, d );
+					var cd = isInsideBoundary( planeIntersect, c, d, a );
+					var da = isInsideBoundary( planeIntersect, d, a, b );
+					
+					if ( ab && bc && cd && da ) {
+						
+						if ( this._debug ) this.logPoint( scene, planeIntersect, 0xFF0000 );
+						logIntersect( planeIntersect, face );
+						
+					}
+				}
+			}
+		}
+		
+		function logIntersect( planeIntersect, face ) {
+			
+			var distance = camera.position.distanceTo( planeIntersect );
+			
+			if ( distance < intersect.distance ) {
+				
+				intersect.distance = distance;
+				intersect.face = face;
+				intersect.point = planeIntersect;
+			}
+		}
+		
+		function isInsideBoundary( pointOnPlaneToCheck, pointInside, boundaryPointA, boundaryPointB ) {
+		
+			var toB = boundaryPointB.clone().subSelf( boundaryPointA );
+			var toI = pointInside.clone().subSelf( boundaryPointA );
+			var pointMid = toB.setLength( toI.dot( toB ) ).addSelf( boundaryPointA );
+			var pointMirror = pointMid.subSelf( pointInside ).multiplyScalar( 2 ).addSelf( pointInside );
+			
+			return pointOnPlaneToCheck.distanceToSquared( pointInside ) <
+				   pointOnPlaneToCheck.distanceToSquared( pointMirror );
+		};
+		
+		return intersect;
+	}
+
+
+};

+ 10 - 0
src/hci/SelectableFace3.js

@@ -0,0 +1,10 @@
+THREE.SelectableFace3 =  function ( a, b, c, normal, color, onSelect) {
+	
+	THREE.Face3.call( this, a, b, c, normal, color );
+	
+	this.selectable = true;
+	this.onSelect = onSelect;
+};
+
+THREE.SelectableFace3.prototype = new THREE.Face3();
+THREE.SelectableFace3.prototype.constructor = THREE.SelectableFace3;

+ 11 - 0
src/hci/SelectableFace4.js

@@ -0,0 +1,11 @@
+var SelectableFace4 = function ( a, b, c, d, onSelect, normal, color) {
+	
+	THREE.Face4.call( this, a, b, c, d, normal, color );
+	
+	this.selectable = true;
+	this.onSelect = onSelect;
+};
+
+SelectableFace4.prototype = new THREE.Face4();
+SelectableFace4.prototype.constructor = SelectableFace4;  
+THREE.SelectableFace4 = SelectableFace4;

+ 4 - 4
src/lights/AmbientLight.js

@@ -1,8 +1,8 @@
-THREE.AmbientLight = function(color) {
-  
-  THREE.Light.call(this, color);
+THREE.AmbientLight = function ( hex ) {
+
+	THREE.Light.call( this, hex );
 
 };
 
 THREE.AmbientLight.prototype = new THREE.Light();
-THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; 
+THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; 

+ 7 - 8
src/lights/DirectionalLight.js

@@ -1,12 +1,11 @@
-THREE.DirectionalLight = function(color, direction) {
-  
-  THREE.Light.call(this, color);
-  
-  this.direction = direction || new Vector3(1, 1, 1);
-  
-  this.direction.normalize();
+THREE.DirectionalLight = function ( hex, intensity ) {
+
+	THREE.Light.call( this, hex );
+
+	this.position = new THREE.Vector3( 0, 1, 0 );
+	this.intensity = intensity || 1;
 
 };
 
 THREE.DirectionalLight.prototype = new THREE.Light();
-THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; 
+THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; 

+ 3 - 3
src/lights/Light.js

@@ -1,5 +1,5 @@
-THREE.Light = function(color) {
+THREE.Light = function ( hex ) {
 
-  this.color = color;
+	this.color = new THREE.Color( 0xff << 24 | hex );
 
-};
+};

+ 11 - 0
src/lights/PointLight.js

@@ -0,0 +1,11 @@
+THREE.PointLight = function ( hex, intensity ) {
+
+	THREE.Light.call( this, hex );
+
+	this.position = new THREE.Vector3( 0, 0, 0 );
+	this.intensity = intensity || 1;
+
+};
+
+THREE.DirectionalLight.prototype = new THREE.Light();
+THREE.DirectionalLight.prototype.constructor = THREE.PointLight; 

+ 14 - 6
src/objects/Object3D.js

@@ -9,19 +9,27 @@ THREE.Object3D = function ( material ) {
 	this.scale = new THREE.Vector3( 1, 1, 1 );
 
 	this.matrix = new THREE.Matrix4();
+	this.matrixTranslation = new THREE.Matrix4();
+	this.matrixRotation = new THREE.Matrix4();
+	this.matrixScale = new THREE.Matrix4();
+
 	this.screen = new THREE.Vector3();
 
 	this.autoUpdateMatrix = true;
 
 	this.updateMatrix = function () {
 
-		this.matrix.identity();
+		this.matrixPosition = THREE.Matrix4.translationMatrix( this.position.x, this.position.y, this.position.z );
+
+		this.matrixRotation = THREE.Matrix4.rotationXMatrix( this.rotation.x );
+		this.matrixRotation.multiplySelf( THREE.Matrix4.rotationYMatrix( this.rotation.y ) );
+		this.matrixRotation.multiplySelf( THREE.Matrix4.rotationZMatrix( this.rotation.z ) );
+
+		this.matrixScale = THREE.Matrix4.scaleMatrix( this.scale.x, this.scale.y, this.scale.z );
 
-		this.matrix.multiplySelf( THREE.Matrix4.translationMatrix( this.position.x, this.position.y, this.position.z ) );
-		this.matrix.multiplySelf( THREE.Matrix4.rotationXMatrix( this.rotation.x ) );
-		this.matrix.multiplySelf( THREE.Matrix4.rotationYMatrix( this.rotation.y ) );
-		this.matrix.multiplySelf( THREE.Matrix4.rotationZMatrix( this.rotation.z ) );
-		this.matrix.multiplySelf( THREE.Matrix4.scaleMatrix( this.scale.x, this.scale.y, this.scale.z ) );
+		this.matrix.copy( this.matrixPosition );
+		this.matrix.multiplySelf( this.matrixRotation );
+		this.matrix.multiplySelf( this.matrixScale );
 
 	};
 

+ 279 - 26
src/renderers/CanvasRenderer.js

@@ -4,17 +4,24 @@
 
 THREE.CanvasRenderer = function () {
 
-	THREE.Renderer.call( this );
+	var _renderList = null,
+	_projector = new THREE.Projector(),
 
-	var _canvas = document.createElement( 'canvas' ),
+	_canvas = document.createElement( 'canvas' ),
 	_context = _canvas.getContext( '2d' ),
 	_width, _height, _widthHalf, _heightHalf,
 	_clipRect = new THREE.Rectangle(),
 	_clearRect = new THREE.Rectangle(),
 	_bboxRect = new THREE.Rectangle(),
-	_vector2 = new THREE.Vector2(),
 
-	v5 = new THREE.Vector2(), v6 = new THREE.Vector2(),
+	_enableLighting = false,
+	_color = new THREE.Color( 0xffffffff ),
+	_light = new THREE.Color( 0xffffffff ),
+	_ambientLight = new THREE.Color( 0xffffffff ),
+
+	_vector2 = new THREE.Vector2(), // Needed for expand
+	_vector3 = new THREE.Vector3(), // Needed for PointLight
+	v5 = new THREE.Vector2(), v6 = new THREE.Vector2(), // Needed for latter splitting tris to quads
 	uv1 = new THREE.UV(), uv2 = new THREE.UV(), uv3 = new THREE.UV(), uv4 = new THREE.UV();
 
 	this.domElement = _canvas;
@@ -39,14 +46,14 @@ THREE.CanvasRenderer = function () {
 			_clearRect.inflate( 1 );
 			_clearRect.minSelf( _clipRect );
 
-			/*
 			_context.setTransform( 1, 0, 0, - 1, _widthHalf, _heightHalf );
 			_context.clearRect( _clearRect.getX(), _clearRect.getY(), _clearRect.getWidth(), _clearRect.getHeight() );
-			*/
 
+			/*
 			// Opera workaround
 			_context.setTransform( 1, 0, 0, 1, _widthHalf, _heightHalf );
 			_context.clearRect( _clearRect.getX(), - ( _clearRect.getHeight() + _clearRect.getY() ), _clearRect.getWidth(), _clearRect.getHeight() );
+			*/
 
 			_clearRect.empty();
 
@@ -55,19 +62,19 @@ THREE.CanvasRenderer = function () {
 
 	this.render = function ( scene, camera ) {
 
-		var e, el, m, ml, element, material, pi2 = Math.PI * 2,
+		var e, el, element, m, ml, material, pi2 = Math.PI * 2,
 		v1x, v1y, v2x, v2y, v3x, v3y, v4x, v4y, v5x, v5y, v6x, v6y,
 		width, height, scaleX, scaleY, offsetX, offsetY,
 		bitmap, bitmapWidth, bitmapHeight;
 
-		this.project( scene, camera );
-
 		if ( this.autoClear ) {
 
 			this.clear();
 
 		}
 
+		_renderList = _projector.projectScene( scene, camera );
+
 		_context.setTransform( 1, 0, 0, - 1, _widthHalf, _heightHalf );
 
 		/* DEBUG
@@ -75,9 +82,17 @@ THREE.CanvasRenderer = function () {
 		_context.fillRect( _clipRect.getX(), _clipRect.getY(), _clipRect.getWidth(), _clipRect.getHeight() );
 		*/
 
-		for ( e = 0, el = this.renderList.length; e < el; e++ ) {
+		_enableLighting = scene.lights.length > 0;
 
-			element = this.renderList[ e ];
+		if ( _enableLighting ) {
+
+			calculateAmbientLight( scene, _ambientLight );
+
+		}
+
+		for ( e = 0, el = _renderList.length; e < el; e++ ) {
+
+			element = _renderList[ e ];
 
 			_bboxRect.empty();
 
@@ -91,6 +106,21 @@ THREE.CanvasRenderer = function () {
 
 					if ( material instanceof THREE.ParticleCircleMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						width = element.scale.x * _widthHalf;
 						height = element.scale.y * _heightHalf;
 
@@ -111,7 +141,7 @@ THREE.CanvasRenderer = function () {
 						_context.arc( 0, 0, 1, 0, pi2, true );
 						_context.closePath();
 
-						_context.fillStyle = material.color.__styleString;
+						_context.fillStyle = _color.__styleString;
 						_context.fill();
 
 						_context.restore();
@@ -191,11 +221,26 @@ THREE.CanvasRenderer = function () {
 
 					if ( material instanceof THREE.LineColorMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						_context.lineWidth = material.lineWidth;
 						_context.lineJoin = "round";
 						_context.lineCap = "round";
 
-						_context.strokeStyle = material.color.__styleString;
+						_context.strokeStyle = _color.__styleString;
 						_context.stroke();
 
 						_bboxRect.inflate( _context.lineWidth );
@@ -238,6 +283,21 @@ THREE.CanvasRenderer = function () {
 
 					if ( material instanceof THREE.MeshColorFillMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -245,11 +305,26 @@ THREE.CanvasRenderer = function () {
 						_context.lineTo( v1x, v1y );
 						_context.closePath();
 
-						_context.fillStyle = material.color.__styleString;
+						_context.fillStyle = _color.__styleString;
 						_context.fill();
 
 					} else if ( material instanceof THREE.MeshColorStrokeMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -261,13 +336,28 @@ THREE.CanvasRenderer = function () {
 						_context.lineJoin = "round";
 						_context.lineCap = "round";
 
-						_context.strokeStyle = material.color.__styleString;
+						_context.strokeStyle = _color.__styleString;
 						_context.stroke();
 
 						_bboxRect.inflate( _context.lineWidth );
 
 					} else if ( material instanceof THREE.MeshFaceColorFillMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( element.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = element.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -275,11 +365,26 @@ THREE.CanvasRenderer = function () {
 						_context.lineTo( v1x, v1y );
 						_context.closePath();
 
-						_context.fillStyle = element.color.__styleString;
+						_context.fillStyle = _color.__styleString;
 						_context.fill();
 
 					} else if ( material instanceof THREE.MeshFaceColorStrokeMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( element.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = element.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -291,7 +396,7 @@ THREE.CanvasRenderer = function () {
 						_context.lineJoin = "round";
 						_context.lineCap = "round";
 
-						_context.strokeStyle = element.color.__styleString;
+						_context.strokeStyle = _color.__styleString;
 						_context.stroke();
 
 						_bboxRect.inflate( _context.lineWidth );
@@ -310,7 +415,6 @@ THREE.CanvasRenderer = function () {
 							_context.moveTo( v1x, v1y );
 							_context.lineTo( v2x, v2y );
 							_context.lineTo( v3x, v3y );
-							_context.lineTo( v4x, v4y );
 							_context.lineTo( v1x, v1y );
 							_context.closePath();
 
@@ -385,6 +489,21 @@ THREE.CanvasRenderer = function () {
 
 					if ( material instanceof THREE.MeshColorFillMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -393,12 +512,27 @@ THREE.CanvasRenderer = function () {
 						_context.lineTo( v1x, v1y );
 						_context.closePath();
 
-						_context.fillStyle = material.color.__styleString;
+						_context.fillStyle = _color.__styleString;
 						_context.fill();
 
 
 					} else if ( material instanceof THREE.MeshColorStrokeMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( material.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = material.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -411,13 +545,28 @@ THREE.CanvasRenderer = function () {
 						_context.lineJoin = "round";
 						_context.lineCap = "round";
 
-						_context.strokeStyle = material.color.__styleString;
+						_context.strokeStyle = _color.__styleString;
 						_context.stroke();
 
 						_bboxRect.inflate( _context.lineWidth );
 
 					} else if ( material instanceof THREE.MeshFaceColorFillMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( element.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = element.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -426,11 +575,26 @@ THREE.CanvasRenderer = function () {
 						_context.lineTo( v1x, v1y );
 						_context.closePath();
 
-						_context.fillStyle = element.color.__styleString;
+						_context.fillStyle = _color.__styleString;
 						_context.fill();
 
 					} else if ( material instanceof THREE.MeshFaceColorStrokeMaterial ) {
 
+						if ( _enableLighting ) {
+
+							_light.copyRGB( _ambientLight );
+							calculateFaceLight( scene, element, _light );
+
+							_color.copyRGBA( element.color );
+							_color.multiplySelfRGB( _light );
+							_color.updateStyleString();
+
+						} else {
+
+							_color = element.color;
+
+						}
+
 						_context.beginPath();
 						_context.moveTo( v1x, v1y );
 						_context.lineTo( v2x, v2y );
@@ -443,7 +607,7 @@ THREE.CanvasRenderer = function () {
 						_context.lineJoin = "round";
 						_context.lineCap = "round";
 
-						_context.strokeStyle = element.color.__styleString;
+						_context.strokeStyle = _color.__styleString;
 						_context.stroke();
 
 						_bboxRect.inflate( _context.lineWidth );
@@ -513,7 +677,96 @@ THREE.CanvasRenderer = function () {
 
 	};
 
-	function drawTexturedTriangle( bitmap, v1x, v1y, v2x, v2y, v3x, v3y, uv1u, uv1v, uv2u, uv2v, uv3u, uv3v )  {
+	function calculateAmbientLight( scene, color ) {
+
+		var l, ll, light;
+
+		color.setRGBA( 1, 1, 1, 1 );
+
+		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+
+			light = scene.lights[ l ];
+
+			if ( light instanceof THREE.AmbientLight ) {
+
+				color.r *= light.color.r;
+				color.g *= light.color.g;
+				color.b *= light.color.b;
+
+			}
+
+		}
+
+	}
+
+	function calculateLight( scene, element, color ) {
+
+		var l, ll, light;
+
+		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+
+			light = scene.lights[ l ];
+
+			if ( light instanceof THREE.DirectionalLight ) {
+
+				color.r += light.color.r;
+				color.g += light.color.g;
+				color.b += light.color.b;
+
+			} else if ( light instanceof THREE.PointLight ) {
+
+				color.r += light.color.r;
+				color.g += light.color.g;
+				color.b += light.color.b;
+
+			}
+
+		}
+
+	}
+
+	function calculateFaceLight( scene, element, color ) {
+
+		var l, ll, light, amount;
+
+		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+
+			light = scene.lights[ l ];
+
+			if ( light instanceof THREE.DirectionalLight ) {
+
+				amount = element.normalWorld.dot( light.position ) * light.intensity;
+
+				if ( amount > 0 ) {
+
+					color.r += light.color.r * amount;
+					color.g += light.color.g * amount;
+					color.b += light.color.b * amount;
+
+				}
+
+			} else if ( light instanceof THREE.PointLight ) {
+
+				_vector3.sub( light.position, element.centroidWorld );
+				_vector3.normalize();
+
+				amount = element.normalWorld.dot( _vector3 ) * light.intensity;
+
+				if ( amount > 0 ) {
+
+					color.r += light.color.r * amount;
+					color.g += light.color.g * amount;
+					color.b += light.color.b * amount;
+
+				}
+
+			}
+
+		}
+
+	}
+
+	function drawTexturedTriangle( bitmap, v1x, v1y, v2x, v2y, v3x, v3y, uv1u, uv1v, uv2u, uv2v, uv3u, uv3v ) {
 
 		// Textured triangle drawing by Thatcher Ulrich.
 		// http://tulrich.com/geekstuff/canvas/jsgl.js
@@ -546,10 +799,13 @@ THREE.CanvasRenderer = function () {
 
 	}
 
+	// Hide anti-alias gaps
+
 	function expand( a, b ) {
 
 		_vector2.sub( b, a );
 		_vector2.unit();
+		_vector2.multiplyScalar( 0.75 );
 
 		b.addSelf( _vector2 );
 		a.subSelf( _vector2 );
@@ -557,6 +813,3 @@ THREE.CanvasRenderer = function () {
 	}
 
 };
-
-THREE.CanvasRenderer.prototype = new THREE.Renderer();
-THREE.CanvasRenderer.prototype.constructor = THREE.CanvasRenderer;

+ 6 - 7
src/renderers/DOMRenderer.js

@@ -6,7 +6,9 @@ THREE.DOMRenderer = function () {
 
 	THREE.Renderer.call( this );
 
-	var _div = document.createElement( 'div' ),
+	var _renderList = null,
+	_projector = new THREE.Projector(),
+	_div = document.createElement( 'div' ),
 	_width, _height, _widthHalf, _heightHalf;
 
 	this.domElement = _div;
@@ -22,11 +24,11 @@ THREE.DOMRenderer = function () {
 
 		var e, el, m, ml, element, material, dom, v1x, v1y;
 
-		this.project( scene, camera );
+		_renderList = _projector.projectScene( scene, camera );
 
-		for ( e = 0, el = this.renderList.length; e < el; e++ ) {
+		for ( e = 0, el = _renderList.length; e < el; e++ ) {
 
-			element = this.renderList[ e ];
+			element = _renderList[ e ];
 
 			if ( element instanceof THREE.RenderableParticle ) {
 
@@ -53,6 +55,3 @@ THREE.DOMRenderer = function () {
 	};
 
 }
-
-THREE.DOMRenderer.prototype = new THREE.Renderer();
-THREE.DOMRenderer.prototype.constructor = THREE.DOMRenderer;

+ 230 - 0
src/renderers/Projector.js

@@ -0,0 +1,230 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ */
+
+THREE.Projector = function() {
+
+	var _renderList = null,
+	_face3, _face3Count, _face3Pool = [],
+	_face4, _face4Count, _face4Pool = [],
+	_line, _lineCount, _linePool = [],
+	_particle, _particleCount, _particlePool = [],
+
+	_vector4 = new THREE.Vector4(),
+	_projScreenMatrix = new THREE.Matrix4(),
+	_projScreenObjectMatrix = new THREE.Matrix4();
+
+	this.projectScene = function ( scene, camera ) {
+
+		var o, ol, v, vl, f, fl, objects, object, objectMatrix,
+		vertices, vertex, vertexPositionScreen, vertex2,
+		faces, face, v1, v2, v3, v4;
+
+		_renderList = [];
+		_face3Count = 0, _face4Count = 0, _lineCount = 0, _particleCount = 0;
+
+		if( camera.autoUpdateMatrix ) {
+
+			camera.updateMatrix();
+
+		}
+
+		_projScreenMatrix.multiply( camera.projectionMatrix, camera.matrix );
+
+		objects = scene.objects;
+
+		for ( o = 0, ol = objects.length; o < ol; o++ ) {
+
+			object = objects[ o ];
+			objectMatrix = object.matrix;
+
+			if( object.autoUpdateMatrix ) {
+
+				object.updateMatrix();
+
+			}
+
+			if ( object instanceof THREE.Mesh ) {
+
+				_projScreenObjectMatrix.multiply( _projScreenMatrix, objectMatrix );
+
+				// vertices
+
+				vertices = object.geometry.vertices;
+
+				for ( v = 0, vl = vertices.length; v < vl; v++ ) {
+
+					vertex = vertices[ v ];
+
+					vertexPositionScreen = vertex.positionScreen;
+					vertexPositionScreen.copy( vertex.position );
+					_projScreenObjectMatrix.transform( vertexPositionScreen );
+
+					vertex.__visible = vertexPositionScreen.z > 0 && vertexPositionScreen.z < 1;
+
+				}
+
+				// faces
+
+				faces = object.geometry.faces;
+
+				for ( f = 0, fl = faces.length; f < fl; f++ ) {
+
+					face = faces[ f ];
+
+					if ( face instanceof THREE.Face3 ) {
+
+						v1 = vertices[ face.a ]; v2 = vertices[ face.b ]; v3 = vertices[ face.c ];
+
+						if ( v1.__visible && v2.__visible && v3.__visible ) {
+
+							if ( ( object.doubleSided || ( object.flipSided !=
+							   ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
+							   ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ) ) ) {
+
+								_face3 = _face3Pool[ _face3Count ] = _face3Pool[ _face3Count ] || new THREE.RenderableFace3();
+								_face3.v1.copy( v1.positionScreen );
+								_face3.v2.copy( v2.positionScreen );
+								_face3.v3.copy( v3.positionScreen );
+
+								_face3.centroidWorld.copy( face.centroid );
+								object.matrix.transform( _face3.centroidWorld );
+
+								_face3.normalWorld.copy( face.normal );
+								object.matrixRotation.transform( _face3.normalWorld );
+
+								_face3.z = Math.max( v1.positionScreen.z, Math.max( v2.positionScreen.z, v3.positionScreen.z ) );
+
+								_face3.material = object.material;
+								_face3.overdraw = object.overdraw;
+								_face3.uvs = object.geometry.uvs[ f ];
+								_face3.color = face.color;
+
+								_renderList.push( _face3 );
+
+								_face3Count ++;
+
+							}
+
+						}
+
+					} else if ( face instanceof THREE.Face4 ) {
+
+						v1 = vertices[ face.a ]; v2 = vertices[ face.b ]; v3 = vertices[ face.c ]; v4 = vertices[ face.d ];
+
+						if ( v1.__visible && v2.__visible && v3.__visible && v4.__visible ) {
+
+							if ( ( object.doubleSided || ( object.flipSided !=
+							   ( ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
+							   ( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
+							   ( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
+							   ( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0 ) ) ) ) {
+
+								_face4 = _face4Pool[ _face4Count ] = _face4Pool[ _face4Count ] || new THREE.RenderableFace4();
+								_face4.v1.copy( v1.positionScreen );
+								_face4.v2.copy( v2.positionScreen );
+								_face4.v3.copy( v3.positionScreen );
+								_face4.v4.copy( v4.positionScreen );
+
+								_face4.centroidWorld.copy( face.centroid );
+								object.matrix.transform( _face4.centroidWorld );
+
+								_face4.normalWorld.copy( face.normal );
+								object.matrixRotation.transform( _face4.normalWorld );
+
+								_face4.z = Math.max( v1.positionScreen.z, Math.max( v2.positionScreen.z, Math.max( v3.positionScreen.z, v4.positionScreen.z ) ) );
+
+								_face4.material = object.material;
+								_face4.overdraw = object.overdraw;
+								_face4.uvs = object.geometry.uvs[ f ];
+								_face4.color = face.color;
+
+								_renderList.push( _face4 );
+
+								_face4Count ++;
+
+							}
+
+						}
+
+					}
+
+				}
+
+			} else if ( object instanceof THREE.Line ) {
+
+				_projScreenObjectMatrix.multiply( _projScreenMatrix, objectMatrix );
+
+				vertices = object.geometry.vertices;
+
+				for ( v = 0, vl = vertices.length; v < vl; v++ ) {
+
+					vertex = vertices[ v ];
+
+					vertexPositionScreen = vertex.positionScreen;
+					vertexPositionScreen.copy( vertex.position );
+					_projScreenObjectMatrix.transform( vertexPositionScreen );
+
+					vertex.__visible = vertexPositionScreen.z > 0 && vertexPositionScreen.z < 1;
+
+					if ( v > 0 ) {
+
+						vertex2 = object.geometry.vertices[ v - 1 ];
+
+						if ( vertex.__visible && vertex2.__visible ) {
+
+							_line = _linePool[ _lineCount ] = _linePool[ _lineCount ] || new THREE.RenderableLine();
+							_line.v1.copy( vertex.positionScreen );
+							_line.v2.copy( vertex2.positionScreen );
+							_line.z = Math.max( vertex.positionScreen.z, vertex2.positionScreen.z );
+							_line.material = object.material;
+
+							_renderList.push( _line );
+
+							_lineCount ++;
+
+						}
+					}
+				}
+
+			} else if ( object instanceof THREE.Particle ) {
+
+				_vector4.set( object.position.x, object.position.y, object.position.z, 1 );
+
+				camera.matrix.transform( _vector4 );
+				camera.projectionMatrix.transform( _vector4 );
+
+				object.screen.set( _vector4.x / _vector4.w, _vector4.y / _vector4.w, _vector4.z / _vector4.w );
+
+				if ( object.screen.z > 0 && object.screen.z < 1 ) {
+
+					_particle = _particlePool[ _particleCount ] = _particlePool[ _particleCount ] || new THREE.RenderableParticle();
+					_particle.x = object.screen.x;
+					_particle.y = object.screen.y;
+					_particle.z = object.screen.z;
+
+					_particle.rotation = object.rotation.z;
+
+					_particle.scale.x = object.scale.x * Math.abs( _vector4.x / _vector4.w - ( _vector4.x + camera.projectionMatrix.n11 ) / ( _vector4.w + camera.projectionMatrix.n14 ) );
+					_particle.scale.y = object.scale.y * Math.abs( _vector4.y / _vector4.w - ( _vector4.y + camera.projectionMatrix.n22 ) / ( _vector4.w + camera.projectionMatrix.n24 ) );
+					_particle.material = object.material;
+					_particle.color = object.color;
+
+					_renderList.push( _particle );
+
+					_particleCount ++;
+
+				}
+
+			}
+
+		}
+
+		_renderList.sort( function ( a, b ) { return b.z - a.z; } );
+
+		return _renderList;
+
+	};
+
+};

+ 0 - 225
src/renderers/Renderer.js

@@ -1,225 +0,0 @@
-/**
- * @author mr.doob / http://mrdoob.com/
- * @author supereggbert / http://www.paulbrunt.co.uk/
- */
-
-THREE.Renderer = function() {
-
-	var face3Pool = [],
-	face4Pool = [],
-	linePool = [],
-	particlePool = [],
-
-	vector4 = new THREE.Vector4(),
-	projViewMatrix = new THREE.Matrix4();
-	projViewObjMatrix = new THREE.Matrix4();
-
-	function painterSort( a, b ) {
-
-		return b.z - a.z;
-
-	}
-
-	this.renderList = null;
-
-	this.project = function (scene, camera) {
-
-		var o, ol, v, vl, f, fl, vertex, vertex2, face, object, v1, v2, v3, v4,
-		face3count = 0, face4count = 0, lineCount = 0, particleCount = 0;
-
-		this.renderList = [];
-
-		if( camera.autoUpdateMatrix ) {
-
-			camera.updateMatrix();
-
-		}
-		
-		projViewMatrix.multiply( camera.projectionMatrix, camera.matrix );
-
-		for ( o = 0, ol = scene.objects.length; o < ol; o++ ) {
-
-			object = scene.objects[ o ];
-
-			if( object.autoUpdateMatrix ) {
-
-				object.updateMatrix();
-
-			}
-
-			if ( object instanceof THREE.Mesh ) {
-
-				projViewObjMatrix.multiply( projViewMatrix, object.matrix );
-
-				// vertices
-
-				for ( v = 0, vl = object.geometry.vertices.length; v < vl; v++ ) {
-
-					vertex = object.geometry.vertices[ v ];
-					vertex.screen.copy( vertex.position );
-
-					projViewObjMatrix.transform( vertex.screen );
-
-					vertex.__visible = vertex.screen.z > 0 && vertex.screen.z < 1;
-
-				}
-
-				// faces
-
-				for ( f = 0, fl = object.geometry.faces.length; f < fl; f++ ) {
-
-					face = object.geometry.faces[ f ];
-
-					if ( face instanceof THREE.Face3 ) {
-
-						v1 = object.geometry.vertices[ face.a ];
-						v2 = object.geometry.vertices[ face.b ];
-						v3 = object.geometry.vertices[ face.c ];
-
-						if ( v1.__visible && v2.__visible && v3.__visible &&
-						   ( object.doubleSided || ( object.flipSided !=
-						   ( v3.screen.x - v1.screen.x ) * ( v2.screen.y - v1.screen.y ) -
-						   ( v3.screen.y - v1.screen.y ) * ( v2.screen.x - v1.screen.x ) < 0 ) ) ) {
-
-							if ( !face3Pool[ face3count ] ) {
-
-								face3Pool[ face3count ] = new THREE.RenderableFace3();
-
-							}
-
-							face3Pool[ face3count ].v1.copy( v1.screen );
-							face3Pool[ face3count ].v2.copy( v2.screen );
-							face3Pool[ face3count ].v3.copy( v3.screen );
-							face3Pool[ face3count ].z = Math.max( v1.screen.z, Math.max( v2.screen.z, v3.screen.z ) );
-
-							face3Pool[ face3count ].material = object.material;
-							face3Pool[ face3count ].overdraw = object.overdraw;
-							face3Pool[ face3count ].uvs = object.geometry.uvs[ f ];
-							face3Pool[ face3count ].color = face.color;
-
-							this.renderList.push(face3Pool[face3count]);
-
-							face3count++;
-						}
-
-					} else if ( face instanceof THREE.Face4 ) {
-
-						v1 = object.geometry.vertices[ face.a ];
-						v2 = object.geometry.vertices[ face.b ];
-						v3 = object.geometry.vertices[ face.c ];
-						v4 = object.geometry.vertices[ face.d ];
-
-						if ( v1.__visible && v2.__visible && v3.__visible && v4.__visible &&
-						   ( object.doubleSided || ( object.flipSided !=
-						   ( ( v4.screen.x - v1.screen.x ) * ( v2.screen.y - v1.screen.y ) -
-						   ( v4.screen.y - v1.screen.y ) * ( v2.screen.x - v1.screen.x ) < 0 ||
-						   ( v2.screen.x - v3.screen.x ) * ( v4.screen.y - v3.screen.y ) -
-						   ( v2.screen.y - v3.screen.y ) * ( v4.screen.x - v3.screen.x ) < 0 ) ) ) ) {
-
-							if ( !face4Pool[ face4count ] ) {
-
-								face4Pool[ face4count ] = new THREE.RenderableFace4();
-
-							}
-
-							face4Pool[ face4count ].v1.copy( v1.screen );
-							face4Pool[ face4count ].v2.copy( v2.screen );
-							face4Pool[ face4count ].v3.copy( v3.screen );
-							face4Pool[ face4count ].v4.copy( v4.screen );
-							face4Pool[ face4count ].z = Math.max( v1.screen.z, Math.max( v2.screen.z, Math.max( v3.screen.z, v4.screen.z ) ) );
-
-							face4Pool[ face4count ].material = object.material;
-							face4Pool[ face4count ].overdraw = object.overdraw;
-							face4Pool[ face4count ].uvs = object.geometry.uvs[ f ];
-							face4Pool[ face4count ].color = face.color;
-
-							this.renderList.push( face4Pool[ face4count ] );
-
-							face4count++;
-						}
-
-					}
-
-				}
-
-			} else if ( object instanceof THREE.Line ) {
-
-				projViewObjMatrix.multiply( projViewMatrix, object.matrix );
-
-				for ( v = 0, vl = object.geometry.vertices.length; v < vl; v++ ) {
-
-					vertex = object.geometry.vertices[ v ];
-					vertex.screen.copy( vertex.position );
-
-					projViewObjMatrix.transform( vertex.screen );
-
-					vertex.__visible = vertex.screen.z > 0 && vertex.screen.z < 1;
-
-					if ( v > 0 ) {
-
-						vertex2 = object.geometry.vertices[ v - 1 ];
-
-						if ( vertex.__visible && vertex2.__visible ) {
-
-							if ( !linePool[ lineCount ] ) {
-
-								linePool[ lineCount ] = new THREE.RenderableLine();
-
-							}
-
-							linePool[ lineCount ].v1.copy( vertex.screen );
-							linePool[ lineCount ].v2.copy( vertex2.screen );
-							linePool[ lineCount ].z = Math.max( vertex.screen.z, vertex2.screen.z );
-							linePool[ lineCount ].material = object.material;
-
-							this.renderList.push( linePool[lineCount] );
-
-							lineCount++;
-
-						}
-					}
-				}
-
-			} else if ( object instanceof THREE.Particle ) {
-
-				vector4.set( object.position.x, object.position.y, object.position.z, 1 );
-
-				camera.matrix.transform( vector4 );
-				camera.projectionMatrix.transform( vector4 );
-
-				object.screen.set( vector4.x / vector4.w, vector4.y / vector4.w, vector4.z / vector4.w );
-
-				if ( object.screen.z > 0 && object.screen.z < 1 ) {
-
-					if ( !particlePool[ particleCount ] ) {
-
-						particlePool[ particleCount ] = new THREE.RenderableParticle();
-
-					}
-
-					particlePool[ particleCount ].x = object.screen.x;
-					particlePool[ particleCount ].y = object.screen.y;
-					particlePool[ particleCount ].z = object.screen.z;
-
-					particlePool[ particleCount ].rotation = object.rotation.z;
-
-					particlePool[ particleCount ].scale.x = object.scale.x * Math.abs( vector4.x / vector4.w - ( vector4.x + camera.projectionMatrix.n11 ) / ( vector4.w + camera.projectionMatrix.n14 ) );
-					particlePool[ particleCount ].scale.y = object.scale.y * Math.abs( vector4.y / vector4.w - ( vector4.y + camera.projectionMatrix.n22 ) / ( vector4.w + camera.projectionMatrix.n24 ) );
-					particlePool[ particleCount ].material = object.material;
-					particlePool[ particleCount ].color = object.color;
-
-					this.renderList.push( particlePool[ particleCount ] );
-
-					particleCount++;
-
-				}
-
-			}
-
-		}
-
-		this.renderList.sort( painterSort );
-
-	};
-
-};

+ 150 - 13
src/renderers/SVGRenderer.js

@@ -4,12 +4,20 @@
 
 THREE.SVGRenderer = function () {
 
-	THREE.Renderer.call( this );
-
-	var _svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
+	var _renderList = null,
+	_projector = new THREE.Projector(),
+	_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
 	_width, _height, _widthHalf, _heightHalf,
 	_clipRect = new THREE.Rectangle(),
 	_bboxRect = new THREE.Rectangle(),
+
+	_enableLighting = false,
+	_color = new THREE.Color( 0xffffffff ),
+	_light = new THREE.Color( 0xffffffff ),
+	_ambientLight = new THREE.Color( 0xffffffff ),
+
+	_vector3 = new THREE.Vector3(), // Needed for PointLight
+
 	_svgPathPool = [], _svgCirclePool = [],
 	_quality = 1;
 
@@ -63,11 +71,19 @@ THREE.SVGRenderer = function () {
 
 		}
 
-		this.project( scene, camera );
+		_renderList = _projector.projectScene( scene, camera );
+
+		_enableLighting = scene.lights.length > 0;
 
-		for ( e = 0, el = this.renderList.length; e < el; e++ ) {
+		if ( _enableLighting ) {
 
-			element = this.renderList[ e ];
+			calculateAmbientLight( scene, _ambientLight );
+
+		}
+
+		for ( e = 0, el = _renderList.length; e < el; e++ ) {
+
+			element = _renderList[ e ];
 
 			for ( m = 0, ml = element.material.length; m < ml; m++ ) {
 
@@ -135,23 +151,84 @@ THREE.SVGRenderer = function () {
 
 				}
 
+
 				// TODO: Move out of materials loop
 
 				if ( material instanceof THREE.MeshColorFillMaterial ) {
 
-					svgNode.setAttribute( 'style', 'fill: ' + material.color.__styleString );
+					if ( _enableLighting ) {
+
+						_light.copyRGB( _ambientLight );
+						calculateFaceLight( scene, element, _light );
+
+						_color.copyRGBA( material.color );
+						_color.multiplySelfRGB( _light );
+						_color.updateStyleString();
+
+					} else {
+
+							_color = material.color;
+
+					}
+
+					svgNode.setAttribute( 'style', 'fill: ' + _color.__styleString );
 
 				} else if ( material instanceof THREE.MeshFaceColorFillMaterial ) {
 
-					svgNode.setAttribute( 'style', 'fill: ' + element.color.__styleString );
+					if ( _enableLighting ) {
+
+						_light.copyRGB( _ambientLight );
+						calculateFaceLight( scene, element, _light );
+
+						_color.copyRGBA( element.color );
+						_color.multiplySelfRGB( _light );
+						_color.updateStyleString();
+
+					} else {
+
+							_color = element.color;
+
+					}
+
+					svgNode.setAttribute( 'style', 'fill: ' + _color.__styleString );
 
 				} else if ( material instanceof THREE.MeshColorStrokeMaterial ) {
 
-					svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.__styleString + '; stroke-width: ' + material.lineWidth + '; stroke-linecap: round; stroke-linejoin: round' );
+					if ( _enableLighting ) {
+
+						_light.copyRGB( _ambientLight );
+						calculateFaceLight( scene, element, _light );
+
+						_color.copyRGBA( material.color );
+						_color.multiplySelfRGB( _light );
+						_color.updateStyleString();
+
+					} else {
+
+							_color = material.color;
+
+					}
+
+					svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.__styleString + '; stroke-width: ' + material.lineWidth + '; stroke-linecap: round; stroke-linejoin: round' );
 
 				} else if ( material instanceof THREE.MeshFaceColorStrokeMaterial ) {
 
-					svgNode.setAttribute( 'style', 'fill: none; stroke: ' + element.color.__styleString + '; stroke-width: ' + material.lineWidth + '; stroke-linecap: round; stroke-linejoin: round' );
+					if ( _enableLighting ) {
+
+						_light.copyRGB( _ambientLight );
+						calculateFaceLight( scene, element, _light );
+
+						_color.copyRGBA( element.color );
+						_color.multiplySelfRGB( _light );
+						_color.updateStyleString();
+
+					} else {
+
+						_color = element.color;
+
+					}
+
+					svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.__styleString + '; stroke-width: ' + material.lineWidth + '; stroke-linecap: round; stroke-linejoin: round' );
 
 				}
 
@@ -163,6 +240,69 @@ THREE.SVGRenderer = function () {
 
 	};
 
+	function calculateAmbientLight( scene, color ) {
+
+		var l, ll, light;
+
+		color.setRGBA( 1, 1, 1, 1 );
+
+		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+
+			light = scene.lights[ l ];
+
+			if ( light instanceof THREE.AmbientLight ) {
+
+				color.r *= light.color.r;
+				color.g *= light.color.g;
+				color.b *= light.color.b;
+
+			}
+
+		}
+
+	}
+
+	function calculateFaceLight( scene, element, color ) {
+
+		var l, ll, light, amount;
+
+		for ( l = 0, ll = scene.lights.length; l < ll; l++ ) {
+
+			light = scene.lights[ l ];
+
+			if ( light instanceof THREE.DirectionalLight ) {
+
+				amount = element.normalWorld.dot( light.position ) * light.intensity;
+
+				if ( amount > 0 ) {
+
+					color.r += light.color.r * amount;
+					color.g += light.color.g * amount;
+					color.b += light.color.b * amount;
+
+				}
+
+			} else if ( light instanceof THREE.PointLight ) {
+
+				_vector3.sub( light.position, element.centroidWorld );
+				_vector3.normalize();
+
+				amount = element.normalWorld.dot( _vector3 ) * light.intensity;
+
+				if ( amount > 0 ) {
+
+					color.r += light.color.r * amount;
+					color.g += light.color.g * amount;
+					color.b += light.color.b * amount;
+
+				}
+
+			}
+
+		}
+
+	}
+
 	function getPathNode( id ) {
 
 		if ( _svgPathPool[ id ] == null ) {
@@ -204,6 +344,3 @@ THREE.SVGRenderer = function () {
 	}
 
 };
-
-THREE.SVGRenderer.prototype = new THREE.Renderer();
-THREE.SVGRenderer.prototype.constructor = THREE.CanvasRenderer;

+ 5 - 3
src/renderers/WebGLRenderer.js

@@ -30,7 +30,7 @@ THREE.WebGLRenderer = function () {
 
 	this.render = function ( scene, camera ) {
 
-		var face, faceColor, object, material, normal, lightColor, lightDirection, light,
+		var face, faceColor, object, material, normal, lightColor, lightPosition, light,
 		vertexArray, faceArray, colorArray, normalArray, vertexIndex,
 		o, ol, f, fl, m, ml, i, v1, v2, v3, v4,
 		l, ll;
@@ -56,8 +56,8 @@ THREE.WebGLRenderer = function () {
 			} else if( light instanceof THREE.DirectionalLight ) {
 
 				lightColor = light.color;
-				lightDirection = light.direction;
-				_gl.uniform3f( _program.lightingDirection, lightDirection.x, lightDirection.y, lightDirection.z );
+				lightPosition = light.position;
+				_gl.uniform3f( _program.lightingDirection, lightPosition.x, lightPosition.y, lightPosition.z );
 				_gl.uniform3f( _program.directionalColor, lightColor.r, lightColor.g, lightColor.b );
 
 			}
@@ -161,6 +161,8 @@ THREE.WebGLRenderer = function () {
 
 				}
 
+				camera.autoUpdateMatrix && camera.updateMatrix();
+				object.autoUpdateMatrix && object.updateMatrix();
 
 				viewMatrix.multiply( camera.matrix, object.matrix );
 

+ 3 - 0
src/renderers/renderables/RenderableFace3.js

@@ -8,6 +8,9 @@ THREE.RenderableFace3 = function () {
 	this.v2 = new THREE.Vector2();
 	this.v3 = new THREE.Vector2();
 
+	this.centroidWorld = new THREE.Vector3();
+	this.normalWorld = new THREE.Vector3();
+
 	this.z = null;
 
 	this.color = null;

+ 3 - 0
src/renderers/renderables/RenderableFace4.js

@@ -9,6 +9,9 @@ THREE.RenderableFace4 = function () {
 	this.v3 = new THREE.Vector2();
 	this.v4 = new THREE.Vector2();
 
+	this.centroidWorld = new THREE.Vector3();
+	this.normalWorld = new THREE.Vector3();
+
 	this.z = null;
 
 	this.color = null;

+ 6 - 5
utils/Builder.py

@@ -19,13 +19,14 @@ files.append('core/Face4.js')
 files.append('core/UV.js')
 files.append('core/Geometry.js')
 files.append('cameras/Camera.js')
-files.append('objects/Object3D.js')
-files.append('objects/Line.js')
-files.append('objects/Mesh.js')
-files.append('objects/Particle.js')
 files.append('lights/Light.js')
 files.append('lights/AmbientLight.js')
 files.append('lights/DirectionalLight.js')
+files.append('lights/PointLight.js')
+files.append('objects/Object3D.js')
+files.append('objects/Particle.js')
+files.append('objects/Line.js')
+files.append('objects/Mesh.js')
 files.append('materials/LineColorMaterial.js')
 files.append('materials/MeshBitmapUVMappingMaterial.js')
 files.append('materials/MeshColorFillMaterial.js')
@@ -36,7 +37,7 @@ files.append('materials/ParticleBitmapMaterial.js')
 files.append('materials/ParticleCircleMaterial.js')
 files.append('materials/ParticleDOMMaterial.js')
 files.append('scenes/Scene.js')
-files.append('renderers/Renderer.js')
+files.append('renderers/Projector.js')
 files.append('renderers/DOMRenderer.js')
 files.append('renderers/CanvasRenderer.js')
 files.append('renderers/SVGRenderer.js')

+ 6 - 5
utils/BuilderCanvas.py

@@ -19,13 +19,14 @@ files.append('core/Face4.js')
 files.append('core/UV.js')
 files.append('core/Geometry.js')
 files.append('cameras/Camera.js')
-files.append('objects/Object3D.js')
-files.append('objects/Line.js')
-files.append('objects/Mesh.js')
-files.append('objects/Particle.js')
 files.append('lights/Light.js')
 files.append('lights/AmbientLight.js')
 files.append('lights/DirectionalLight.js')
+files.append('lights/PointLight.js')
+files.append('objects/Object3D.js')
+files.append('objects/Particle.js')
+files.append('objects/Line.js')
+files.append('objects/Mesh.js')
 files.append('materials/LineColorMaterial.js')
 files.append('materials/MeshBitmapUVMappingMaterial.js')
 files.append('materials/MeshColorFillMaterial.js')
@@ -35,7 +36,7 @@ files.append('materials/MeshFaceColorStrokeMaterial.js')
 files.append('materials/ParticleBitmapMaterial.js')
 files.append('materials/ParticleCircleMaterial.js')
 files.append('scenes/Scene.js')
-files.append('renderers/Renderer.js')
+files.append('renderers/Projector.js')
 files.append('renderers/CanvasRenderer.js')
 files.append('renderers/renderables/RenderableFace3.js')
 files.append('renderers/renderables/RenderableFace4.js')

+ 1 - 1
utils/BuilderDOM.py

@@ -22,7 +22,7 @@ files.append('objects/Object3D.js')
 files.append('objects/Particle.js')
 files.append('materials/ParticleDOMMaterial.js')
 files.append('scenes/Scene.js')
-files.append('renderers/Renderer.js')
+files.append('renderers/Projector.js')
 files.append('renderers/DOMRenderer.js')
 files.append('renderers/renderables/RenderableParticle.js')
 

+ 6 - 5
utils/BuilderDebug.py

@@ -19,13 +19,14 @@ files.append('core/Face4.js')
 files.append('core/UV.js')
 files.append('core/Geometry.js')
 files.append('cameras/Camera.js')
-files.append('objects/Object3D.js')
-files.append('objects/Line.js')
-files.append('objects/Mesh.js')
-files.append('objects/Particle.js')
 files.append('lights/Light.js')
 files.append('lights/AmbientLight.js')
 files.append('lights/DirectionalLight.js')
+files.append('lights/PointLight.js')
+files.append('objects/Object3D.js')
+files.append('objects/Particle.js')
+files.append('objects/Line.js')
+files.append('objects/Mesh.js')
 files.append('materials/LineColorMaterial.js')
 files.append('materials/MeshBitmapUVMappingMaterial.js')
 files.append('materials/MeshColorFillMaterial.js')
@@ -36,7 +37,7 @@ files.append('materials/ParticleBitmapMaterial.js')
 files.append('materials/ParticleCircleMaterial.js')
 files.append('materials/ParticleDOMMaterial.js')
 files.append('scenes/Scene.js')
-files.append('renderers/Renderer.js')
+files.append('renderers/Projector.js')
 files.append('renderers/DOMRenderer.js')
 files.append('renderers/CanvasRenderer.js')
 files.append('renderers/SVGRenderer.js')

+ 6 - 6
utils/BuilderSVG.py

@@ -19,14 +19,14 @@ files.append('core/Face4.js')
 files.append('core/UV.js')
 files.append('core/Geometry.js')
 files.append('cameras/Camera.js')
-files.append('objects/Object3D.js')
-files.append('objects/Line.js')
-files.append('objects/Mesh.js')
-files.append('objects/Particle.js')
 files.append('lights/Light.js')
 files.append('lights/AmbientLight.js')
 files.append('lights/DirectionalLight.js')
-files.append('materials/LineColorMaterial.js')
+files.append('lights/PointLight.js')
+files.append('objects/Object3D.js')
+files.append('objects/Particle.js')
+files.append('objects/Line.js')
+files.append('objects/Mesh.js')
 files.append('materials/MeshBitmapUVMappingMaterial.js')
 files.append('materials/MeshColorFillMaterial.js')
 files.append('materials/MeshColorStrokeMaterial.js')
@@ -35,7 +35,7 @@ files.append('materials/MeshFaceColorStrokeMaterial.js')
 files.append('materials/ParticleBitmapMaterial.js')
 files.append('materials/ParticleCircleMaterial.js')
 files.append('scenes/Scene.js')
-files.append('renderers/Renderer.js')
+files.append('renderers/Projector.js')
 files.append('renderers/SVGRenderer.js')
 files.append('renderers/renderables/RenderableFace3.js')
 files.append('renderers/renderables/RenderableFace4.js')

+ 5 - 4
utils/BuilderWebGL.py

@@ -19,13 +19,14 @@ files.append('core/Face4.js')
 files.append('core/UV.js')
 files.append('core/Geometry.js')
 files.append('cameras/Camera.js')
-files.append('objects/Object3D.js')
-files.append('objects/Line.js')
-files.append('objects/Mesh.js')
-files.append('objects/Particle.js')
 files.append('lights/Light.js')
 files.append('lights/AmbientLight.js')
 files.append('lights/DirectionalLight.js')
+files.append('lights/PointLight.js')
+files.append('objects/Object3D.js')
+files.append('objects/Particle.js')
+files.append('objects/Line.js')
+files.append('objects/Mesh.js')
 files.append('materials/LineColorMaterial.js')
 files.append('materials/MeshBitmapUVMappingMaterial.js')
 files.append('materials/MeshColorFillMaterial.js')

+ 1 - 1
utils/REVISION

@@ -1 +1 @@
-17
+18

+ 80 - 0
utils/exporters/blender/2.54/scripts/op/io_mesh_threejs/__init__.py

@@ -0,0 +1,80 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    import sys
+    reload(sys.modules.get("io_mesh_threejs.export_threejs", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper
+
+
+class ExportTHREEJS(bpy.types.Operator, ExportHelper):
+    '''This script exports the selected object for the three.js engine.'''
+    bl_idname = "export.threejs"
+    bl_label = "Export Three.js"
+    
+    filename_ext = ".js"
+
+    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
+    use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
+    use_uv_coords = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
+    use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
+
+    @classmethod
+    def poll(cls, context):
+        return context.active_object != None
+
+    def execute(self, context):
+        print("Selected: " + context.active_object.name)
+
+        if not self.properties.filepath:
+            raise Exception("filename not set")
+
+        filepath = self.filepath
+        import io_mesh_threejs.export_threejs
+        return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
+
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        row.prop(self.properties, "use_modifiers")
+        row.prop(self.properties, "use_normals")
+        row = layout.row()
+        row.prop(self.properties, "use_uv_coords")
+        row.prop(self.properties, "use_colors")
+
+
+def menu_func(self, context):
+    default_path = bpy.data.filepath.replace(".blend", ".js")
+    self.layout.operator(ExportTHREEJS.bl_idname, text="Three.js (.js)").filepath = default_path
+
+
+def register():
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+if __name__ == "__main__":
+    register()

+ 176 - 0
utils/exporters/blender/2.54/scripts/op/io_mesh_threejs/export_threejs.py

@@ -0,0 +1,176 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# Based on export_ply.py
+# Contributors: Mr.doob, Kikko, alteredq
+
+"""
+This script exports the selected object for the three.js engine.
+"""
+
+import bpy
+import os
+import os.path
+
+def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True):
+
+    def rvec3d(v):
+        return round(v[0], 6), round(v[1], 6), round(v[2], 6)
+
+    def rvec2d(v):
+        return round(v[0], 6), round(v[1], 6)
+
+    scene = context.scene
+    obj = context.object
+
+    if not filepath.lower().endswith('.js'):
+        filepath += '.js'
+
+    classname = os.path.basename(filepath).split(".")[0]
+
+    if not obj:
+        raise Exception("Error, Select 1 active object")
+
+    file = open(filepath, 'w')
+
+    if scene.objects.active:
+        bpy.ops.object.mode_set(mode='OBJECT')
+
+    if use_modifiers:
+        mesh = obj.create_mesh(scene, True, 'PREVIEW')
+    else:
+        mesh = obj.data
+
+    if not mesh:
+        raise Exception("Error, could not get mesh data from active object")
+
+    # mesh.transform(obj.matrix_world) # XXX
+
+    faceUV = (len(mesh.uv_textures) > 0)
+    vertexUV = (len(mesh.sticky) > 0)
+    vertexColors = len(mesh.vertex_colors) > 0
+
+    if (not faceUV) and (not vertexUV):
+        use_uv_coords = False
+    if not vertexColors:
+        use_colors = False
+
+    if not use_uv_coords:
+        faceUV = vertexUV = False
+    if not use_colors:
+        vertexColors = False
+
+    if faceUV:
+        active_uv_layer = mesh.uv_textures.active
+        if not active_uv_layer:
+            use_uv_coords = False
+            faceUV = None
+        else:
+            active_uv_layer = active_uv_layer.data
+
+    if vertexColors:
+        active_col_layer = mesh.vertex_colors.active
+        if not active_col_layer:
+            use_colors = False
+            vertexColors = None
+        else:
+            active_col_layer = active_col_layer.data
+
+    # incase
+    color = uvcoord = uvcoord_key = normal = normal_key = None
+
+    file.write('// Generated with Blender 2.54 exporter\n')
+    file.write('// http://github.com/mrdoob/three.js/tree/master/utils/exporters/blender\n\n')
+
+    file.write('var %s = function () {\n\n' % classname)
+
+    file.write('\tvar scope = this;\n\n')
+
+    file.write('\tTHREE.Geometry.call( this );\n\n')
+
+    for v in mesh.vertices:
+        file.write('\tv( %.6f, %.6f, %.6f );\n' % (v.co.x, v.co.z, -v.co.y)) # co
+
+    file.write('\n')
+
+    if use_normals:
+        for f in mesh.faces:
+            if len(f.vertices) == 3:
+                file.write('\tf3( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.normal[0], f.normal[1], f.normal[2]))
+            else:
+                file.write('\tf4( %d, %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.vertices[3], f.normal[0], f.normal[1], f.normal[2]))
+
+    else:
+        for f in mesh.faces:
+            if len(f.vertices) == 3:
+                file.write('\tf3( %d, %d, %d );\n' % (f.vertices[0], f.vertices[1], f.vertices[2]))
+            else:
+                file.write('\tf4( %d, %d, %d, %d );\n' % (f.vertices[0], f.vertices[1], f.vertices[2], f.vertices[3]))
+
+    face_index_pairs = [ (face, index) for index, face in enumerate(mesh.faces)]
+
+    if use_uv_coords:
+        file.write('\n')
+        for f, f_index in face_index_pairs:
+            tface = mesh.uv_textures[0].data[f_index]
+            if len(f.vertices) == 3:
+                file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv1[0], 1.0-tface.uv1[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1]))
+            else:
+                file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv1[0], 1.0-tface.uv1[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1], tface.uv4[0], 1.0-tface.uv4[1]))
+
+    file.write('\n')
+
+    file.write('\tfunction v( x, y, z ) {\n\n')
+    file.write('\t\tscope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );\n\n')
+    file.write('\t}\n\n')
+
+    file.write('\tfunction f3( a, b, c, nx, ny, nz ) {\n\n')
+    file.write('\t\tscope.faces.push( new THREE.Face3( a, b, c, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n')
+    file.write('\t}\n\n')
+
+    file.write('\tfunction f4( a, b, c, d, nx, ny, nz ) {\n\n')
+    file.write('\t\tscope.faces.push( new THREE.Face4( a, b, c, d, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n')
+    file.write('\t}\n\n')
+
+    file.write('\tfunction uv( u1, v1, u2, v2, u3, v3, u4, v4 ) {\n\n')
+    file.write('\t\tvar uv = [];\n')
+    file.write('\t\tuv.push( new THREE.UV( u1, v1 ) );\n')
+    file.write('\t\tuv.push( new THREE.UV( u2, v2 ) );\n')
+    file.write('\t\tuv.push( new THREE.UV( u3, v3 ) );\n')
+    file.write('\t\tif ( u4 && v4 ) uv.push( new THREE.UV( u4, v4 ) );\n')
+    file.write('\t\tscope.uvs.push( uv );\n')
+    file.write('\t}\n\n')
+
+    file.write('\tthis.computeCentroids();\n')
+
+    if not use_normals:
+        file.write('\tthis.computeNormals();\n')
+
+    file.write('\n}\n\n')
+
+    file.write('%s.prototype = new THREE.Geometry();\n' % classname)
+    file.write('%s.prototype.constructor = %s;' % (classname, classname))
+
+    file.close()
+
+    print("writing", filepath, "done")
+
+    if use_modifiers:
+        bpy.data.meshes.remove(mesh)
+
+    return {'FINISHED'}

+ 0 - 0
utils/exporters/export_threejs_2.53b.py → utils/exporters/blender/export_threejs_2.53b.py


+ 0 - 0
utils/exporters/export_threejs_2.5a2.py → utils/exporters/blender/export_threejs_2.5a2.py


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff