/**
* 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.jsr231;
import javax.media.opengl.GL;
import org.openmali.vecmath2.Colorf;
import org.openmali.vecmath2.Point3f;
import org.openmali.vecmath2.TexCoord1f;
import org.openmali.vecmath2.TexCoord2f;
import org.openmali.vecmath2.TexCoord3f;
import org.openmali.vecmath2.TexCoord4f;
import org.openmali.vecmath2.Vector3f;
import org.xith3d.render.CanvasPeer;
import org.xith3d.render.OpenGLCapabilities;
import org.xith3d.render.OpenGLStatesCache;
import org.xith3d.render.SceneGraphOpenGLReference;
import org.xith3d.render.SceneGraphOpenGLReferences;
import org.xith3d.render.preprocessing.ShapeAtom;
import org.xith3d.scenegraph.Geometry;
import org.xith3d.scenegraph.GeometryStripArray;
import org.xith3d.scenegraph.IndexedGeometryArray;
import org.xith3d.scenegraph.IndexedGeometryStripArray;
/**
* This shaderPeer is capable of recording and playing back a DisplayList.
*
* @author Marvin Froehlich (aka Qudus)
*/
public class DisplayListRenderPeer
{
private static final boolean USE_PRECOMPILED_DISPLAY_LISTS = true;
private static SceneGraphOpenGLReferences.Provider dlNameProvider = new SceneGraphOpenGLReferences.Provider()
{
public SceneGraphOpenGLReference newReference( CanvasPeer canvasPeer, SceneGraphOpenGLReferences references, int numNamesPerContext )
{
return ( new SceneGraphOpenGLReference( canvasPeer, references, numNamesPerContext )
{
@Override
public void prepareObjectForDestroy()
{
SceneGraphOpenGLReference ref = getReferences().removeReference( getContext().getCanvasID() );
( (CanvasPeerImplBase)getContext() ).addDestroyableObject( ref );
}
@Override
public void destroyObject( int index, int name )
{
final GL gl = ( (CanvasPeerImplBase)getContext() ).getGL();
gl.glDeleteLists( name, 1 );
}
} );
}
};
private static Point3f coord = new Point3f();
private static Vector3f normal = new Vector3f();
private static Colorf color = new Colorf();
private static TexCoord1f texCoord1 = new TexCoord1f();
private static TexCoord2f texCoord2 = new TexCoord2f();
private static TexCoord3f texCoord3 = new TexCoord3f();
private static TexCoord4f texCoord4 = new TexCoord4f();
private static final void drawGeometryArray( GL gl,
Geometry geom,
final int[] index,
final int startIndex,
final int endIndex,
final int mode,
@SuppressWarnings( "unused" ) final boolean isMinVersion13
)
{
gl.glBegin( mode );
for ( int i = startIndex; i <= endIndex; i++ )
{
final int i_ = ( index == null ) ? i : index[ i ];
if ( geom.hasNormals() )
{
geom.getNormal( i_, normal );
gl.glNormal3f( normal.getX(), normal.getY(), normal.getZ() );
}
if ( geom.hasColors() )
{
geom.getColor( i_, color );
if ( color.hasAlpha() )
gl.glColor4f( color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() );
else
gl.glColor3f( color.getRed(), color.getGreen(), color.getBlue() );
}
final int[] tuSetMap = geom.getTexCoordSetMap();
for ( int t = 0; t < tuSetMap.length; t++ )
{
final int unit = tuSetMap[ t ];
switch ( geom.getTexCoordSize( unit ) ) // this will return 0, if the texture unit is not used!
{
case 1:
geom.getTextureCoordinate( unit, i_, texCoord1 );
gl.glMultiTexCoord1f( unit, texCoord1.getS() );
break;
case 2:
geom.getTextureCoordinate( unit, i_, texCoord2 );
gl.glMultiTexCoord2f( unit, texCoord2.getS(), texCoord2.getT() );
break;
case 3:
geom.getTextureCoordinate( unit, i_, texCoord3 );
gl.glMultiTexCoord3f( unit, texCoord3.getS(), texCoord3.getT(), texCoord3.getP() );
break;
case 4:
geom.getTextureCoordinate( unit, i_, texCoord4 );
gl.glMultiTexCoord4f( unit, texCoord4.getS(), texCoord4.getT(), texCoord4.getP(), texCoord4.getQ() );
break;
}
}
geom.getCoordinate( i_, coord );
gl.glVertex3f( coord.getX(), coord.getY(), coord.getZ() );
}
gl.glEnd();
}
public static final void drawRegularGeometryArray( GL gl, Geometry geom, final int mode, final boolean isMinVersion13 )
{
final int[] index = null;
final int startIndex = geom.getInitialVertexIndex();
final int numIndices = geom.getValidVertexCount();
drawGeometryArray( gl, geom, index, startIndex, startIndex + numIndices - 1, mode, isMinVersion13 );
}
public static final void drawIndexedGeometryArray( GL gl, IndexedGeometryArray geom, final int mode, final boolean isMinVersion13 )
{
final int[] index = geom.getIndex();
final int startIndex = geom.getInitialIndexIndex();
final int numIndices = geom.getValidIndexCount();
drawGeometryArray( gl, geom, index, startIndex, startIndex + numIndices - 1, mode, isMinVersion13 );
}
public static final void drawGeometryStripArray( GL gl, GeometryStripArray geom, final int mode, final int stripsCount, final int[] stripVertexCounts, final boolean isMinVersion13 )
{
final int startIndex = geom.getInitialVertexIndex();
final int numIndices = geom.getValidVertexCount();
int i0 = 0;
for ( int strip = 0; strip < stripsCount; strip++ )
{
final int start = ( i0 >= startIndex ) ? i0 : startIndex;
int end = start + stripVertexCounts[ strip ] - 1;
if ( end + 1 > numIndices )
end = numIndices - 1;
if ( end < start )
break;
drawGeometryArray( gl, geom, null, start, end, mode, isMinVersion13 );
i0 += stripVertexCounts[ strip ];
}
}
public static final void drawIndexedGeometryStripArray( GL gl, IndexedGeometryStripArray geom, final int mode, final int stripsCount, final int[] stripVertexCounts, final boolean isMinVersion13 )
{
final int[] index = geom.getIndex();
final int startIndex = geom.getInitialIndexIndex();
final int numIndices = geom.getValidIndexCount();
int i0 = 0;
for ( int strip = 0; strip < stripsCount; strip++ )
{
final int start = ( i0 >= startIndex ) ? i0 : startIndex;
int end = start + stripVertexCounts[ strip ] - 1;
if ( end + 1 > numIndices )
end = numIndices - 1;
if ( end < start )
break;
drawGeometryArray( gl, geom, index, start, end, mode, isMinVersion13 );
i0 += stripVertexCounts[ strip ];
}
}
private static final int recordDisplayList( GL gl, ShapeAtom atom, Geometry geom, int dlName,
boolean useVertexArrayWorkaround, int texturesUseMap,
CanvasPeer canvasPeer, OpenGLCapabilities glCaps, OpenGLStatesCache statesCache
)
{
if ( dlName == -1 )
{
dlName = gl.glGenLists( 1 );
}
// Don't use COMPILE_AND_EXECUTE! It is MUCH faster to first compile and then playback afterwards.
if ( USE_PRECOMPILED_DISPLAY_LISTS )
gl.glNewList( dlName, GL.GL_COMPILE );
else
gl.glNewList( dlName, GL.GL_COMPILE_AND_EXECUTE );
if ( useVertexArrayWorkaround )
ShapeAtomPeer.renderWithForcedVertexArrays( gl, atom, texturesUseMap, geom, canvasPeer, glCaps, statesCache );
else
atom.lastComputedPolysCount = ShapeAtomPeer.drawBuffers( gl, geom, false, true, glCaps.isMinVersion13() );
gl.glEndList();
return ( dlName );
}
private static final void playbackDisplayList( GL gl, final int dlName )
{
gl.glCallList( dlName );
}
public static final void renderDisplayList( GL gl, ShapeAtom atom, Geometry geom, CanvasPeer canvasPeer,
OpenGLCapabilities glCaps, OpenGLStatesCache statesCache, boolean isNormalRenderMode
)
{
SceneGraphOpenGLReference openGLRef = geom.getOpenGLReference_DL().getReference( canvasPeer, dlNameProvider );
// ATI- and Intel-cards don't like plain-OpenGL-Multi-Texturing.
final boolean useVertexArrayWorkaround = !glCaps.supportsPlainMultiTexturing() || geom.hasVertexAttributes();
int texturesUseMap = 0;
if ( useVertexArrayWorkaround )
{
texturesUseMap = ShapeAtomPeer.setStates( gl, geom, glCaps, statesCache, isNormalRenderMode, ShapeAtomPeer.CARE_MAP_ALL );
}
if ( !openGLRef.nameExists() )
{
openGLRef.setName( recordDisplayList( gl, atom, geom, -1, useVertexArrayWorkaround, texturesUseMap, canvasPeer, glCaps, statesCache ) );
}
else if ( !openGLRef.isNameValid() )
{
final int dlName = openGLRef.getName();
recordDisplayList( gl, atom, geom, dlName, useVertexArrayWorkaround, texturesUseMap, canvasPeer, glCaps, statesCache );
openGLRef.setName( dlName );
if ( USE_PRECOMPILED_DISPLAY_LISTS )
playbackDisplayList( gl, dlName );
}
else
{
final int dlName = openGLRef.getName();
playbackDisplayList( gl, dlName );
}
}
}