package org.papervision3d.render
{
/**
* @Author Ralph Hauwert
*/
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.core.clipping.draw.Clipping;
import org.papervision3d.core.clipping.draw.RectangleClipping;
import org.papervision3d.core.proto.CameraObject3D;
import org.papervision3d.core.proto.SceneObject3D;
import org.papervision3d.core.render.IRenderEngine;
import org.papervision3d.core.render.command.RenderableListItem;
import org.papervision3d.core.render.data.QuadTree;
import org.papervision3d.core.render.data.RenderSessionData;
import org.papervision3d.core.render.data.RenderStatistics;
import org.papervision3d.core.render.filter.AbstractQuadrantFilter;
import org.papervision3d.core.render.filter.BasicRenderFilter;
import org.papervision3d.core.render.filter.QuadrantFilter;
import org.papervision3d.core.render.filter.QuadrantZFilter;
import org.papervision3d.core.render.material.MaterialManager;
import org.papervision3d.core.render.project.BasicProjectionPipeline;
import org.papervision3d.core.render.sort.BasicRenderSorter;
import org.papervision3d.core.utils.StopWatch;
import org.papervision3d.events.RendererEvent;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.view.layer.ViewportLayer;
/**
* BasicRenderEngine links Viewport3Ds,
* Scene3D, and Camera3Ds together
* by gathering in all of their data, rendering the data, then calling the
* necessary functions to update from the rendered data
*/
public class QuadrantRenderEngine extends BasicRenderEngine implements IRenderEngine
{
public var quadTree:QuadTree = new QuadTree();
private var clip:Clipping;
//private var quadFilter:AbstractQuadrantFilter;// = new QuadrantFilter();
public var quadFilters:Array = [];
public static var CORRECT_Z_FILTER:Number = 0x01;
public static var QUAD_SPLIT_FILTER:Number = 0x02;
public static var ALL_FILTERS:Number = CORRECT_Z_FILTER + QUAD_SPLIT_FILTER;
/**
* Creates and prepares all the objects and events needed for rendering
*/
public function QuadrantRenderEngine(type:Number = 3):void
{
if(type & QUAD_SPLIT_FILTER){
quadFilters.push(new QuadrantFilter());
}
if(type & CORRECT_Z_FILTER){
quadFilters.push(new QuadrantZFilter());
}
init();
}
/** @private */
protected override function init():void
{
renderStatistics = new RenderStatistics();
projectionPipeline = new BasicProjectionPipeline();
stopWatch = new StopWatch();
sorter = new BasicRenderSorter();
filter = new BasicRenderFilter();
renderList = new Array();
clipping = null;
clip = new Clipping();
renderSessionData = new RenderSessionData();
renderSessionData.renderer = this;
projectionDoneEvent = new RendererEvent(RendererEvent.PROJECTION_DONE, renderSessionData);
renderDoneEvent = new RendererEvent(RendererEvent.RENDER_DONE, renderSessionData);
}
/**
* Takes the data from the scene, camera, and viewport, renders it, then updates the viewport
*
* @param camera The CameraObject3D looking at the scene
* @param scene The Scene3D holding the DisplayObject3D's you want rendered
* @param viewPort The Viewport3D that will display your scene
*
* @return RenderStatistics The RenderStatistics objectholds all the data from the last render
*/
override public function renderScene(scene:SceneObject3D, camera:CameraObject3D, viewPort:Viewport3D):RenderStatistics
{
// Set the camera's viewport so it can resize its frustum.
camera.viewport = viewPort.sizeRectangle;
//Update the renderSessionData object.
renderSessionData.scene = scene;
renderSessionData.camera = camera;
renderSessionData.viewPort = viewPort;
renderSessionData.container = viewPort.containerSprite;
renderSessionData.triangleCuller = viewPort.triangleCuller;
renderSessionData.particleCuller = viewPort.particleCuller;
renderSessionData.renderObjects = scene.objects;
renderSessionData.renderLayers = null;
renderSessionData.renderStatistics.clear();
renderSessionData.clipping = clipping;
renderSessionData.quadrantTree = quadTree;
//quadFilter = new QuadrantFilter();
quadTree.clip = clip;
if(clipping)
clipping.reset(renderSessionData);
//Clear the viewport.
viewPort.updateBeforeRender(renderSessionData);
//Project the Scene (this will fill up the renderlist).
projectionPipeline.project(renderSessionData);
if(hasEventListener(RendererEvent.PROJECTION_DONE)){
dispatchEvent(projectionDoneEvent);
}
//Render the Scene. TODO: delete null if layers is deleted from doRender
doRender(renderSessionData, null);
if(hasEventListener(RendererEvent.RENDER_DONE)){
dispatchEvent(renderDoneEvent);
}
return renderSessionData.renderStatistics;
}
/** @private */
private function getLayerObjects(layers:Array):Array{
var array:Array = new Array();
for each (var vpl:ViewportLayer in layers){
array = array.concat(vpl.getLayerObjects());
}
return array;
}
//TODO: layers parameter isn't used. Delete?
/** @private */
protected override function doRender(renderSessionData:RenderSessionData, layers:Array = null):RenderStatistics
{
stopWatch.reset();
stopWatch.start();
//Update Materials.
MaterialManager.getInstance().updateMaterialsBeforeRender(renderSessionData);
//Filter the list
filter.filter(renderList);
clip = new RectangleClipping(-renderSessionData.viewPort.viewportWidth/2, -renderSessionData.viewPort.viewportHeight/2, renderSessionData.viewPort.viewportWidth/2, renderSessionData.viewPort.viewportHeight/2);//new Clipping();
for each(var qf:AbstractQuadrantFilter in quadFilters){
qf.filterTree(quadTree, Scene3D(renderSessionData.scene), Camera3D(renderSessionData.camera), clip);
}
quadTree.render(renderSessionData, renderSessionData.viewPort.containerSprite.graphicsChannel);
//Update Materials
MaterialManager.getInstance().updateMaterialsAfterRender(renderSessionData);
renderSessionData.renderStatistics.renderTime = stopWatch.stop();
renderSessionData.viewPort.updateAfterRender(renderSessionData);
return renderStatistics;
}
override public function addToRenderList(renderCommand:RenderableListItem):int{
quadTree.add(renderCommand);
return 1;
}
}
}