/*
Moo3D - A MooTools class that helps render basic 3D with JavaScript
Copyright (C) 2010 Hadrien Jouet @ Grownseed

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 3 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, see <http://www.gnu.org/licenses/>.

[ slitghly modified for purposes of the adbox website ]
*/

var Moo3D = new Class(
{
	options:
	{
		rotationAxis:
		{
			x: 0,
			y: 0,
			z: 0
		},
		camera:
		{
			x: 0,
			y: 0,
			z: 0,
			focalLength: 1000
		},
		origins:
		{
			x: 0,
			y: 0
		}
	},
	
	initialize: function(options)
	{
		this.setOptions(options);
		this.objects = [];
	},
	
	/*
	 * Add an Object:
	 * An object is a series of none or more 3D points
	 */
	add: function(object)
	{
		object = this.transform3DPointsTo2DPoints(object);
		
		//complete object's points
		object.each(function(point)
		{
			if (!$defined(point.modifiers))
				point.modifiers = {};
			
			if (!$defined(point.modifiers.left))
				point.modifiers.left = function(){return this.projection.x;};
			if (!$defined(point.modifiers.top))
				point.modifiers.top = function(){return this.projection.y;};
			
			point.modifiers.position = 'absolute';
			
			point.modifiers = new Hash(point.modifiers);
		}.bind(this));
		
		this.objects.push(object);
	},
	
	transform3DPointsTo2DPoints: function(points)
	{
		var transformedPoints = [];
		var sx = Math.sin(this.options.rotationAxis.x);
		var cx = Math.cos(this.options.rotationAxis.x);
		var sy = Math.sin(this.options.rotationAxis.y);
		var cy = Math.cos(this.options.rotationAxis.y);
		var sz = Math.sin(this.options.rotationAxis.z);
		var cz = Math.cos(this.options.rotationAxis.z);
		
		var x, y, z, xy, xz, yx, yz, zx, zy, scale;
		
		var i = points.length;
		
		while (i--)
		{	
			x = points[i].x - this.options.camera.x;
			y = points[i].y - this.options.camera.y;
			z = points[i].z - this.options.camera.z;
			
			//rotation around x
			xy = cx*y - sx*z;
			xz = sx*y + cx*z;
			//rotation around y
			yz = cy*xz - sy*x;
			yx = sy*xz + cy*x;
			//rotation around z
			zx = cz*yx - sz*xy;
			zy = sz*yx + cz*xy;
			
			scale = this.options.camera.focalLength / (this.options.camera.focalLength + yz);
			
			points[i].projection =
			{
				scale: scale,
				x: Math.round(zx * scale),
				y: Math.round(zy * scale),
				depth: -yz
			};
		}
		
		return points;
	},
	
	/*
	 * render points' properties.
	 * if object is passed, then only that object's points will be updated,
	 * otherwise all objects' points will be updated
	 */
	render: function(object)
	{
		var objects;
		
		if ($defined(object))
			objects = [object];
		else
			objects = this.objects;
		
		objects.each(function(obj)
		{
			
			obj = this.transform3DPointsTo2DPoints(obj);
			
			obj.each(function(point)
			{
				if (point.animating) return false;
				point.modifiers.each(function(value, style)
				{
					point.element.setStyle(style, ($type(value) == 'function' ? value.attempt([], point) : value));
				});
			});
		}.bind(this));
	}
});

Moo3D.implement(new Options);
