diff --git a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglCanvas.java b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglCanvas.java
index f597f3a8d..d52702e99 100644
--- a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglCanvas.java
+++ b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglCanvas.java
@@ -1,478 +1,482 @@
-/*
- * Copyright (c) 2009-2010 jMonkeyEngine
- * All rights reserved.
- *
- * 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.jme3.system.lwjgl;
-
-import com.jme3.system.AppSettings;
-import com.jme3.system.JmeCanvasContext;
-import com.jme3.system.JmeContext.Type;
-import com.jme3.system.JmeSystem;
-import com.jme3.system.Platform;
-import java.awt.Canvas;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.swing.SwingUtilities;
-import org.lwjgl.LWJGLException;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.input.Mouse;
-import org.lwjgl.opengl.Display;
-import org.lwjgl.opengl.Pbuffer;
-import org.lwjgl.opengl.PixelFormat;
-
-public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext {
-
- protected static final int TASK_NOTHING = 0,
- TASK_DESTROY_DISPLAY = 1,
- TASK_CREATE_DISPLAY = 2,
- TASK_COMPLETE = 3;
-
-// protected static final boolean USE_SHARED_CONTEXT =
-// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true"));
-
- protected static final boolean USE_SHARED_CONTEXT = false;
-
- private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());
- private Canvas canvas;
- private int width;
- private int height;
-
- private final Object taskLock = new Object();
- private int desiredTask = TASK_NOTHING;
-
- private Thread renderThread;
- private boolean runningFirstTime = true;
- private boolean mouseWasGrabbed = false;
-
- private boolean mouseWasCreated = false;
- private boolean keyboardWasCreated = false;
-
- private Pbuffer pbuffer;
- private PixelFormat pbufferFormat;
- private PixelFormat canvasFormat;
-
- private class GLCanvas extends Canvas {
- @Override
- public void addNotify(){
- super.addNotify();
-
- if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED)
- return; // already destroyed.
-
- if (renderThread == null){
- logger.log(Level.INFO, "EDT: Creating OGL thread.");
-
- // Also set some settings on the canvas here.
- // So we don't do it outside the AWT thread.
- canvas.setFocusable(true);
- canvas.setIgnoreRepaint(true);
-
- renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
- renderThread.start();
- }else if (needClose.get()){
- return;
- }
-
- logger.log(Level.INFO, "EDT: Telling OGL to create display ..");
- synchronized (taskLock){
- desiredTask = TASK_CREATE_DISPLAY;
-// while (desiredTask != TASK_COMPLETE){
-// try {
-// taskLock.wait();
-// } catch (InterruptedException ex) {
-// return;
-// }
-// }
-// desiredTask = TASK_NOTHING;
- }
-// logger.log(Level.INFO, "EDT: OGL has created the display");
- }
-
- @Override
- public void removeNotify(){
- if (needClose.get()){
- logger.log(Level.INFO, "EDT: Application is stopped. Not restoring canvas.");
- super.removeNotify();
- return;
- }
-
- // We must tell GL context to shutdown and wait for it to
- // shutdown, otherwise, issues will occur.
- logger.log(Level.INFO, "EDT: Telling OGL to destroy display ..");
- synchronized (taskLock){
- desiredTask = TASK_DESTROY_DISPLAY;
- while (desiredTask != TASK_COMPLETE){
- try {
- taskLock.wait();
- } catch (InterruptedException ex){
- super.removeNotify();
- return;
- }
- }
- desiredTask = TASK_NOTHING;
- }
-
- logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death");
- // GL context is dead at this point
-
- super.removeNotify();
- }
- }
-
- public LwjglCanvas(){
- super();
- canvas = new GLCanvas();
- }
-
- @Override
- public Type getType() {
- return Type.Canvas;
- }
-
- public void create(boolean waitFor){
- if (renderThread == null){
- logger.log(Level.INFO, "MAIN: Creating OGL thread.");
-
- renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
- renderThread.start();
- }
- // do not do anything.
- // superclass's create() will be called at initInThread()
- if (waitFor)
- waitFor(true);
- }
-
- @Override
- public void setTitle(String title) {
- }
-
- @Override
- public void restart() {
- frameRate = settings.getFrameRate();
- // TODO: Handle other cases, like change of pixel format, etc.
- }
-
- public Canvas getCanvas(){
- return canvas;
- }
-
- @Override
- protected void runLoop(){
- if (desiredTask != TASK_NOTHING){
- synchronized (taskLock){
- switch (desiredTask){
- case TASK_CREATE_DISPLAY:
- logger.log(Level.INFO, "OGL: Creating display ..");
- restoreCanvas();
- listener.gainFocus();
- desiredTask = TASK_NOTHING;
- break;
- case TASK_DESTROY_DISPLAY:
- logger.log(Level.INFO, "OGL: Destroying display ..");
- listener.loseFocus();
- pauseCanvas();
- break;
- }
- desiredTask = TASK_COMPLETE;
- taskLock.notifyAll();
- }
- }
-
- if (renderable.get()){
- int newWidth = Math.max(canvas.getWidth(), 1);
- int newHeight = Math.max(canvas.getHeight(), 1);
- if (width != newWidth || height != newHeight){
- width = newWidth;
- height = newHeight;
- if (listener != null){
- listener.reshape(width, height);
- }
- }
- }else{
- if (frameRate <= 0){
- // NOTE: MUST be done otherwise
- // Windows OS will freeze
- Display.sync(30);
- }
- }
-
- super.runLoop();
- }
-
- private void pauseCanvas(){
- if (Mouse.isCreated()){
- if (Mouse.isGrabbed()){
- Mouse.setGrabbed(false);
- mouseWasGrabbed = true;
- }
- mouseWasCreated = true;
- Mouse.destroy();
- }
- if (Keyboard.isCreated()){
- keyboardWasCreated = true;
- Keyboard.destroy();
- }
-
- renderable.set(false);
- destroyContext();
- }
-
- /**
- * Called to restore the canvas.
- */
- private void restoreCanvas(){
- logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");
- while (!canvas.isDisplayable()){
- try {
- Thread.sleep(10);
- } catch (InterruptedException ex) {
- logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
- }
- }
-
- logger.log(Level.INFO, "OGL: Creating display context ..");
-
- // Set renderable to true, since canvas is now displayable.
- renderable.set(true);
- createContext(settings);
-
- logger.log(Level.INFO, "OGL: Display is active!");
-
- try {
- if (mouseWasCreated){
- Mouse.create();
- if (mouseWasGrabbed){
- Mouse.setGrabbed(true);
- mouseWasGrabbed = false;
- }
- }
- if (keyboardWasCreated){
- Keyboard.create();
- keyboardWasCreated = false;
- }
- } catch (LWJGLException ex){
- logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);
- }
-
- SwingUtilities.invokeLater(new Runnable(){
- public void run(){
- canvas.requestFocus();
- }
- });
- }
-
- /**
- * It seems it is best to use one pixel format for all shared contexts.
- * @see http://developer.apple.com/library/mac/#qa/qa1248/_index.html
- */
- protected PixelFormat acquirePixelFormat(boolean forPbuffer){
- if (forPbuffer){
- // Use 0 samples for pbuffer format, prevents
- // crashes on bad drivers
- if (pbufferFormat == null){
- pbufferFormat = new PixelFormat(settings.getBitsPerPixel(),
- 0,
- settings.getDepthBits(),
- settings.getStencilBits(),
- 0);
- }
- return pbufferFormat;
- }else{
- if (canvasFormat == null){
- canvasFormat = new PixelFormat(settings.getBitsPerPixel(),
- 0,
- settings.getDepthBits(),
- settings.getStencilBits(),
- settings.getSamples());
- }
- return canvasFormat;
- }
- }
-
- /**
- * Makes sure the pbuffer is available and ready for use
- */
- protected void makePbufferAvailable() throws LWJGLException{
- if (pbuffer != null && pbuffer.isBufferLost()){
- logger.log(Level.WARNING, "PBuffer was lost!");
- pbuffer.destroy();
- pbuffer = null;
- }
-
- if (pbuffer == null) {
- pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);
- pbuffer.makeCurrent();
- logger.log(Level.INFO, "OGL: Pbuffer has been created");
-
- // Any created objects are no longer valid
- if (!runningFirstTime){
- renderer.resetGLObjects();
- }
- }
-
- pbuffer.makeCurrent();
- if (!pbuffer.isCurrent()){
- throw new LWJGLException("Pbuffer cannot be made current");
- }
- }
-
- protected void destroyPbuffer(){
- if (pbuffer != null){
- if (!pbuffer.isBufferLost()){
- pbuffer.destroy();
- }
- pbuffer = null;
- }
- }
-
- /**
- * This is called:
- * 1) When the context thread ends
- * 2) Any time the canvas becomes non-displayable
- */
- protected void destroyContext(){
- try {
- // invalidate the state so renderer can resume operation
- if (!USE_SHARED_CONTEXT){
- renderer.cleanup();
- }
-
- if (Display.isCreated()){
- /* FIXES:
- * org.lwjgl.LWJGLException: X Error
- * BadWindow (invalid Window parameter) request_code: 2 minor_code: 0
- *
- * Destroying keyboard early prevents the error above, triggered
- * by destroying keyboard in by Display.destroy() or Display.setParent(null).
- * Therefore Keyboard.destroy() should precede any of these calls.
- */
- if (Keyboard.isCreated()){
- // Should only happen if called in
- // LwjglAbstractDisplay.deinitInThread().
- Keyboard.destroy();
- }
-
- //try {
- // NOTE: On Windows XP, not calling setParent(null)
- // freezes the application.
- // On Mac it freezes the application.
- // On Linux it fixes a crash with X Window System.
- if (JmeSystem.getPlatform() == Platform.Windows32
- || JmeSystem.getPlatform() == Platform.Windows64){
- //Display.setParent(null);
- }
- //} catch (LWJGLException ex) {
- // logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);
- //}
-
- Display.destroy();
- }
-
- // The canvas is no longer visible,
- // but the context thread is still running.
- if (!needClose.get()){
- // MUST make sure there's still a context current here ..
- // Display is dead, make pbuffer available to the system
- makePbufferAvailable();
-
- renderer.invalidateState();
- }else{
- // The context thread is no longer running.
- // Destroy pbuffer.
- destroyPbuffer();
- }
- } catch (LWJGLException ex) {
- listener.handleError("Failed make pbuffer available", ex);
- }
- }
-
- /**
- * This is called:
- * 1) When the context thread starts
- * 2) Any time the canvas becomes displayable again.
- */
- @Override
- protected void createContext(AppSettings settings) {
- // In case canvas is not visible, we still take framerate
- // from settings to prevent "100% CPU usage"
- frameRate = settings.getFrameRate();
-
- try {
- if (renderable.get()){
- if (!runningFirstTime){
- // because the display is a different opengl context
- // must reset the context state.
- if (!USE_SHARED_CONTEXT){
- renderer.cleanup();
- }
- }
-
- // if the pbuffer is currently active,
- // make sure to deactivate it
- destroyPbuffer();
-
- if (Keyboard.isCreated()){
- Keyboard.destroy();
- }
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ex) {
- }
-
- Display.setVSyncEnabled(settings.isVSync());
- Display.setParent(canvas);
-
- if (USE_SHARED_CONTEXT){
- Display.create(acquirePixelFormat(false), pbuffer);
- }else{
- Display.create(acquirePixelFormat(false));
- }
-
- renderer.invalidateState();
- }else{
- // First create the pbuffer, if it is needed.
- makePbufferAvailable();
- }
-
- // At this point, the OpenGL context is active.
- if (runningFirstTime){
- // THIS is the part that creates the renderer.
- // It must always be called, now that we have the pbuffer workaround.
- initContextFirstTime();
- runningFirstTime = false;
- }
- } catch (LWJGLException ex) {
- listener.handleError("Failed to initialize OpenGL context", ex);
- // TODO: Fix deadlock that happens after the error (throw runtime exception?)
- }
- }
-}
+F/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.system.lwjgl;
+
+import com.jme3.system.AppSettings;
+import com.jme3.system.JmeCanvasContext;
+import com.jme3.system.JmeContext.Type;
+import com.jme3.system.JmeSystem;
+import com.jme3.system.Platform;
+import java.awt.Canvas;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.SwingUtilities;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.Pbuffer;
+import org.lwjgl.opengl.PixelFormat;
+
+public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext {
+
+ protected static final int TASK_NOTHING = 0,
+ TASK_DESTROY_DISPLAY = 1,
+ TASK_CREATE_DISPLAY = 2,
+ TASK_COMPLETE = 3;
+
+// protected static final boolean USE_SHARED_CONTEXT =
+// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true"));
+
+ protected static final boolean USE_SHARED_CONTEXT = false;
+
+ private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());
+ private Canvas canvas;
+ private int width;
+ private int height;
+
+ private final Object taskLock = new Object();
+ private int desiredTask = TASK_NOTHING;
+
+ private Thread renderThread;
+ private boolean runningFirstTime = true;
+ private boolean mouseWasGrabbed = false;
+
+ private boolean mouseWasCreated = false;
+ private boolean keyboardWasCreated = false;
+
+ private Pbuffer pbuffer;
+ private PixelFormat pbufferFormat;
+ private PixelFormat canvasFormat;
+
+ private class GLCanvas extends Canvas {
+ @Override
+ public void addNotify(){
+ super.addNotify();
+
+ if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED)
+ return; // already destroyed.
+
+ if (renderThread == null){
+ logger.log(Level.INFO, "EDT: Creating OGL thread.");
+
+ // Also set some settings on the canvas here.
+ // So we don't do it outside the AWT thread.
+ canvas.setFocusable(true);
+ canvas.setIgnoreRepaint(true);
+
+ renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
+ renderThread.start();
+ }else if (needClose.get()){
+ return;
+ }
+
+ logger.log(Level.INFO, "EDT: Telling OGL to create display ..");
+ synchronized (taskLock){
+ desiredTask = TASK_CREATE_DISPLAY;
+// while (desiredTask != TASK_COMPLETE){
+// try {
+// taskLock.wait();
+// } catch (InterruptedException ex) {
+// return;
+// }
+// }
+// desiredTask = TASK_NOTHING;
+ }
+// logger.log(Level.INFO, "EDT: OGL has created the display");
+ }
+
+ @Override
+ public void removeNotify(){
+ if (needClose.get()){
+ logger.log(Level.INFO, "EDT: Application is stopped. Not restoring canvas.");
+ super.removeNotify();
+ return;
+ }
+
+ // We must tell GL context to shutdown and wait for it to
+ // shutdown, otherwise, issues will occur.
+ logger.log(Level.INFO, "EDT: Telling OGL to destroy display ..");
+ synchronized (taskLock){
+ desiredTask = TASK_DESTROY_DISPLAY;
+ while (desiredTask != TASK_COMPLETE){
+ try {
+ taskLock.wait();
+ } catch (InterruptedException ex){
+ super.removeNotify();
+ return;
+ }
+ }
+ desiredTask = TASK_NOTHING;
+ }
+
+ logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death");
+ // GL context is dead at this point
+
+ super.removeNotify();
+ }
+ }
+
+ public LwjglCanvas(){
+ super();
+ canvas = new GLCanvas();
+ }
+
+ @Override
+ public Type getType() {
+ return Type.Canvas;
+ }
+
+ public void create(boolean waitFor){
+ if (renderThread == null){
+ logger.log(Level.INFO, "MAIN: Creating OGL thread.");
+
+ renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
+ renderThread.start();
+ }
+ // do not do anything.
+ // superclass's create() will be called at initInThread()
+ if (waitFor)
+ waitFor(true);
+ }
+
+ @Override
+ public void setTitle(String title) {
+ }
+
+ @Override
+ public void restart() {
+ frameRate = settings.getFrameRate();
+ // TODO: Handle other cases, like change of pixel format, etc.
+ }
+
+ public Canvas getCanvas(){
+ return canvas;
+ }
+
+ @Override
+ protected void runLoop(){
+ if (desiredTask != TASK_NOTHING){
+ synchronized (taskLock){
+ switch (desiredTask){
+ case TASK_CREATE_DISPLAY:
+ logger.log(Level.INFO, "OGL: Creating display ..");
+ restoreCanvas();
+ listener.gainFocus();
+ desiredTask = TASK_NOTHING;
+ break;
+ case TASK_DESTROY_DISPLAY:
+ logger.log(Level.INFO, "OGL: Destroying display ..");
+ listener.loseFocus();
+ pauseCanvas();
+ break;
+ }
+ desiredTask = TASK_COMPLETE;
+ taskLock.notifyAll();
+ }
+ }
+
+ if (renderable.get()){
+ int newWidth = Math.max(canvas.getWidth(), 1);
+ int newHeight = Math.max(canvas.getHeight(), 1);
+ if (width != newWidth || height != newHeight){
+ width = newWidth;
+ height = newHeight;
+ if (listener != null){
+ listener.reshape(width, height);
+ }
+ }
+ }else{
+ if (frameRate <= 0){
+ // NOTE: MUST be done otherwise
+ // Windows OS will freeze
+ Display.sync(30);
+ }
+ }
+
+ super.runLoop();
+ }
+
+ private void pauseCanvas(){
+ if (Mouse.isCreated()){
+ if (Mouse.isGrabbed()){
+ Mouse.setGrabbed(false);
+ mouseWasGrabbed = true;
+ }
+ mouseWasCreated = true;
+ Mouse.destroy();
+ }
+ if (Keyboard.isCreated()){
+ keyboardWasCreated = true;
+ Keyboard.destroy();
+ }
+
+ renderable.set(false);
+ destroyContext();
+ }
+
+ /**
+ * Called to restore the canvas.
+ */
+ private void restoreCanvas(){
+ logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");
+ while (!canvas.isDisplayable()){
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException ex) {
+ logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
+ }
+ }
+
+ logger.log(Level.INFO, "OGL: Creating display context ..");
+
+ // Set renderable to true, since canvas is now displayable.
+ renderable.set(true);
+ createContext(settings);
+
+ logger.log(Level.INFO, "OGL: Display is active!");
+
+ try {
+ if (mouseWasCreated){
+ Mouse.create();
+ if (mouseWasGrabbed){
+ Mouse.setGrabbed(true);
+ mouseWasGrabbed = false;
+ }
+ }
+ if (keyboardWasCreated){
+ Keyboard.create();
+ keyboardWasCreated = false;
+ }
+ } catch (LWJGLException ex){
+ logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);
+ }
+
+ SwingUtilities.invokeLater(new Runnable(){
+ public void run(){
+ canvas.requestFocus();
+ }
+ });
+ }
+
+ /**
+ * It seems it is best to use one pixel format for all shared contexts.
+ * @see http://developer.apple.com/library/mac/#qa/qa1248/_index.html
+ */
+ protected PixelFormat acquirePixelFormat(boolean forPbuffer){
+ if (forPbuffer){
+ // Use 0 samples for pbuffer format, prevents
+ // crashes on bad drivers
+ if (pbufferFormat == null){
+ pbufferFormat = new PixelFormat(settings.getBitsPerPixel(),
+ 0,
+ settings.getDepthBits(),
+ settings.getStencilBits(),
+ 0);
+ }
+ return pbufferFormat;
+ }else{
+ if (canvasFormat == null){
+ int samples = 0;
+ if (settings.getSamples() > 1){
+ samples = settings.getSamples();
+ }
+ canvasFormat = new PixelFormat(settings.getBitsPerPixel(),
+ 0,
+ settings.getDepthBits(),
+ settings.getStencilBits(),
+ samples);
+ }
+ return canvasFormat;
+ }
+ }
+
+ /**
+ * Makes sure the pbuffer is available and ready for use
+ */
+ protected void makePbufferAvailable() throws LWJGLException{
+ if (pbuffer != null && pbuffer.isBufferLost()){
+ logger.log(Level.WARNING, "PBuffer was lost!");
+ pbuffer.destroy();
+ pbuffer = null;
+ }
+
+ if (pbuffer == null) {
+ pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);
+ pbuffer.makeCurrent();
+ logger.log(Level.INFO, "OGL: Pbuffer has been created");
+
+ // Any created objects are no longer valid
+ if (!runningFirstTime){
+ renderer.resetGLObjects();
+ }
+ }
+
+ pbuffer.makeCurrent();
+ if (!pbuffer.isCurrent()){
+ throw new LWJGLException("Pbuffer cannot be made current");
+ }
+ }
+
+ protected void destroyPbuffer(){
+ if (pbuffer != null){
+ if (!pbuffer.isBufferLost()){
+ pbuffer.destroy();
+ }
+ pbuffer = null;
+ }
+ }
+
+ /**
+ * This is called:
+ * 1) When the context thread ends
+ * 2) Any time the canvas becomes non-displayable
+ */
+ protected void destroyContext(){
+ try {
+ // invalidate the state so renderer can resume operation
+ if (!USE_SHARED_CONTEXT){
+ renderer.cleanup();
+ }
+
+ if (Display.isCreated()){
+ /* FIXES:
+ * org.lwjgl.LWJGLException: X Error
+ * BadWindow (invalid Window parameter) request_code: 2 minor_code: 0
+ *
+ * Destroying keyboard early prevents the error above, triggered
+ * by destroying keyboard in by Display.destroy() or Display.setParent(null).
+ * Therefore Keyboard.destroy() should precede any of these calls.
+ */
+ if (Keyboard.isCreated()){
+ // Should only happen if called in
+ // LwjglAbstractDisplay.deinitInThread().
+ Keyboard.destroy();
+ }
+
+ //try {
+ // NOTE: On Windows XP, not calling setParent(null)
+ // freezes the application.
+ // On Mac it freezes the application.
+ // On Linux it fixes a crash with X Window System.
+ if (JmeSystem.getPlatform() == Platform.Windows32
+ || JmeSystem.getPlatform() == Platform.Windows64){
+ //Display.setParent(null);
+ }
+ //} catch (LWJGLException ex) {
+ // logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);
+ //}
+
+ Display.destroy();
+ }
+
+ // The canvas is no longer visible,
+ // but the context thread is still running.
+ if (!needClose.get()){
+ // MUST make sure there's still a context current here ..
+ // Display is dead, make pbuffer available to the system
+ makePbufferAvailable();
+
+ renderer.invalidateState();
+ }else{
+ // The context thread is no longer running.
+ // Destroy pbuffer.
+ destroyPbuffer();
+ }
+ } catch (LWJGLException ex) {
+ listener.handleError("Failed make pbuffer available", ex);
+ }
+ }
+
+ /**
+ * This is called:
+ * 1) When the context thread starts
+ * 2) Any time the canvas becomes displayable again.
+ */
+ @Override
+ protected void createContext(AppSettings settings) {
+ // In case canvas is not visible, we still take framerate
+ // from settings to prevent "100% CPU usage"
+ frameRate = settings.getFrameRate();
+
+ try {
+ if (renderable.get()){
+ if (!runningFirstTime){
+ // because the display is a different opengl context
+ // must reset the context state.
+ if (!USE_SHARED_CONTEXT){
+ renderer.cleanup();
+ }
+ }
+
+ // if the pbuffer is currently active,
+ // make sure to deactivate it
+ destroyPbuffer();
+
+ if (Keyboard.isCreated()){
+ Keyboard.destroy();
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ }
+
+ Display.setVSyncEnabled(settings.isVSync());
+ Display.setParent(canvas);
+
+ if (USE_SHARED_CONTEXT){
+ Display.create(acquirePixelFormat(false), pbuffer);
+ }else{
+ Display.create(acquirePixelFormat(false));
+ }
+
+ renderer.invalidateState();
+ }else{
+ // First create the pbuffer, if it is needed.
+ makePbufferAvailable();
+ }
+
+ // At this point, the OpenGL context is active.
+ if (runningFirstTime){
+ // THIS is the part that creates the renderer.
+ // It must always be called, now that we have the pbuffer workaround.
+ initContextFirstTime();
+ runningFirstTime = false;
+ }
+ } catch (LWJGLException ex) {
+ listener.handleError("Failed to initialize OpenGL context", ex);
+ // TODO: Fix deadlock that happens after the error (throw runtime exception?)
+ }
+ }
+}
diff --git a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglDisplay.java b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglDisplay.java
index 652a8dc36..db106e794 100644
--- a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglDisplay.java
+++ b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglDisplay.java
@@ -81,11 +81,15 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
displayMode = new DisplayMode(settings.getWidth(), settings.getHeight());
}
+ int samples = 0;
+ if (settings.getSamples() > 1){
+ samples = settings.getSamples();
+ }
PixelFormat pf = new PixelFormat(settings.getBitsPerPixel(),
0,
settings.getDepthBits(),
settings.getStencilBits(),
- settings.getSamples());
+ samples);
frameRate = settings.getFrameRate();
logger.log(Level.INFO, "Selected display mode: {0}", displayMode);
diff --git a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java
index 2c5a384a1..912453129 100644
--- a/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java
+++ b/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java
@@ -1,194 +1,198 @@
-/*
- * Copyright (c) 2009-2010 jMonkeyEngine
- * All rights reserved.
- *
- * 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.jme3.system.lwjgl;
-
-import com.jme3.input.JoyInput;
-import com.jme3.input.KeyInput;
-import com.jme3.input.MouseInput;
-import com.jme3.input.TouchInput;
-import com.jme3.input.dummy.DummyKeyInput;
-import com.jme3.input.dummy.DummyMouseInput;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.lwjgl.LWJGLException;
-import org.lwjgl.Sys;
-import org.lwjgl.opengl.*;
-
-public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
-
- private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName());
- private Pbuffer pbuffer;
- protected AtomicBoolean needClose = new AtomicBoolean(false);
- private int width;
- private int height;
- private PixelFormat pixelFormat;
-
- protected void initInThread(){
- if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0){
- logger.severe("Offscreen surfaces are not supported.");
- return;
- }
-
- pixelFormat = new PixelFormat(settings.getBitsPerPixel(),
- 0,
- settings.getDepthBits(),
- settings.getStencilBits(),
- settings.getSamples());
-
- width = settings.getWidth();
- height = settings.getHeight();
- try{
- Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- public void uncaughtException(Thread thread, Throwable thrown) {
- listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
- }
- });
-
- pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs());
- pbuffer.makeCurrent();
-
- renderable.set(true);
-
- logger.info("Offscreen buffer created.");
- printContextInitInfo();
- } catch (LWJGLException ex){
- listener.handleError("Failed to create display", ex);
- } finally {
- // TODO: It is possible to avoid "Failed to find pixel format"
- // error here by creating a default display.
- }
- super.internalCreate();
- listener.initialize();
- }
-
- protected boolean checkGLError(){
- try {
- Util.checkGLError();
- } catch (OpenGLException ex){
- listener.handleError("An OpenGL error has occured!", ex);
- }
- // NOTE: Always return true since this is used in an "assert" statement
- return true;
- }
-
- protected void runLoop(){
- if (!created.get())
- throw new IllegalStateException();
-
- if (pbuffer.isBufferLost()){
- pbuffer.destroy();
- try{
- pbuffer = new Pbuffer(width, height, pixelFormat, null);
- pbuffer.makeCurrent();
- }catch (LWJGLException ex){
- listener.handleError("Failed to restore pbuffer content", ex);
- }
- }
-
- listener.update();
- assert checkGLError();
-
- renderer.onFrame();
-
- int frameRate = settings.getFrameRate();
- if (frameRate >= 1){
- Display.sync(frameRate);
- }
- }
-
- protected void deinitInThread(){
- renderable.set(false);
-
- listener.destroy();
- renderer.cleanup();
- pbuffer.destroy();
- logger.info("Offscreen buffer destroyed.");
- }
-
- public void run(){
- logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
- initInThread();
- while (!needClose.get()){
- runLoop();
- }
- deinitInThread();
- }
-
- public void destroy(boolean waitFor){
- needClose.set(true);
- if (waitFor)
- waitFor(false);
- }
-
- public void create(boolean waitFor){
- if (created.get()){
- logger.warning("create() called when pbuffer is already created!");
- return;
- }
-
- new Thread(this, "LWJGL Renderer Thread").start();
- if (waitFor)
- waitFor(true);
- }
-
- public void restart() {
- }
-
- public void setAutoFlushFrames(boolean enabled){
- }
-
- public Type getType() {
- return Type.OffscreenSurface;
- }
-
- public MouseInput getMouseInput() {
- return new DummyMouseInput();
- }
-
- public KeyInput getKeyInput() {
- return new DummyKeyInput();
- }
-
- public JoyInput getJoyInput() {
- return null;
- }
-
- public TouchInput getTouchInput() {
- return null;
- }
-
- public void setTitle(String title) {
- }
-
-}
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.system.lwjgl;
+
+import com.jme3.input.JoyInput;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.TouchInput;
+import com.jme3.input.dummy.DummyKeyInput;
+import com.jme3.input.dummy.DummyMouseInput;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.Sys;
+import org.lwjgl.opengl.*;
+
+public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
+
+ private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName());
+ private Pbuffer pbuffer;
+ protected AtomicBoolean needClose = new AtomicBoolean(false);
+ private int width;
+ private int height;
+ private PixelFormat pixelFormat;
+
+ protected void initInThread(){
+ if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0){
+ logger.severe("Offscreen surfaces are not supported.");
+ return;
+ }
+
+ int samples = 0;
+ if (settings.getSamples() > 1){
+ samples = settings.getSamples();
+ }
+ pixelFormat = new PixelFormat(settings.getBitsPerPixel(),
+ 0,
+ settings.getDepthBits(),
+ settings.getStencilBits(),
+ settings.getSamples());
+
+ width = settings.getWidth();
+ height = settings.getHeight();
+ try{
+ Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ public void uncaughtException(Thread thread, Throwable thrown) {
+ listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
+ }
+ });
+
+ pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs());
+ pbuffer.makeCurrent();
+
+ renderable.set(true);
+
+ logger.info("Offscreen buffer created.");
+ printContextInitInfo();
+ } catch (LWJGLException ex){
+ listener.handleError("Failed to create display", ex);
+ } finally {
+ // TODO: It is possible to avoid "Failed to find pixel format"
+ // error here by creating a default display.
+ }
+ super.internalCreate();
+ listener.initialize();
+ }
+
+ protected boolean checkGLError(){
+ try {
+ Util.checkGLError();
+ } catch (OpenGLException ex){
+ listener.handleError("An OpenGL error has occured!", ex);
+ }
+ // NOTE: Always return true since this is used in an "assert" statement
+ return true;
+ }
+
+ protected void runLoop(){
+ if (!created.get())
+ throw new IllegalStateException();
+
+ if (pbuffer.isBufferLost()){
+ pbuffer.destroy();
+ try{
+ pbuffer = new Pbuffer(width, height, pixelFormat, null);
+ pbuffer.makeCurrent();
+ }catch (LWJGLException ex){
+ listener.handleError("Failed to restore pbuffer content", ex);
+ }
+ }
+
+ listener.update();
+ assert checkGLError();
+
+ renderer.onFrame();
+
+ int frameRate = settings.getFrameRate();
+ if (frameRate >= 1){
+ Display.sync(frameRate);
+ }
+ }
+
+ protected void deinitInThread(){
+ renderable.set(false);
+
+ listener.destroy();
+ renderer.cleanup();
+ pbuffer.destroy();
+ logger.info("Offscreen buffer destroyed.");
+ }
+
+ public void run(){
+ logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
+ initInThread();
+ while (!needClose.get()){
+ runLoop();
+ }
+ deinitInThread();
+ }
+
+ public void destroy(boolean waitFor){
+ needClose.set(true);
+ if (waitFor)
+ waitFor(false);
+ }
+
+ public void create(boolean waitFor){
+ if (created.get()){
+ logger.warning("create() called when pbuffer is already created!");
+ return;
+ }
+
+ new Thread(this, "LWJGL Renderer Thread").start();
+ if (waitFor)
+ waitFor(true);
+ }
+
+ public void restart() {
+ }
+
+ public void setAutoFlushFrames(boolean enabled){
+ }
+
+ public Type getType() {
+ return Type.OffscreenSurface;
+ }
+
+ public MouseInput getMouseInput() {
+ return new DummyMouseInput();
+ }
+
+ public KeyInput getKeyInput() {
+ return new DummyKeyInput();
+ }
+
+ public JoyInput getJoyInput() {
+ return null;
+ }
+
+ public TouchInput getTouchInput() {
+ return null;
+ }
+
+ public void setTitle(String title) {
+ }
+
+}