Browse Source

Merge remote branch 'remotes/sole/master'

alteredq 14 years ago
parent
commit
7abad40d83
3 changed files with 531 additions and 0 deletions
  1. 176 0
      examples/geometry/cube.html
  2. 155 0
      src/renderers/Renderer.js
  3. 200 0
      utils/build.py

+ 176 - 0
examples/geometry/cube.html

@@ -0,0 +1,176 @@
+<!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="../../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">
+
+			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;
+
+			init();
+			setInterval(loop, 1000/60);
+
+			function init()
+			{
+				container = document.createElement('div');
+				document.body.appendChild(container);
+				
+				var info = document.createElement('div');
+				info.style.position = 'absolute';
+				info.style.top = '10px';
+				info.style.width = '100%';
+				info.style.textAlign = 'center';
+				info.innerHTML = 'Drag to spin the cube';
+				container.appendChild(info);
+			
+				camera = new Camera(0, 150, 400);
+				camera.focus = 300;
+				camera.target.y = 150;
+				camera.updateMatrix();
+
+				scene = new Scene();
+
+				// Cube
+
+				geometry = new Cube(200, 200, 200);
+
+				for (var i = 0; i < geometry.faces.length; i++)
+					geometry.faces[i].color.setRGBA( Math.floor( Math.random() * 128), Math.floor( Math.random() * 128 + 128), Math.floor( Math.random() * 128 + 128), 255 );
+								
+				cube = new Mesh(geometry, new FaceColorMaterial());
+				cube.position.y = 150;
+				cube.updateMatrix();
+				scene.add(cube);
+				
+				// Plane
+				
+				plane = new Mesh(new Plane(200, 200), new ColorMaterial(0xe0e0e0));
+				plane.rotation.x = 90 * (Math.PI / 180);
+				plane.updateMatrix();
+				scene.add(plane);
+				
+				renderer = new CanvasRenderer();
+				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+				container.appendChild(renderer.viewport);
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild(stats.domElement);
+				
+				document.addEventListener('mousedown', onDocumentMouseDown, false);
+				document.addEventListener('touchstart', onDocumentTouchStart, false);
+				document.addEventListener('touchmove', onDocumentTouchMove, false);
+			}
+
+			//
+
+			function onDocumentMouseDown( event )
+			{
+				event.preventDefault();
+				
+				document.addEventListener('mousemove', onDocumentMouseMove, false);
+				document.addEventListener('mouseup', onDocumentMouseUp, false);
+				document.addEventListener('mouseout', onDocumentMouseOut, false);
+				
+				mouseXOnMouseDown = event.clientX - windowHalfX;
+				targetRotationOnMouseDown = targetRotation;
+			}
+
+			function onDocumentMouseMove( event )
+			{
+				mouseX = event.clientX - windowHalfX;
+				
+				targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
+			}
+			
+			function onDocumentMouseUp( event )
+			{
+				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);
+			}
+			
+			function onDocumentTouchStart( event )
+			{
+				if(event.touches.length == 1)
+				{
+					event.preventDefault();
+
+					mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
+					targetRotationOnMouseDown = targetRotation;
+				}
+			}
+
+			function onDocumentTouchMove( event )
+			{
+				if(event.touches.length == 1)
+				{
+					event.preventDefault();
+					
+					mouseX = event.touches[0].pageX - windowHalfX;
+					targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
+				}
+			}
+
+			//
+
+			function loop()
+			{
+				cube.rotation.y += (targetRotation - cube.rotation.y) * 0.05;
+				cube.updateMatrix();
+				
+				plane.rotation.z = -cube.rotation.y;
+				plane.updateMatrix();
+				
+				renderer.render(scene, camera);
+				stats.update();
+			}
+	
+		</script>
+
+	</body>
+</html>

+ 155 - 0
src/renderers/Renderer.js

