package necro
{	
	import flash.utils.*;

	public class BasicRenderer implements IRenderer
	{
		private var filters:Array;
		private var filter:IPrimitiveFilter;
		private var scene:Scene3D;
		private var camera:Camera3D;
		private var projtraverser:ProjectionTraverser = new ProjectionTraverser();
		private var blockerarray:BlockerArray = new BlockerArray();
		private var blocktraverser:BlockerTraverser = new BlockerTraverser();
		private var blockers:Array;
		private var priarray:PrimitiveArray = new PrimitiveArray();
		private var lightarray:LightArray = new LightArray();
		private var pritraverser:PrimitiveTraverser = new PrimitiveTraverser();
		private var primitives:Array;
		private var materials:Dictionary;
		private var primitive:DrawPrimitive;
		private var triangle:DrawTriangle;
		private var object:Object;
		private var clip:Clipping;
		private var _session:AbstractRenderSession;

		public function get session():AbstractRenderSession
		{
			return _session;
		}
		
		public function set session(value:AbstractRenderSession):void
		{
			_session = value;
		}

		public function BasicRenderer(...filters)
		{
			this.filters = filters;
			this.filters.push(new ZSortFilter());
		}

		public function render(view:View3D):Array
		{
			scene = view.scene;
			camera = view.camera;
			clip = view.clip;
			projtraverser.view = view;
			scene.traverse(projtraverser);
			blockerarray.clip = clip;
			blocktraverser.consumer = blockerarray;
			blocktraverser.view = view;
			scene.traverse(blocktraverser);
			blockers = blockerarray.list();
			lightarray.clear();
			_session.lightarray = lightarray;
			priarray.clip = clip;
			priarray.blockers = blockers;
			pritraverser.consumer = priarray;
			pritraverser.session = _session;
			scene.traverse(pritraverser);
			primitives = priarray.list();
			for each (filter in filters)
			primitives = filter.filter(primitives, scene, camera, clip);
			materials = new Dictionary(true);
			for each (primitive in primitives) {
				if(primitive is DrawTriangle) {
					triangle = primitive as DrawTriangle;
					if (!materials[triangle.source]) {
						materials[triangle.source] = new Dictionary(true);
					}
					if (triangle.material is IUpdatingMaterial && !materials[triangle.source][triangle.material]) {
						materials[triangle.source][triangle.material] = (triangle.material as IUpdatingMaterial);
						materials[triangle.source][triangle.material].updateMaterial(triangle.source, view);
					}
				}
			
			}
			for each (primitive in primitives) {
				primitive.render();
			}
			return primitives;
		}

		public function toString():String
		{
			return "Basic ["+filters.join("+")+"]";
		}
	}
}