/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.render;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.jagatoo.logging.LogLevel;
import org.jagatoo.logging.ProfileTimer;
import org.openmali.vecmath2.Point3f;
import org.xith3d.picking.PickPool;
import org.xith3d.picking.PickRequest;
import org.xith3d.picking.PickResult;
import org.xith3d.render.preprocessing.FrustumCuller;
import org.xith3d.render.preprocessing.sorting.FrontToBackRenderBinSorter;
import org.xith3d.render.preprocessing.sorting.OrderedStateRenderBinSorter;
import org.xith3d.render.preprocessing.sorting.RenderBinSorter;
import org.xith3d.scenegraph.BranchGroup;
import org.xith3d.scenegraph.GroupNode;
import org.xith3d.scenegraph.SceneGraph;
import org.xith3d.scenegraph.Transform3D;
import org.xith3d.scenegraph.View;
import org.xith3d.scenegraph._SG_PrivilegedAccess;
import org.xith3d.scenegraph.modifications.ScenegraphModificationsListener;
import org.xith3d.sound.SoundProcessor;
import org.xith3d.utility.logging.X3DLog;
/**
* The Renderer is the main class for managing the transformation from the
* scene graph to the 3D card. The Renderer is in charge of atom shader
* sorting, transparency passes, etc.<br>
* <br>
* The actual OpenGL calls are made by the rendering peer which is
* supplied when the renderer is created. The renderer supports several different
* modes of operation including offscreen, render to texture, render to image and
* rendering to screen.
*
* @author David Yazel
* @author Marvin Froehlich (aka Qudus)
* @author Amos Wenger (aka BlueSky) [code cleaning, documentation]
*/
public class DefaultRenderer extends Renderer
{
private static final FrontToBackRenderBinSorter frontToBackSorter = new FrontToBackRenderBinSorter();
private RenderBinSorter opaqueRenderBinSorter = new OrderedStateRenderBinSorter();
private RenderBinSorter transparentRenderBinSorter = new FrontToBackRenderBinSorter();
private OpaqueSortingPolicy opaqueSortingPolicy = OpaqueSortingPolicy.SORT_BY_STATES;
private TransparentSortingPolicy transparentSortingPolicy = TransparentSortingPolicy.SORT_FRONT_TO_BACK;
private final FrustumCuller frustumCuller;
private final ScenegraphModificationsManager modManager;
private final ArrayList< ScenegraphModificationsListener > modListeners;
private final ArrayList< Canvas3D > canvasList;
private final ArrayList< RenderTarget > renderTargets;
private final HashMap< RenderTarget, RenderPass > renderTargetRenderPassMap = new HashMap< RenderTarget, RenderPass >();
private final ArrayList< RenderPass > renderPasses;
private final ArrayList< RenderPass > tmpRenderPasses;
private final ArrayList< RenderPass > tmpRenderPasses2;
private final ArrayList< RenderPass > effectiveRenderPasses;
private final ArrayList< ArrayList< GroupNode >> tmpGroupsListsLists;
private final ArrayList< GroupNode > tmpGroupList;
private boolean layeredMode = false;
private Point3f viewPosition2 = new Point3f();
private List< PickRequest > pickRequests;
private boolean recullForced = false;
private long frameId = 0L;
private volatile boolean isRendering;
private long shapesRendered = 0;
private long trianglesRendered = 0;
/**
* {@inheritDoc}
*/
@Override
public final SoundProcessor getSoundProcessor()
{
return ( SoundProcessor.getInstance() );
}
public ScenegraphModificationsManager getScenegraphModificationsManager()
{
return ( modManager );
}
/**
* {@inheritDoc}
*/
@Override
public void addScenegraphModificationListener( ScenegraphModificationsListener modListener )
{
modListeners.add( modListener );
}
/**
* {@inheritDoc}
*/
@Override
public void removeScenegraphModificationListener( ScenegraphModificationsListener modListener )
{
modListeners.remove( modListener );
}
/**
* {@inheritDoc}
*/
@Override
public List< ScenegraphModificationsListener > getScenegraphModificationListeners()
{
return ( modListeners );
}
/**
* {@inheritDoc}
*/
@Override
protected final void addCanvas3D( Canvas3D canvas )
{
canvasList.add( canvas );
canvas.setRenderer( this );
}
/**
* {@inheritDoc}
*/
@Override
protected final void removeCanvas3D( Canvas3D canvas )
{
canvasList.remove( canvas );
canvas.setRenderer( null );
}
/**
* {@inheritDoc}
*/
@Override
protected final Canvas3D removeCanvas3D( int i )
{
final Canvas3D canvas = canvasList.remove( i );
canvas.setRenderer( null );
return ( canvas );
}
/**
* {@inheritDoc}
*/
@Override
public final int getNumberOfCanvas3Ds()
{
return ( canvasList.size() );
}
/**
* {@inheritDoc}
*/
@Override
public final Canvas3D getCanvas3D( int index )
{
return ( canvasList.get( index ) );
}
/**
* {@inheritDoc}
*/
@Override
public final void addRenderTarget( RenderTarget renderTarget, RenderPass renderPass )
{
renderTargets.add( renderTarget );
renderPass.setRenderTarget( renderTarget );
renderTargetRenderPassMap.put( renderTarget, renderPass );
}
/**
* {@inheritDoc}
*/
@Override
public final RenderPass addRenderTarget( RenderTarget renderTarget, RenderPassConfig passConfig )
{
RenderPass pass = new RenderPass( passConfig );
addRenderTarget( renderTarget, pass );
return ( pass );
}
/**
* {@inheritDoc}
*/
@Override
public final void removeRenderTarget( RenderTarget renderTarget )
{
renderTargets.remove( renderTarget );
renderTargetRenderPassMap.remove( renderTarget );
}
/**
* {@inheritDoc}
*/
@Override
public List< RenderTarget > getRenderTargets()
{
return ( renderTargets );
}
/**
* {@inheritDoc}
*/
@Override
protected final RenderPass addRenderPass( RenderPass renderPass )
{
if ( renderPass == null )
throw new IllegalArgumentException( "renderPass must not be null." );
renderPasses.add( renderPass );
return ( renderPass );
}
/**
* {@inheritDoc}
*/
@Override
protected final RenderPass addRenderPass( int index, RenderPass renderPass )
{
if ( renderPass == null )
throw new IllegalArgumentException( "renderPass must not be null." );
renderPasses.add( index, renderPass );
return ( renderPass );
}
/**
* {@inheritDoc}
*/
@Override
protected final boolean removeRenderPasses( BranchGroup branchGroup )
{
final List< RenderPass > passes = getRenderPasses( branchGroup );
int n = 0;
for ( int i = 0; i < passes.size(); i++ )
{
if ( renderPasses.remove( passes.get( i ) ) )
n++;
}
return ( n > 0 );
}
/**
* {@inheritDoc}
*/
@Override
protected final boolean removeRenderPass( RenderPass renderPass )
{
return ( removeRenderPasses( renderPass.getBranchGroup() ) );
}
/**
* {@inheritDoc}
*/
@Override
protected final boolean removeRenderPass( int index )
{
final RenderPass removedPass = renderPasses.remove( index );
return ( removedPass != null );
}
/**
* {@inheritDoc}
*/
@Override
protected void removeAllRenderPasses()
{
renderPasses.clear(); // TODO: handle map?
}
/**
* {@inheritDoc}
*/
@Override
public final int getRenderPassesCount()
{
return ( renderPasses.size() );
}
/**
* {@inheritDoc}
*/
@Override
public final List< RenderPass > getRenderPasses( BranchGroup branchGroup )
{
tmpRenderPasses2.clear();
for ( int i = 0; i < renderPasses.size(); i++ )
{
final RenderPass rp = renderPasses.get( i );
if ( rp.getBranchGroup() == branchGroup )
tmpRenderPasses2.add( rp );
}
return ( tmpRenderPasses2 );
}
/**
* {@inheritDoc}
*/
@Override
public final RenderPass getRenderPass( int index )
{
return ( renderPasses.get( index ) );
}
/**
* {@inheritDoc}
*/
@Override
public final List< RenderPass > getRenderPasses()
{
return ( renderPasses );
}
/**
* {@inheritDoc}
*/
@Override
public final void setLayeredMode( boolean layeredMode )
{
this.layeredMode = layeredMode;
}
/**
* {@inheritDoc}
*/
@Override
public final boolean isLayeredMode()
{
return ( layeredMode );
}
/**
* {@inheritDoc}
*/
@Override
public final void setOpaqueSorter( RenderBinSorter sorter )
{
this.opaqueRenderBinSorter = sorter;
this.opaqueSortingPolicy = OpaqueSortingPolicy.CUSTOM;
}
/**
* {@inheritDoc}
*/
@Override
public final RenderBinSorter getOpaqueSorter()
{
return ( opaqueRenderBinSorter );
}
/**
* {@inheritDoc}
*/
@Override
public final void setTransparentSorter( RenderBinSorter sorter )
{
this.transparentRenderBinSorter = sorter;
this.transparentSortingPolicy = TransparentSortingPolicy.CUSTOM;
}
/**
* {@inheritDoc}
*/
@Override
public final RenderBinSorter getTransparentSorter()
{
return ( transparentRenderBinSorter );
}
/**
* {@inheritDoc}
*/
@Override
public final void setOpaqueSortingPolicy( OpaqueSortingPolicy policy )
{
this.opaqueRenderBinSorter = policy.getSorter();
this.opaqueSortingPolicy = policy;
}
/**
* {@inheritDoc}
*/
@Override
public final OpaqueSortingPolicy getOpaqueSortingPolicy()
{
return ( opaqueSortingPolicy );
}
/**
* {@inheritDoc}
*/
@Override
public final void setTransparentSortingPolicy( TransparentSortingPolicy policy )
{
this.transparentRenderBinSorter = policy.getSorter();
this.transparentSortingPolicy = policy;
}
/**
* {@inheritDoc}
*/
@Override
public final TransparentSortingPolicy getTransparentSortingPolicy()
{
return ( transparentSortingPolicy );
}
/**
* {@inheritDoc}
*/
@Override
protected void addPickRequest( PickRequest pickRequest )
{
synchronized ( pickRequests )
{
pickRequests.add( pickRequest );
}
}
/**
* Sorts all atoms according to the current policies.
*
* @param pass
* @param viewTransform
*/
private final void sortAllAtoms( RenderPass pass, Transform3D viewTransform )
{
final RenderPassConfig passConfig = pass.getConfig();
RenderBinSorter opaqueSorter;
RenderBinSorter transparentSorter;
if ( passConfig != null )
{
opaqueSorter = passConfig.getOpaqueSorter();
transparentSorter = passConfig.getTransparentSorter();
if ( passConfig.getOpaqueSortingPolicy() == null )
opaqueSorter = this.getOpaqueSorter();
if ( passConfig.getTransparentSortingPolicy() == null )
transparentSorter = this.getTransparentSorter();
}
else
{
opaqueSorter = this.getOpaqueSorter();
transparentSorter = this.getTransparentSorter();
}
pass.getRenderBinProvider().sortAllAtoms( opaqueSorter, transparentSorter, viewTransform );
}
protected Object doRender( List< RenderPass > renderPasses, Canvas3D canvas, long frameId, long nanoTime, long nanoStep, PickRequest pickRequest )
{
// block until the rendering is finished...
while ( canvas.getPeer().isRendering() )
{
try
{
Thread.sleep( 10L );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
return ( canvas.getPeer().initRenderingImpl( canvas.getView(), renderPasses, layeredMode, frameId, nanoTime, nanoStep, pickRequest ) );
}
/**
* Renders one frame from a specified universe and on a canvas.
*
* @param universe
* @param canvas
*/
private Object renderOnceInternal( List< RenderPass > renderPasses, List< ? extends List< GroupNode > > groupLists, Canvas3D canvas, long nanoTime, long nanoStep, PickRequest pickRequest )
{
Object result;
synchronized ( canvas.getPeer().getRenderLock() )
{
frameId++;
canvas.checkForResized();
X3DLog.println("\nSTARTING FRAME\n" );
shapesRendered = 0L;
trianglesRendered = 0L;
isRendering = true;
final OpenGLCapabilities glCaps = canvas.getPeer().getOpenGLCapabilities();
ProfileTimer.startProfile( X3DLog.LOG_CHANNEL, "Renderer:renderOnce" );
if ( ( groupLists != null ) && modManager.hasAnythingChanged() )
{
for ( int i = 0; i < groupLists.size(); i++ )
{
final List< GroupNode > groups = groupLists.get( i );
for ( int j = 0; j < groups.size(); j++ )
{
final GroupNode group = groups.get( j );
group.setModListener( modManager );
/*
if ( ( group instanceof BranchGroup ) && ( (BranchGroup)group ).isRefillForeced() )
{
// collect
atomsCollector.collectAtoms( renderPasses, groupLists, modManager, soundProcessor, glCaps );
}
*/
}
}
}
else if ( ( renderPasses != null ) && modManager.hasAnythingChanged() )
{
for ( int i = 0; i < renderPasses.size(); i++ )
{
final RenderPass renderPass = renderPasses.get( i );
final BranchGroup bg = renderPass.getBranchGroup();
bg.setModListener( modManager );
/*
if ( bg.isRefillForeced() )
{
// collect
atomsCollector.collectAtoms( renderPasses, modManager, soundProcessor, glCaps );
}
*/
}
}
final Point3f viewPosition = canvas.getView().getPosition();
List< RenderPass > rps = renderPasses;
if ( pickRequest == null )
{
if ( renderTargets.size() > 0 )
{
effectiveRenderPasses.clear();
for ( int i = 0; i < renderTargets.size(); i++ )
{
final RenderTarget renderTarget = renderTargets.get( i );
final RenderPass renderPass = renderTargetRenderPassMap.get( renderTarget );
// notify the RenderCallbacks, if any
renderPass.getRenderCallbackNotifier().notifyBeforeRenderPassIsProcessed( renderPass );
final Point3f viewPos;
if ( renderPass.getConfig().getViewTransform() == null )
{
viewPos = viewPosition;
}
else
{
renderPass.getConfig().getViewTransform().getTranslation( viewPosition2 );
viewPos = viewPosition2;
}
frustumCuller.cullAtoms( renderPass, renderTarget.getGroup(), canvas, viewPos, glCaps, frameId, nanoTime, nanoStep, null );
effectiveRenderPasses.add( renderPass );
// notify the RenderCallbacks, if any
renderPass.getRenderCallbackNotifier().notifyAfterRenderPassIsProcessed( renderPass );
}
for ( int j = 0; j < renderPasses.size(); j++ )
{
effectiveRenderPasses.add( renderPasses.get( j ) );
}
rps = effectiveRenderPasses;
}
// cull
shapesRendered = frustumCuller.cullAtoms( renderPasses, groupLists, canvas, glCaps, frameId, nanoTime, nanoStep, null );
trianglesRendered = canvas.getPeer().getTriangles();
// sort
for ( int i = 0; i < rps.size(); i++ )
{
final RenderPass renderPass = rps.get( i );
final Transform3D viewTransform;
if ( renderPass.getConfig().getViewTransform() == null )
viewTransform = canvas.getView().getTransform();
else
viewTransform = renderPass.getConfig().getViewTransform();
sortAllAtoms( renderPass, viewTransform );
}
modManager.resetAnythingChanged();
_SG_PrivilegedAccess.setChanged( canvas.getView().getTransform(), false );
recullForced = false;
}
else if ( ( modManager.hasAnythingChanged() ) || ( canvas.getView().getTransform().isChanged() ) || ( recullForced ) )
{
// cull
frustumCuller.cullAtoms( (RenderPass)null, (GroupNode)null, canvas, viewPosition, glCaps, frameId, nanoTime, nanoStep, pickRequest );
// sort
for ( int i = 0; i < pickRequest.getRenderPasses().size(); i++ )
{
final RenderPass renderPass = pickRequest.getRenderPasses().get( i );
// notify the RenderCallbacks, if any
renderPass.getRenderCallbackNotifier().notifyBeforeRenderPassIsProcessed( renderPass );
final Transform3D viewTransform;
if ( renderPass.getConfig().getViewTransform() == null )
viewTransform = canvas.getView().getTransform();
else
viewTransform = renderPass.getConfig().getViewTransform();
renderPass.getRenderBinProvider().sortAllAtoms( frontToBackSorter, frontToBackSorter, viewTransform );
// notify the RenderCallbacks, if any
renderPass.getRenderCallbackNotifier().notifyAfterRenderPassIsProcessed( renderPass );
}
}
if ( pickRequest == null )
result = doRender( rps, canvas, frameId, nanoTime, nanoStep, pickRequest );
else
result = doRender( pickRequest.getRenderPasses(), canvas, frameId, nanoTime, nanoStep, pickRequest );
ProfileTimer.endProfile();
isRendering = false;
}
canvas.getPeer().finish();
return ( result );
}
@SuppressWarnings( "unchecked" )
private final long performPickings( Canvas3D canvas, long nanoTime, long nanoStep )
{
synchronized ( pickRequests )
{
for ( int i = 0; i < pickRequests.size(); i++ )
{
final long t0 = System.nanoTime();
final PickRequest pickRequest = pickRequests.get( i );
Object resultObj = renderOnceInternal( null, null, canvas, nanoTime, nanoStep, pickRequest );
final long dt = System.nanoTime() - t0;
final long dtm = dt / 1000000L;
if ( pickRequest.getPickAll() )
{
final List< PickResult > results = (List< PickResult >)resultObj;
if ( ( results == null ) || ( results.size() == 0 ) )
pickRequest.getAllPickListener().onPickingMissed( pickRequest.getUserObject(), dtm );
else
pickRequest.getAllPickListener().onObjectsPicked( results, pickRequest.getUserObject(), dtm );
}
else
{
final PickResult result = (PickResult)resultObj;
if ( result == null )
pickRequest.getNearestPickListener().onPickingMissed( pickRequest.getUserObject(), dtm );
else
pickRequest.getNearestPickListener().onObjectPicked( result, pickRequest.getUserObject(), dtm );
}
PickPool.deallocatePickRequest( pickRequest );
}
pickRequests.clear();
recullForced = true;
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( List< RenderPass > renderPasses, List< ? extends List< GroupNode >> groupsLists, Canvas3D canvas, long nanoTime, long nanoStep )
{
synchronized ( this )
{
if ( !pickRequests.isEmpty() )
{
performPickings( canvas, nanoTime, nanoStep );
}
renderOnceInternal( renderPasses, groupsLists, canvas, nanoTime, nanoStep, null );
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( RenderPass renderPass, GroupNode group, Canvas3D canvas, long nanoTime, long nanoStep )
{
synchronized ( this )
{
if ( !pickRequests.isEmpty() )
{
performPickings( canvas, nanoTime, nanoStep );
}
tmpRenderPasses.clear();
tmpRenderPasses.add( renderPass );
if ( group == null )
{
renderOnceInternal( tmpRenderPasses, null, canvas, nanoTime, nanoStep, null );
}
else
{
tmpGroupsListsLists.clear();
tmpGroupList.clear();
tmpGroupList.add( group );
tmpGroupsListsLists.add( tmpGroupList );
renderOnceInternal( tmpRenderPasses, tmpGroupsListsLists, canvas, nanoTime, nanoStep, null );
}
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( RenderPass renderPass, Canvas3D canvas, long nanoTime, long nanoStep )
{
return ( renderOnce( renderPass, null, canvas, nanoTime, nanoStep ) );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( Canvas3D canvas, long nanoTime, long nanoStep )
{
synchronized ( this )
{
if ( !pickRequests.isEmpty() )
{
performPickings( canvas, nanoTime, nanoStep );
}
renderOnceInternal( renderPasses, (List< List< GroupNode >>)null, canvas, nanoTime, nanoStep, null );
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( View view, long nanoTime, long nanoStep )
{
final int n = view.getCanvas3Ds().size();
for ( int i = 0; i < n; i++ )
{
renderOnce( view.getCanvas3D( i ), nanoTime, nanoStep );
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( RenderPass renderPass, GroupNode group, long nanoTime, long nanoStep )
{
final SceneGraph sg;
if ( group == null )
sg = renderPass.getBranchGroup().getSceneGraph();
else
sg = group.getRoot().getSceneGraph();
final int nv = sg.getNumberOfViews();
for ( int i = 0; i < nv; i++ )
{
renderOnce( sg.getView( i ), nanoTime, nanoStep );
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( RenderPass renderPass, long nanoTime, long nanoStep )
{
final SceneGraph sg = renderPass.getBranchGroup().getSceneGraph();
final int nv = sg.getNumberOfViews();
for ( int i = 0; i < nv; i++ )
{
renderOnce( sg.getView( i ), nanoTime, nanoStep );
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long renderOnce( long nanoTime, long nanoStep )
{
synchronized ( this )
{
final Canvas3D firstCanvas = canvasList.get( 0 );
if ( !pickRequests.isEmpty() )
{
performPickings( firstCanvas, nanoTime, nanoStep );
}
final int nc = canvasList.size();
for ( int i = 0; i < nc; i++ )
{
renderOnceInternal( renderPasses, (List< List< GroupNode >>)null, canvasList.get( i ), nanoTime, nanoStep, null );
}
}
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public long getLastFrameId()
{
return ( frameId );
}
/**
* {@inheritDoc}
*/
@Override
public final long getNumRenderedShapes()
{
return ( shapesRendered );
}
/**
* {@inheritDoc}
*/
@Override
public final long getNumRenderedTriangles()
{
return ( trianglesRendered );
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRendering()
{
return ( isRendering );
}
/**
* Creates a new Renderer.
*/
public DefaultRenderer()
{
this.frustumCuller = new FrustumCuller();
this.modManager = new ScenegraphModificationsManager( this );
this.modListeners = new ArrayList< ScenegraphModificationsListener >( 1 );
this.canvasList = new ArrayList< Canvas3D >();
this.renderTargets = new ArrayList< RenderTarget >();
this.renderPasses = new ArrayList< RenderPass >();
this.tmpRenderPasses = new ArrayList< RenderPass >();
this.tmpRenderPasses2 = new ArrayList< RenderPass >();
this.effectiveRenderPasses = new ArrayList< RenderPass >();
this.tmpGroupsListsLists = new ArrayList< ArrayList< GroupNode > >();
this.tmpGroupList = new ArrayList< GroupNode >( 1 );
this.pickRequests = new ArrayList< PickRequest >();
}
}