@@ -0,0 +1,155 @@
+var Renderer = Class.extend
+({
+	matrix: null,
+
+	viewport: null,
+	renderList: null,
+
+	face3Pool: null,
+	face4Pool: null,
+
+	width: null,
+	height: null,
+	widthHalf: null,
+	heightHalf: null,
+
+	init: function()
+	{
+		this.matrix = new Matrix4();
+
+		this.face3Pool = new Array();
+		this.face4Pool = new Array();
+	},
+
+	setSize: function( width, height )
+	{
+		this.width = width;
+		this.height = height;
+
+		this.widthHalf = this.width / 2;
+		this.heightHalf = this.height / 2;
+	},
+
+	sort: function(a, b)
+	{
+		return a.screen.z - b.screen.z;
+	},
+
+	render: function( scene, camera )
+	{
+		var vertex, face, object;
+		var face3count = 0, face4count = 0;
+
+		var focuszoom = camera.focus * camera.zoom;
+
+		var matrixMultiply = this.matrix.multiply;
+		var matrixTransform = this.matrix.transform;
+
+		this.renderList = new Array();
+
+		for (var i = 0; i < scene.objects.length; i++)
+		{
+			object = scene.objects[i];
+
+			if (object instanceof Mesh)
+			{
+				matrixMultiply( camera.matrix, object.matrix );
+
+				// vertices
+
+				for (var j = 0; j < object.geometry.vertices.length; j++)
+				{
+					vertex = object.geometry.vertices[j];
+
+					vertex.screen.copy( vertex );
+
+					matrixTransform( vertex.screen );
+
+					vertex.screen.z = focuszoom / (camera.focus + vertex.screen.z);
+
+					vertex.visible = vertex.screen.z > 0;					
+
+					vertex.screen.x *= vertex.screen.z;
+					vertex.screen.y *= vertex.screen.z; 
+				}
+
+				// faces
+
+				for (j = 0; j < object.geometry.faces.length; j++)
+				{
+					face = object.geometry.faces[j];
+					
+					// TODO: Use normals for culling
+
+					if (face instanceof Face3)
+					{
+						if (face.a.visible && face.b.visible && face.c.visible && (object.doubleSided ||
+						   (face.c.screen.x - face.a.screen.x) * (face.b.screen.y - face.a.screen.y) -
+						   (face.c.screen.y - face.a.screen.y) * (face.b.screen.x - face.a.screen.x) > 0) )
+						{
+							face.screen.z = (face.a.screen.z + face.b.screen.z + face.c.screen.z) * 0.3;
+							
+							if (this.face3Pool[face3count] == null)
+								this.face3Pool[face3count] = new Face3(new Vertex(), new Vertex(), new Vertex());
+
+							this.face3Pool[face3count].a.screen.copy(face.a.screen);
+							this.face3Pool[face3count].b.screen.copy(face.b.screen);
+							this.face3Pool[face3count].c.screen.copy(face.c.screen);
+							this.face3Pool[face3count].screen.z = face.screen.z;
+							this.face3Pool[face3count].color = face.color;
+							this.face3Pool[face3count].material = object.material;
+
+							this.renderList.push( this.face3Pool[face3count] );
+
+							face3count++;
+						}
+					}
+					else if (face instanceof Face4)
+					{
+						if (face.a.visible && face.b.visible && face.c.visible && (object.doubleSided ||
+						   ((face.d.screen.x - face.a.screen.x) * (face.b.screen.y - face.a.screen.y) -
+						   (face.d.screen.y - face.a.screen.y) * (face.b.screen.x - face.a.screen.x) > 0 ||
+						   (face.b.screen.x - face.c.screen.x) * (face.d.screen.y - face.c.screen.y) -
+						   (face.b.screen.y - face.c.screen.y) * (face.d.screen.x - face.c.screen.x) > 0)) )
+						{
+							face.screen.z = (face.a.screen.z + face.b.screen.z + face.c.screen.z + face.d.screen.z) * 0.25;
+
+							if (this.face4Pool[face4count] == null)
+								this.face4Pool[face4count] = new Face4(new Vertex(), new Vertex(), new Vertex(), new Vertex());
+
+							this.face4Pool[face4count].a.screen.copy(face.a.screen);
+							this.face4Pool[face4count].b.screen.copy(face.b.screen);
+							this.face4Pool[face4count].c.screen.copy(face.c.screen);
+							this.face4Pool[face4count].d.screen.copy(face.d.screen);
+							this.face4Pool[face4count].screen.z = face.screen.z;
+							this.face4Pool[face4count].color = face.color;
+							this.face4Pool[face4count].material = object.material;
+
+							this.renderList.push( this.face4Pool[face4count] );
+
+							face4count++;
+						}						
+					}
+				}
+			}
+			else if (object instanceof Particle)
+			{
+				object.screen.copy(object.position);
+
+				camera.matrix.transform( object.screen );
+
+				object.screen.z = focuszoom / (camera.focus + object.screen.z);
+
+				if (object.screen.z < 0)
+					continue;					
+
+				object.screen.x *= object.screen.z;
+				object.screen.y *= object.screen.z;
+
+				this.renderList.push( object );
+			}
+		}
+
+		this.renderList.sort(this.sort);
+	}
+});

