/**
* 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.lwjgl;
import java.nio.IntBuffer;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.openmali.types.twodee.Rect2i;
import org.xith3d.picking.PickRequest;
import org.xith3d.render.CanvasPeer;
import org.xith3d.render.OpenGLCapabilities;
import org.xith3d.render.OpenGLInfo;
import org.xith3d.render.OpenGlExtensions;
import org.xith3d.render.RenderPass;
import org.xith3d.render.SceneGraphOpenGLReference;
import org.xith3d.render.config.DisplayMode;
import org.xith3d.render.config.FSAA;
import org.xith3d.render.config.DisplayMode.FullscreenMode;
import org.xith3d.scenegraph.View;
import org.xith3d.utility.logging.X3DLog;
/**
* The CanvasPeer base implementation for the LightWeight Java Game Library (LWJGL)
*
* @author David Yazel
* @author Marvin Froehlich (aka Qudus)
* @author Amos Wenger (aka BlueSky)
*/
public abstract class CanvasPeerImplBase extends CanvasPeer
{
protected static Boolean DEBUG_GL = null;
private Rect2i currentViewport = null;
private boolean isDefaultViewport = true;
private Rect2i maxViewport = new Rect2i( -1, -1, -1, -1 );
protected Thread renderingThread = null;
protected boolean vsyncSwitched = false;
private long renderedFrames = 0L;
private boolean isInitialized = false;
@Override
protected RenderPeerImpl createRenderPeer()
{
return ( new RenderPeerImpl( this, new StateUnitPeerRegistryImpl(), new OpenGLStatesCacheImpl() ) );
}
public CanvasPeerImplBase( DisplayMode displayMode, FullscreenMode fullscreen, boolean vsync, FSAA fsaa, int depthBufferSize )
{
super( displayMode, fullscreen, vsync, fsaa, depthBufferSize );
}
protected void init() throws Throwable
{
this.oglInfo = new OpenGLInfo( GL11.glGetString( GL11.GL_RENDERER ), GL11.glGetString( GL11.GL_VERSION ), GL11.glGetString( GL11.GL_VENDOR ), GL11.glGetString( GL11.GL_EXTENSIONS ) );
OpenGlExtensions.setExtensions( oglInfo );
IntBuffer intBuffer = BufferUtils.createIntBuffer( 16 );
GL11.glGetInteger( GL11.GL_MAX_TEXTURE_SIZE, intBuffer );
final int maxTexSize = intBuffer.get( 0 );
intBuffer.clear();
GL11.glGetInteger( GL13.GL_MAX_TEXTURE_UNITS, intBuffer );
final int maxTUs = intBuffer.get( 0 );
final int maxVAs;
if ( oglInfo.getVersionMajor() >= 2 )
{
intBuffer.clear();
GL11.glGetInteger( GL20.GL_MAX_VERTEX_ATTRIBS, intBuffer );
maxVAs = intBuffer.get( 0 );
}
else
{
maxVAs = 0;
}
intBuffer.clear();
GL11.glGetInteger( GL11.GL_MAX_VIEWPORT_DIMS, intBuffer );
this.maxViewport.set( 0, 0, intBuffer.get( 0 ), intBuffer.get( 1 ) );
setOpenGLCapabilities( new OpenGLCapabilities( maxTexSize, maxTUs, TextureUnitStateUnitPeer.getMaxAnisotropicLevel(), maxVAs, oglInfo ) );
getRenderPeer().getStatesCache().update( null, getOpenGLCapabilities() );
IntBuffer ib = BufferUtils.createIntBuffer( 16 );
GL11.glGetInteger( GL11.GL_DEPTH_BITS, ib );
setDepthBufferSize( ib.get( 0 ) );
boolean showInfos = true;
try
{
showInfos = System.getProperty( "org.xith3d.render.lwjgl.displayGLInfos", "true" ).equals( "true" );
}
catch ( SecurityException ignore )
{
// Ignore a SecurityException for Applet deployment
}
if ( showInfos )
{
// System.out.println( "Init GL is " + GL11.class.getName() );
oglInfo.dump();
}
isInitialized = true;
}
protected final boolean isInitialized()
{
return ( isInitialized );
}
/**
* {@inheritDoc}
*/
@Override
public final RenderPeerImpl getRenderPeer()
{
return ( (RenderPeerImpl)super.getRenderPeer() );
}
/**
* {@inheritDoc}
*/
@Override
public long getRenderedFrames()
{
return ( renderedFrames );
}
@Override
protected Class< ? > getExpectedNativeDisplayModeClass()
{
return ( org.lwjgl.opengl.DisplayMode.class );
}
public final org.lwjgl.opengl.DisplayMode getNativeDisplayMode()
{
if ( getDisplayMode() == null )
return ( null );
return ( (org.lwjgl.opengl.DisplayMode)getDisplayMode().getNativeMode() );
}
protected abstract void applyVSync();
protected abstract Thread makeCurrent();
/**
* {@inheritDoc}
*/
@Override
public final void addDestroyableObject( SceneGraphOpenGLReference ref )
{
super.addDestroyableObject( ref );
}
protected void beforeRenderStart()
{
if ( renderingThread == null )
{
renderingThread = makeCurrent();
}
if ( vsyncSwitched )
{
applyVSync();
vsyncSwitched = false;
}
//setNoSwapBuffers( pickRequest != null );
// reset triangles count
setTriangles( 0 );
destroyGLNames( true );
}
/**
* {@inheritDoc}
*/
@Override
public Rect2i getMaxViewport()
{
return ( maxViewport );
}
public Rect2i getCurrentViewport()
{
return ( currentViewport );
}
public void updateViewport( Rect2i viewport )
{
// get the current viewport
boolean viewportChanged = false;
if ( currentViewport == null )
{
if ( viewport == null )
{
if ( getViewport() == null )
{
currentViewport = new Rect2i( 0, 0, getWidth(), getHeight() );
}
else
{
currentViewport = new Rect2i( getViewport() );
getViewport().setClean();
}
isDefaultViewport = true;
}
else
{
currentViewport = new Rect2i( viewport );
isDefaultViewport = false;
}
viewportChanged = true;
}
else if ( viewport != null )
{
if ( ( getViewport() != null ) && ( getViewport().isDirty() ) )
{
currentViewport.set( getViewport() );
getViewport().setClean();
}
if ( !currentViewport.equals( viewport ) )
{
currentViewport.set( viewport );
isDefaultViewport = false;
viewportChanged = true;
}
}
else if ( !isDefaultViewport )
{
if ( getViewport() == null )
{
currentViewport.set( 0, 0, getWidth(), getHeight() );
}
else
{
currentViewport.set( getViewport() );
getViewport().setClean();
}
isDefaultViewport = true;
viewportChanged = true;
}
else if ( ( isDefaultViewport ) && ( !currentViewport.equals( ( getViewport() == null ) ? this : getViewport() ) ) )
{
if ( getViewport() == null )
{
currentViewport.set( 0, 0, getWidth(), getHeight() );
}
else
{
currentViewport.set( getViewport() );
getViewport().setClean();
}
viewportChanged = true;
}
if ( viewportChanged )
{
// OpenGL wants it flipped!
final int y = getHeight() - currentViewport.getTop() - currentViewport.getHeight();
GL11.glViewport( currentViewport.getLeft(), y, currentViewport.getWidth(), currentViewport.getHeight() );
}
}
/**
* {@inheritDoc}
*/
@Override
public void clear()
{
getRenderPeer().clearViewport();
}
/**
* Uses the current render frame to draw all the graphics for the frame.
* If there is not one defined then nothing wil be drawm.
*/
protected final Object doRender( View view, List< RenderPass > renderPasses, boolean layeredMode, long frameId, long nanoTime, long nanoStep, PickRequest pickRequest )
{
Object result = getRenderPeer().render( null, view, renderPasses, layeredMode, frameId, nanoTime, nanoStep, pickRequest );
renderedFrames++;
return ( result );
}
/**
* {@inheritDoc}
*/
@Override
public void destroy()
{
super.destroy();
try
{
GL11.glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
if ( Mouse.isCreated() )
Mouse.destroy();
if ( Keyboard.isCreated() )
Keyboard.destroy();
}
catch ( Throwable t )
{
X3DLog.print( t );
}
}
}