/** * 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.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.net.URL; import java.util.List; import javax.imageio.ImageIO; import org.jagatoo.input.InputSystem; import org.jagatoo.input.impl.awt.AWTCursorConverter; import org.jagatoo.input.impl.mixed.AWTJInputInputDeviceFactory; import org.jagatoo.input.render.Cursor; import org.jagatoo.logging.ProfileTimer; import org.lwjgl.LWJGLException; import org.lwjgl.opengl.AWTGLCanvas; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.PixelFormat; import org.xith3d.picking.PickRequest; import org.xith3d.render.RenderPass; import org.xith3d.render.config.DisplayMode; import org.xith3d.render.config.FSAA; import org.xith3d.render.config.OpenGLLayer; import org.xith3d.render.config.DisplayMode.FullscreenMode; import org.xith3d.scenegraph.View; import org.xith3d.utility.logging.X3DLog; /** * The CanvasPeer implementation for the LightWeight Java Game Library (LWJGL) * * @author David Yazel * @author Marvin Froehlich (aka Qudus) */ public class CanvasPeerImplAWT extends CanvasPeerImplBase { private Frame window; private ContextGLCanvas glCanvas; private int left = 0; private int top = 0; private long lastKnownFrameId = -1L; private boolean closeRequested = false; private boolean isRendering = false; private boolean displayModeChanged = false; private AWTJInputInputDeviceFactory inputDeviceFactory = null; public AWTJInputInputDeviceFactory getInputDeviceFactory( InputSystem inputSystem ) { if ( inputDeviceFactory == null ) { inputDeviceFactory = new AWTJInputInputDeviceFactory( this, inputSystem.getEventQueue() ); } return ( inputDeviceFactory ); } public final ContextGLCanvas getDrawable() { return ( glCanvas ); } public void refreshCursor( org.jagatoo.input.devices.Mouse mouse ) { if ( getCursor() == null ) { glCanvas.setCursor( AWTCursorConverter.HIDDEN_CURSOR ); } else if ( getCursor() == Cursor.DEFAULT_CURSOR ) { glCanvas.setCursor( java.awt.Cursor.getDefaultCursor() ); } else// if ( getCursor() != null ) { AWTCursorConverter.convertCursor( getCursor() ); glCanvas.setCursor( (java.awt.Cursor)getCursor().getCursorObject() ); } } public final boolean receivesInputEvents() { return ( glCanvas.hasFocus() ); } public CanvasPeerImplAWT( Object owner, DisplayMode displayMode, FullscreenMode fullscreen, boolean vsync, FSAA fsaa, int depthBufferSize ) { super( displayMode, fullscreen, vsync, fsaa, depthBufferSize ); if ( owner == null ) { String message = "The " + this.getClass().getSimpleName() + " must be used with an owner (integrated into an AWT/Swing environment)."; X3DLog.error( message ); throw new Error( message ); } assert ( displayMode != null ); displayMode = getDisplayMode(); try { System.setProperty( "org.xith3d.render.lwjgl.displayGLInfos", String.valueOf( false ) ); } catch ( SecurityException ignore ) { // Ignore a SecurityException for Applet deployment } try { this.glCanvas = new ContextGLCanvas( new PixelFormat( 0, depthBufferSize, 8, fsaa.getIntValue() ) ); this.setVSyncEnabled( vsync ); glCanvas.setBounds( 0, 0, displayMode.getWidth(), displayMode.getHeight() ); glCanvas.setFocusable( true ); glCanvas.requestFocus(); } catch ( Throwable t ) { if ( t instanceof Error ) throw (Error)t; else if ( t instanceof RuntimeException ) throw (RuntimeException)t; else throw new Error( t.getMessage(), t ); } // boomschakalacka: // FIXME: this code is unreachable as Exception is thrown in line 135 if owner is null! if ( owner == null ) { this.window = new Frame( "Xith3D (LWJGL)" ); window.setLayout( null ); if ( fullscreen.isFullscreen() ) { window.setBackground( Color.BLACK ); } window.setUndecorated( fullscreen != FullscreenMode.WINDOWED ); window.setSize( displayMode.getWidth(), displayMode.getHeight() ); window.addWindowListener( new WindowAdapter() { @Override public void windowClosing( WindowEvent e ) { closeRequested = true; } } ); final boolean exclusive = ( fullscreen.isFullscreen() && ( displayMode.getNativeMode() != null ) ); window.add( glCanvas ); window.setVisible( true ); if ( !exclusive ) { Thread.yield(); final Dimension frameSize; if ( !fullscreen.isFullscreen() ) { Insets insets = window.getInsets(); glCanvas.setLocation( insets.left, insets.top ); frameSize = new Dimension( displayMode.getWidth() + insets.left + insets.right, displayMode.getHeight() + insets.top + insets.bottom ); window.setSize( frameSize ); } else { frameSize = new Dimension( displayMode.getWidth(), displayMode.getHeight() ); } Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Point upperLeft = new Point( ( screenSize.width - frameSize.width ) / 2, ( screenSize.height - frameSize.height ) / 2 ); window.setLocation( upperLeft ); //frame.setResizable( false/* !fullscreen */); } else { final java.awt.DisplayMode awtMode = (java.awt.DisplayMode)displayMode.getNativeMode(); GraphicsDevice graphDev = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); graphDev.setFullScreenWindow( window ); graphDev.setDisplayMode( awtMode ); } } else { glCanvas.setBounds( 0, 0, displayMode.getWidth(), displayMode.getHeight() ); ( (Container)owner ).add( glCanvas ); } Thread.yield(); // boomschakalacka: // FIXME: this code is unreachable as Exception is thrown in line 135 if owner is null! if ( owner == null ) { /* java.awt.Point loc = glCanvas.getLocation(); glCanvas.setLocation( loc.x + 1, loc.y + 1 ); */ (window).setResizable( false ); java.awt.Dimension size = window.getSize(); window.setSize( size.width - 2, size.height - 2 ); } } private class ContextGLCanvas extends AWTGLCanvas { private static final long serialVersionUID = 521768945921758405L; private View view; private List< RenderPass > renderPasses; private boolean layeredMode; private long frameId = -1L; private long nanoTime = 0L; private long nanoStep = -1L; private PickRequest pickRequest; private Object pickResult; @Override protected void initGL() { synchronized ( getRenderLock() ) { isRendering = true; clear(); try { CanvasPeerImplAWT.this.init(); } catch ( Throwable t ) { t.printStackTrace(); } isRendering = false; } } public void finish() { try { this.swapBuffers(); } catch (LWJGLException ex) { } } @Override protected void paintGL() { if ( !isInitialized() ) return; synchronized ( getRenderLock() ) { isRendering = true; if ( closeRequested ) { closeRequested = false; fireClosingEvent(); } if ( ( frameId < 0L ) || ( frameId <= lastKnownFrameId ) ) { isRendering = false; return; } lastKnownFrameId = frameId; pickResult = doRender( view, renderPasses, layeredMode, frameId, nanoTime, nanoStep, pickRequest ); /* this.view = null; this.bgCache = null; this.renderPasses = null; this.layeredMode = true; this.frameId = -1L; */ try { swapBuffers(); } catch ( LWJGLException e ) { e.printStackTrace(); } isRendering = false; } } public void repaint( View view, List< RenderPass > renderPasses, boolean layeredMode, long frameId, long nanoTime, long nanoStep, PickRequest pickRequest ) { this.view = view; this.renderPasses = renderPasses; this.layeredMode = layeredMode; this.frameId = frameId; this.nanoTime = nanoTime; this.nanoStep = nanoStep; this.pickRequest = pickRequest; this.pickResult = null; repaint(); } /* public ContextGLCanvas( GraphicsDevice graphDev, PixelFormat pixelFormat ) throws LWJGLException { super( graphDev, pixelFormat ); } */ public ContextGLCanvas( PixelFormat pixelFormat ) throws LWJGLException { super( pixelFormat ); } } /** * {@inheritDoc} */ @Override public OpenGLLayer getType() { return ( OpenGLLayer.LWJGL_AWT ); } @Override protected final Class< ? > getExpectedNativeDisplayModeClass() { return ( java.awt.DisplayMode.class ); } @Override protected void applyVSync() { glCanvas.setVSyncEnabled( isVSyncEnabled() ); } /** * {@inheritDoc} */ @Override public void setVSyncEnabled( boolean vsync ) { super.setVSyncEnabled( vsync ); vsyncSwitched = true; } /** * {@inheritDoc} */ @Override public final Frame getWindow() { return ( window ); } /** * {@inheritDoc} */ @Override public final AWTGLCanvas getComponent() { return ( glCanvas ); } /** * {@inheritDoc} */ @Override public void setIcon( URL iconResource ) throws IOException { assert ( window instanceof Frame ) : "Window isn't a Frame"; window.setIconImage( ImageIO.read( iconResource ) ); } /** * {@inheritDoc} */ @Override public final void setTitle( String title ) { window.setTitle( title ); } /** * {@inheritDoc} */ @Override public final String getTitle() { return ( window.getTitle() ); } /** * {@inheritDoc} */ @Override public final boolean setLocation( int x, int y ) { if ( ( window.getLocation().x != x ) || ( window.getLocation().y != y ) ) { window.setLocation( x, y ); this.left = x; this.top = y; return ( true ); } return ( false ); } /** * {@inheritDoc} */ @Override public final int getLeft() { return ( left ); } /** * {@inheritDoc} */ @Override public final int getTop() { return ( top ); } /** * {@inheritDoc} */ @Override public final boolean setSize( int width, int height ) { if ( ( glCanvas.getSize().width != width ) || ( glCanvas.getSize().height != height ) ) { glCanvas.setSize( width, height ); if ( getWindow() != null ) { Insets insets = getWindow().getInsets(); glCanvas.setLocation( insets.left, insets.top ); Dimension frameSize = new Dimension( width + insets.left + insets.right, height + insets.top + insets.bottom ); getWindow().setSize( frameSize ); } return ( true ); } return ( false ); } /** * {@inheritDoc} */ @Override public final int getWidth() { return ( glCanvas.getWidth() ); } /** * {@inheritDoc} */ @Override public final int getHeight() { return ( glCanvas.getHeight() ); } /** * {@inheritDoc} */ @Override protected boolean setDisplayModeImpl( DisplayMode displayMode ) { //final boolean result = !displayMode.equals( getDisplayMode() ); final boolean result = true; if ( result ) displayModeChanged = true; return ( result ); } /** * {@inheritDoc} */ @Override public void setGamma( float gamma, float brightness, float contrast ) { super.setGamma( gamma, brightness, contrast ); try { Display.setDisplayConfiguration( gamma, brightness, contrast ); } catch ( LWJGLException e ) { e.printStackTrace(); } } /** * {@inheritDoc} */ @Override public final boolean isRendering() { return ( isRendering ); } @Override protected Thread makeCurrent() { try { //glCanvas.makeCurrent(); } catch ( Throwable e ) { e.printStackTrace(); } return ( Thread.currentThread() ); } /** * {@inheritDoc} */ @Override public void beforeThreadChanged() { if ( ( renderingThread != null ) || ( getRenderedFrames() == 0L ) ) { try { //glCanvas.releaseContext(); } catch ( Throwable e ) { e.printStackTrace(); } renderingThread = null; } } /** * {@inheritDoc} */ @Override protected Object initRenderingImpl( View view, List< RenderPass > renderPasses, boolean layeredMode, long frameId, long nanoTime, long nanoStep, PickRequest pickRequest ) { if ( displayModeChanged ) { try { Display.setDisplayMode( getNativeDisplayMode() ); } catch ( LWJGLException e ) { e.printStackTrace(); } displayModeChanged = false; } ProfileTimer.startProfile( X3DLog.LOG_CHANNEL, "CanvasPeerImpl::render" ); glCanvas.repaint( view, renderPasses, layeredMode, frameId, nanoTime, nanoStep, pickRequest ); Object result = glCanvas.pickResult; glCanvas.pickResult = null; ProfileTimer.endProfile(); return ( result ); } /** * {@inheritDoc} */ @Override public void destroy() { //super.destroy(); if ( window != null ) window.dispose(); } }