+ 200 - 0
utils/build.py

@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+
+import argparse
+import os
+import tempfile
+
+
+FILES = {
+	'core': ['Three.js', 'core/Color.js', 'core/Vector2.js', 'core/Vector3.js', 'core/Vector4.js', 'core/Ray.js', 'core/Rectangle.js', 'core/Matrix3.js', 'core/Matrix4.js', 'core/Vertex.js', 'core/Face3.js', 'core/Face4.js', 'core/UV.js', 'core/Geometry.js'],
+	'cameras': ['cameras/Camera.js'],
+	'io': ['io/Loader.js'],
+	'lights': ['lights/Light.js', 'lights/AmbientLight.js', 'lights/DirectionalLight.js', 'lights/PointLight.js'],
+	'objects': ['objects/Object3D.js', 'objects/Particle.js', 'objects/Line.js', 'objects/Mesh.js'],
+	'materials': ['materials/LineColorMaterial.js', 'materials/MeshPhongMaterial.js', 'materials/MeshBitmapMaterial.js', 'materials/MeshColorFillMaterial.js', 'materials/MeshColorStrokeMaterial.js', 'materials/MeshFaceMaterial.js', 'materials/ParticleBitmapMaterial.js', 'materials/ParticleCircleMaterial.js', 'materials/ParticleDOMMaterial.js'],
+	'scenes': ['scenes/Scene.js'],
+	'projector': ['renderers/Projector.js'],
+	'renderers': ['renderers/DOMRenderer.js', 'renderers/CanvasRenderer.js', 'renderers/SVGRenderer.js', 'renderers/WebGLRenderer.js'],
+	'renderables': ['renderers/renderables/RenderableFace3.js', 'renderers/renderables/RenderableFace4.js', 'renderers/renderables/RenderableParticle.js', 'renderers/renderables/RenderableLine.js']
+}
+
+
+def merge(files):
+	text = ""
+
+	for filename in files:
+		with open(os.path.join('..', 'src', filename), 'r') as f:
+			text = text + f.read()
+
+	return text
+
+
+def output(text, filename):
+	with open(os.path.join('..', 'build', filename), 'w') as f:
+		f.write(text)
+
+
+def compress(text):
+	
+	in_tuple = tempfile.mkstemp()
+	with os.fdopen(in_tuple[0], 'w') as handle:
+		handle.write(text)
+
+	out_tuple = tempfile.mkstemp()
+	os.system("java -jar yuicompressor-2.4.2.jar %s --type js -o %s --charset utf-8 -v" % (in_tuple[1], out_tuple[1]))
+
+	with os.fdopen(out_tuple[0], 'r') as handle:
+		compressed = handle.read()
+	
+	os.unlink(in_tuple[1])
+	os.unlink(out_tuple[1])
+
+	return compressed
+
+
+def addHeader(text, endFilename):
+	with open(os.path.join('.', 'REVISION'), 'r') as handle:
+		revision = handle.read().rstrip()
+	
+	return ("// %s r%s - http://github.com/mrdoob/three.js\n" % (endFilename, revision)) + text
+
+
+def getAllFiles():
+	files = []
+	for k in ['core', 'cameras', 'io', 'lights', 'objects', 'materials', 'scenes', 'projector', 'renderers', 'renderables']:
+		files.extend(FILES[k])
+	return files
+
+
+def build(files, outputFilename):
+	print "=" * 40
+	print "Compiling", outputFilename
+	print "=" * 40
+
+	output(addHeader(compress(merge(files)), outputFilename), outputFilename)
+
+
+def buildFull():
+	build(getAllFiles(), 'Three.js')
+
+
+def buildCanvas():
+
+	files = getAllFiles()
+
+	files.remove('materials/ParticleDOMMaterial.js')
+	files.remove('renderers/DOMRenderer.js')
+	files.remove('renderers/SVGRenderer.js')
+	files.remove('renderers/WebGLRenderer.js')
+
+	build(files, 'ThreeCanvas.js')
+
+
+def buildWebGL():
+
+	files = getAllFiles()
+
+	files.remove('materials/ParticleDOMMaterial.js')
+	files.remove('renderers/Projector.js')
+	files.remove('renderers/DOMRenderer.js')
+	files.remove('renderers/CanvasRenderer.js')
+	files.remove('renderers/SVGRenderer.js')
+	
+	for f in FILES['renderables']:
+		files.remove(f)
+
+	build(files, 'ThreeWebGL.js')
+
+
+def buildSVG():
+
+	files = getAllFiles()
+
+	files.remove('materials/MeshPhongMaterial.js')
+	files.remove('materials/ParticleDOMMaterial.js')
+	files.remove('renderers/DOMRenderer.js')
+	files.remove('renderers/CanvasRenderer.js')
+	files.remove('renderers/WebGLRenderer.js')
+
+	build(files, 'ThreeSVG.js')
+
+
+def buildDOM():
+
+	files = []
+	for k in ['core', 'cameras', 'io', 'objects', 'scenes', 'projector']:
+		files.extend(FILES[k])
+	
+	files.remove('core/Geometry.js')
+	files.remove('objects/Line.js')
+	files.remove('objects/Mesh.js')
+	files.append('materials/ParticleDOMMaterial.js')
+	files.append('renderers/DOMRenderer.js')
+	files.append('renderers/renderables/RenderableParticle.js')
+
+	build(files, 'ThreeDOM.js')
+
+
+def buildDebug():
+
+	outputFilename = 'ThreeDebug.js'
+
+	print "=" * 40
+	print "Compiling", outputFilename
+	print "=" * 40
+
+	files = getAllFiles()
+	text = merge(files)
+
+	position = 0
+	while True:
+		position = text.find("/* DEBUG", position)
+		if position == -1:
+			break
+		text = text[0:position] + text[position+8:]
+		position = text.find("*/", position)
+		text = text[0:position] + text[position+2:]
+
+	output(addHeader(compress(text), outputFilename), outputFilename)
+
+
+def parse_args():
+
+	parser = argparse.ArgumentParser(description='Build and compress Three.js')
+	parser.add_argument('--full', help='Build Three.js', action='store_const', const=True, default=True)
+	parser.add_argument('--canvas', help='Build ThreeCanvas.js', action='store_true')
+	parser.add_argument('--webgl', help='Build ThreeWebGL.js', action='store_true')
+	parser.add_argument('--svg', help='Build ThreeSVG.js', action='store_true')
+	parser.add_argument('--dom', help='Build ThreeDOM.js', action='store_true')
+	parser.add_argument('--debug', help='Build ThreeDebug.js', action='store_true')
+	parser.add_argument('--all', help='Build all Three.js versions', action='store_true')
+
+	return parser.parse_args()
+
+
+def main(argv=None):
+
+	args = parse_args()
+
+	if args.full or args.all:
+		buildFull()
+
+	if args.canvas or args.all:
+		buildCanvas()
+
+	if args.webgl or args.all:
+		buildWebGL()
+
+	if args.svg or args.all:
+		buildSVG()
+
+	if args.dom or args.all:
+		buildDOM()
+
+	if args.debug or args.all:
+		buildDebug()
+
+
+if __name__ == "__main__":
+	main()
+