* Fixed issue with default samples value causing "No support for WGL_ARB_multisample" error

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9021 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..rd 13 years ago
parent 9c6ca69b34
commit bd828d629c
  1. 960
      engine/src/lwjgl/com/jme3/system/lwjgl/LwjglCanvas.java
  2. 6
      engine/src/lwjgl/com/jme3/system/lwjgl/LwjglDisplay.java
  3. 392
      engine/src/lwjgl/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java

@ -1,478 +1,482 @@
/* F/*
* Copyright (c) 2009-2010 jMonkeyEngine * Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.system.lwjgl; package com.jme3.system.lwjgl;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext; import com.jme3.system.JmeCanvasContext;
import com.jme3.system.JmeContext.Type; import com.jme3.system.JmeContext.Type;
import com.jme3.system.JmeSystem; import com.jme3.system.JmeSystem;
import com.jme3.system.Platform; import com.jme3.system.Platform;
import java.awt.Canvas; import java.awt.Canvas;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.Pbuffer; import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat; import org.lwjgl.opengl.PixelFormat;
public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext { public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext {
protected static final int TASK_NOTHING = 0, protected static final int TASK_NOTHING = 0,
TASK_DESTROY_DISPLAY = 1, TASK_DESTROY_DISPLAY = 1,
TASK_CREATE_DISPLAY = 2, TASK_CREATE_DISPLAY = 2,
TASK_COMPLETE = 3; TASK_COMPLETE = 3;
// protected static final boolean USE_SHARED_CONTEXT = // protected static final boolean USE_SHARED_CONTEXT =
// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true")); // Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true"));
protected static final boolean USE_SHARED_CONTEXT = false; protected static final boolean USE_SHARED_CONTEXT = false;
private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName()); private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());
private Canvas canvas; private Canvas canvas;
private int width; private int width;
private int height; private int height;
private final Object taskLock = new Object(); private final Object taskLock = new Object();
private int desiredTask = TASK_NOTHING; private int desiredTask = TASK_NOTHING;
private Thread renderThread; private Thread renderThread;
private boolean runningFirstTime = true; private boolean runningFirstTime = true;
private boolean mouseWasGrabbed = false; private boolean mouseWasGrabbed = false;
private boolean mouseWasCreated = false; private boolean mouseWasCreated = false;
private boolean keyboardWasCreated = false; private boolean keyboardWasCreated = false;
private Pbuffer pbuffer; private Pbuffer pbuffer;
private PixelFormat pbufferFormat; private PixelFormat pbufferFormat;
private PixelFormat canvasFormat; private PixelFormat canvasFormat;
private class GLCanvas extends Canvas { private class GLCanvas extends Canvas {
@Override @Override
public void addNotify(){ public void addNotify(){
super.addNotify(); super.addNotify();
if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED) if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED)
return; // already destroyed. return; // already destroyed.
if (renderThread == null){ if (renderThread == null){
logger.log(Level.INFO, "EDT: Creating OGL thread."); logger.log(Level.INFO, "EDT: Creating OGL thread.");
// Also set some settings on the canvas here. // Also set some settings on the canvas here.
// So we don't do it outside the AWT thread. // So we don't do it outside the AWT thread.
canvas.setFocusable(true); canvas.setFocusable(true);
canvas.setIgnoreRepaint(true); canvas.setIgnoreRepaint(true);
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread"); renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
renderThread.start(); renderThread.start();
}else if (needClose.get()){ }else if (needClose.get()){
return; return;
} }
logger.log(Level.INFO, "EDT: Telling OGL to create display .."); logger.log(Level.INFO, "EDT: Telling OGL to create display ..");
synchronized (taskLock){ synchronized (taskLock){
desiredTask = TASK_CREATE_DISPLAY; desiredTask = TASK_CREATE_DISPLAY;
// while (desiredTask != TASK_COMPLETE){ // while (desiredTask != TASK_COMPLETE){
// try { // try {
// taskLock.wait(); // taskLock.wait();
// } catch (InterruptedException ex) { // } catch (InterruptedException ex) {
// return; // return;
// } // }
// } // }
// desiredTask = TASK_NOTHING; // desiredTask = TASK_NOTHING;
} }
// logger.log(Level.INFO, "EDT: OGL has created the display"); // logger.log(Level.INFO, "EDT: OGL has created the display");
} }
@Override @Override
public void removeNotify(){ public void removeNotify(){
if (needClose.get()){ if (needClose.get()){
logger.log(Level.INFO, "EDT: Application is stopped. Not restoring canvas."); logger.log(Level.INFO, "EDT: Application is stopped. Not restoring canvas.");
super.removeNotify(); super.removeNotify();
return; return;
} }
// We must tell GL context to shutdown and wait for it to // We must tell GL context to shutdown and wait for it to
// shutdown, otherwise, issues will occur. // shutdown, otherwise, issues will occur.
logger.log(Level.INFO, "EDT: Telling OGL to destroy display .."); logger.log(Level.INFO, "EDT: Telling OGL to destroy display ..");
synchronized (taskLock){ synchronized (taskLock){
desiredTask = TASK_DESTROY_DISPLAY; desiredTask = TASK_DESTROY_DISPLAY;
while (desiredTask != TASK_COMPLETE){ while (desiredTask != TASK_COMPLETE){
try { try {
taskLock.wait(); taskLock.wait();
} catch (InterruptedException ex){ } catch (InterruptedException ex){
super.removeNotify(); super.removeNotify();
return; return;
} }
} }
desiredTask = TASK_NOTHING; desiredTask = TASK_NOTHING;
} }
logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death"); logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death");
// GL context is dead at this point // GL context is dead at this point
super.removeNotify(); super.removeNotify();
} }
} }
public LwjglCanvas(){ public LwjglCanvas(){
super(); super();
canvas = new GLCanvas(); canvas = new GLCanvas();
} }
@Override @Override
public Type getType() { public Type getType() {
return Type.Canvas; return Type.Canvas;
} }
public void create(boolean waitFor){ public void create(boolean waitFor){
if (renderThread == null){ if (renderThread == null){
logger.log(Level.INFO, "MAIN: Creating OGL thread."); logger.log(Level.INFO, "MAIN: Creating OGL thread.");
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread"); renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
renderThread.start(); renderThread.start();
} }
// do not do anything. // do not do anything.
// superclass's create() will be called at initInThread() // superclass's create() will be called at initInThread()
if (waitFor) if (waitFor)
waitFor(true); waitFor(true);
} }
@Override @Override
public void setTitle(String title) { public void setTitle(String title) {
} }
@Override @Override
public void restart() { public void restart() {
frameRate = settings.getFrameRate(); frameRate = settings.getFrameRate();
// TODO: Handle other cases, like change of pixel format, etc. // TODO: Handle other cases, like change of pixel format, etc.
} }
public Canvas getCanvas(){ public Canvas getCanvas(){
return canvas; return canvas;
} }
@Override @Override
protected void runLoop(){ protected void runLoop(){
if (desiredTask != TASK_NOTHING){ if (desiredTask != TASK_NOTHING){
synchronized (taskLock){ synchronized (taskLock){
switch (desiredTask){ switch (desiredTask){
case TASK_CREATE_DISPLAY: case TASK_CREATE_DISPLAY:
logger.log(Level.INFO, "OGL: Creating display .."); logger.log(Level.INFO, "OGL: Creating display ..");
restoreCanvas(); restoreCanvas();
listener.gainFocus(); listener.gainFocus();
desiredTask = TASK_NOTHING; desiredTask = TASK_NOTHING;
break; break;
case TASK_DESTROY_DISPLAY: case TASK_DESTROY_DISPLAY:
logger.log(Level.INFO, "OGL: Destroying display .."); logger.log(Level.INFO, "OGL: Destroying display ..");
listener.loseFocus(); listener.loseFocus();
pauseCanvas(); pauseCanvas();
break; break;
} }
desiredTask = TASK_COMPLETE; desiredTask = TASK_COMPLETE;
taskLock.notifyAll(); taskLock.notifyAll();
} }
} }
if (renderable.get()){ if (renderable.get()){
int newWidth = Math.max(canvas.getWidth(), 1); int newWidth = Math.max(canvas.getWidth(), 1);
int newHeight = Math.max(canvas.getHeight(), 1); int newHeight = Math.max(canvas.getHeight(), 1);
if (width != newWidth || height != newHeight){ if (width != newWidth || height != newHeight){
width = newWidth; width = newWidth;
height = newHeight; height = newHeight;
if (listener != null){ if (listener != null){
listener.reshape(width, height); listener.reshape(width, height);
} }
} }
}else{ }else{
if (frameRate <= 0){ if (frameRate <= 0){
// NOTE: MUST be done otherwise // NOTE: MUST be done otherwise
// Windows OS will freeze // Windows OS will freeze
Display.sync(30); Display.sync(30);
} }
} }
super.runLoop(); super.runLoop();
} }
private void pauseCanvas(){ private void pauseCanvas(){
if (Mouse.isCreated()){ if (Mouse.isCreated()){
if (Mouse.isGrabbed()){ if (Mouse.isGrabbed()){
Mouse.setGrabbed(false); Mouse.setGrabbed(false);
mouseWasGrabbed = true; mouseWasGrabbed = true;
} }
mouseWasCreated = true; mouseWasCreated = true;
Mouse.destroy(); Mouse.destroy();
} }
if (Keyboard.isCreated()){ if (Keyboard.isCreated()){
keyboardWasCreated = true; keyboardWasCreated = true;
Keyboard.destroy(); Keyboard.destroy();
} }
renderable.set(false); renderable.set(false);
destroyContext(); destroyContext();
} }
/** /**
* Called to restore the canvas. * Called to restore the canvas.
*/ */
private void restoreCanvas(){ private void restoreCanvas(){
logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable.."); logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");
while (!canvas.isDisplayable()){ while (!canvas.isDisplayable()){
try { try {
Thread.sleep(10); Thread.sleep(10);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex); logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
} }
} }
logger.log(Level.INFO, "OGL: Creating display context .."); logger.log(Level.INFO, "OGL: Creating display context ..");
// Set renderable to true, since canvas is now displayable. // Set renderable to true, since canvas is now displayable.
renderable.set(true); renderable.set(true);
createContext(settings); createContext(settings);
logger.log(Level.INFO, "OGL: Display is active!"); logger.log(Level.INFO, "OGL: Display is active!");
try { try {
if (mouseWasCreated){ if (mouseWasCreated){
Mouse.create(); Mouse.create();
if (mouseWasGrabbed){ if (mouseWasGrabbed){
Mouse.setGrabbed(true); Mouse.setGrabbed(true);
mouseWasGrabbed = false; mouseWasGrabbed = false;
} }
} }
if (keyboardWasCreated){ if (keyboardWasCreated){
Keyboard.create(); Keyboard.create();
keyboardWasCreated = false; keyboardWasCreated = false;
} }
} catch (LWJGLException ex){ } catch (LWJGLException ex){
logger.log(Level.SEVERE, "Encountered exception when restoring input", ex); logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);
} }
SwingUtilities.invokeLater(new Runnable(){ SwingUtilities.invokeLater(new Runnable(){
public void run(){ public void run(){
canvas.requestFocus(); canvas.requestFocus();
} }
}); });
} }
/** /**
* It seems it is best to use one pixel format for all shared contexts. * It seems it is best to use one pixel format for all shared contexts.
* @see <a href="http://developer.apple.com/library/mac/#qa/qa1248/_index.html">http://developer.apple.com/library/mac/#qa/qa1248/_index.html</a> * @see <a href="http://developer.apple.com/library/mac/#qa/qa1248/_index.html">http://developer.apple.com/library/mac/#qa/qa1248/_index.html</a>
*/ */
protected PixelFormat acquirePixelFormat(boolean forPbuffer){ protected PixelFormat acquirePixelFormat(boolean forPbuffer){
if (forPbuffer){ if (forPbuffer){
// Use 0 samples for pbuffer format, prevents // Use 0 samples for pbuffer format, prevents
// crashes on bad drivers // crashes on bad drivers
if (pbufferFormat == null){ if (pbufferFormat == null){
pbufferFormat = new PixelFormat(settings.getBitsPerPixel(), pbufferFormat = new PixelFormat(settings.getBitsPerPixel(),
0, 0,
settings.getDepthBits(), settings.getDepthBits(),
settings.getStencilBits(), settings.getStencilBits(),
0); 0);
} }
return pbufferFormat; return pbufferFormat;
}else{ }else{
if (canvasFormat == null){ if (canvasFormat == null){
canvasFormat = new PixelFormat(settings.getBitsPerPixel(), int samples = 0;
0, if (settings.getSamples() > 1){
settings.getDepthBits(), samples = settings.getSamples();
settings.getStencilBits(), }
settings.getSamples()); canvasFormat = new PixelFormat(settings.getBitsPerPixel(),
} 0,
return canvasFormat; 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!"); * Makes sure the pbuffer is available and ready for use
pbuffer.destroy(); */
pbuffer = null; protected void makePbufferAvailable() throws LWJGLException{
} if (pbuffer != null && pbuffer.isBufferLost()){
logger.log(Level.WARNING, "PBuffer was lost!");
if (pbuffer == null) { pbuffer.destroy();
pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); pbuffer = null;
pbuffer.makeCurrent(); }
logger.log(Level.INFO, "OGL: Pbuffer has been created");
if (pbuffer == null) {
// Any created objects are no longer valid pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);
if (!runningFirstTime){ pbuffer.makeCurrent();
renderer.resetGLObjects(); logger.log(Level.INFO, "OGL: Pbuffer has been created");
}
} // Any created objects are no longer valid
if (!runningFirstTime){
pbuffer.makeCurrent(); renderer.resetGLObjects();
if (!pbuffer.isCurrent()){ }
throw new LWJGLException("Pbuffer cannot be made current"); }
}
} pbuffer.makeCurrent();
if (!pbuffer.isCurrent()){
protected void destroyPbuffer(){ throw new LWJGLException("Pbuffer cannot be made current");
if (pbuffer != null){ }
if (!pbuffer.isBufferLost()){ }
pbuffer.destroy();
} protected void destroyPbuffer(){
pbuffer = null; 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(){ * This is called:
try { * 1) When the context thread ends
// invalidate the state so renderer can resume operation * 2) Any time the canvas becomes non-displayable
if (!USE_SHARED_CONTEXT){ */
renderer.cleanup(); protected void destroyContext(){
} try {
// invalidate the state so renderer can resume operation
if (Display.isCreated()){ if (!USE_SHARED_CONTEXT){
/* FIXES: renderer.cleanup();
* org.lwjgl.LWJGLException: X Error }
* BadWindow (invalid Window parameter) request_code: 2 minor_code: 0
* if (Display.isCreated()){
* Destroying keyboard early prevents the error above, triggered /* FIXES:
* by destroying keyboard in by Display.destroy() or Display.setParent(null). * org.lwjgl.LWJGLException: X Error
* Therefore Keyboard.destroy() should precede any of these calls. * BadWindow (invalid Window parameter) request_code: 2 minor_code: 0
*/ *
if (Keyboard.isCreated()){ * Destroying keyboard early prevents the error above, triggered
// Should only happen if called in * by destroying keyboard in by Display.destroy() or Display.setParent(null).
// LwjglAbstractDisplay.deinitInThread(). * Therefore Keyboard.destroy() should precede any of these calls.
Keyboard.destroy(); */
} if (Keyboard.isCreated()){
// Should only happen if called in
//try { // LwjglAbstractDisplay.deinitInThread().
// NOTE: On Windows XP, not calling setParent(null) Keyboard.destroy();
// freezes the application. }
// On Mac it freezes the application.
// On Linux it fixes a crash with X Window System. //try {
if (JmeSystem.getPlatform() == Platform.Windows32 // NOTE: On Windows XP, not calling setParent(null)
|| JmeSystem.getPlatform() == Platform.Windows64){ // freezes the application.
//Display.setParent(null); // On Mac it freezes the application.
} // On Linux it fixes a crash with X Window System.
//} catch (LWJGLException ex) { if (JmeSystem.getPlatform() == Platform.Windows32
// logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex); || JmeSystem.getPlatform() == Platform.Windows64){
//} //Display.setParent(null);
}
Display.destroy(); //} catch (LWJGLException ex) {
} // logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);
//}
// The canvas is no longer visible,
// but the context thread is still running. Display.destroy();
if (!needClose.get()){ }
// MUST make sure there's still a context current here ..
// Display is dead, make pbuffer available to the system // The canvas is no longer visible,
makePbufferAvailable(); // but the context thread is still running.
if (!needClose.get()){
renderer.invalidateState(); // MUST make sure there's still a context current here ..
}else{ // Display is dead, make pbuffer available to the system
// The context thread is no longer running. makePbufferAvailable();
// Destroy pbuffer.
destroyPbuffer(); renderer.invalidateState();
} }else{
} catch (LWJGLException ex) { // The context thread is no longer running.
listener.handleError("Failed make pbuffer available", ex); // 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 * This is called:
protected void createContext(AppSettings settings) { * 1) When the context thread starts
// In case canvas is not visible, we still take framerate * 2) Any time the canvas becomes displayable again.
// from settings to prevent "100% CPU usage" */
frameRate = settings.getFrameRate(); @Override
protected void createContext(AppSettings settings) {
try { // In case canvas is not visible, we still take framerate
if (renderable.get()){ // from settings to prevent "100% CPU usage"
if (!runningFirstTime){ frameRate = settings.getFrameRate();
// because the display is a different opengl context
// must reset the context state. try {
if (!USE_SHARED_CONTEXT){ if (renderable.get()){
renderer.cleanup(); if (!runningFirstTime){
} // because the display is a different opengl context
} // must reset the context state.
if (!USE_SHARED_CONTEXT){
// if the pbuffer is currently active, renderer.cleanup();
// make sure to deactivate it }
destroyPbuffer(); }
if (Keyboard.isCreated()){ // if the pbuffer is currently active,
Keyboard.destroy(); // make sure to deactivate it
} destroyPbuffer();
try { if (Keyboard.isCreated()){
Thread.sleep(1000); Keyboard.destroy();
} catch (InterruptedException ex) { }
}
try {
Display.setVSyncEnabled(settings.isVSync()); Thread.sleep(1000);
Display.setParent(canvas); } catch (InterruptedException ex) {
}
if (USE_SHARED_CONTEXT){
Display.create(acquirePixelFormat(false), pbuffer); Display.setVSyncEnabled(settings.isVSync());
}else{ Display.setParent(canvas);
Display.create(acquirePixelFormat(false));
} if (USE_SHARED_CONTEXT){
Display.create(acquirePixelFormat(false), pbuffer);
renderer.invalidateState(); }else{
}else{ Display.create(acquirePixelFormat(false));
// First create the pbuffer, if it is needed. }
makePbufferAvailable();
} renderer.invalidateState();
}else{
// At this point, the OpenGL context is active. // First create the pbuffer, if it is needed.
if (runningFirstTime){ makePbufferAvailable();
// THIS is the part that creates the renderer. }
// It must always be called, now that we have the pbuffer workaround.
initContextFirstTime(); // At this point, the OpenGL context is active.
runningFirstTime = false; if (runningFirstTime){
} // THIS is the part that creates the renderer.
} catch (LWJGLException ex) { // It must always be called, now that we have the pbuffer workaround.
listener.handleError("Failed to initialize OpenGL context", ex); initContextFirstTime();
// TODO: Fix deadlock that happens after the error (throw runtime exception?) runningFirstTime = false;
} }
} } catch (LWJGLException ex) {
} listener.handleError("Failed to initialize OpenGL context", ex);
// TODO: Fix deadlock that happens after the error (throw runtime exception?)
}
}
}

@ -81,11 +81,15 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
displayMode = new DisplayMode(settings.getWidth(), settings.getHeight()); displayMode = new DisplayMode(settings.getWidth(), settings.getHeight());
} }
int samples = 0;
if (settings.getSamples() > 1){
samples = settings.getSamples();
}
PixelFormat pf = new PixelFormat(settings.getBitsPerPixel(), PixelFormat pf = new PixelFormat(settings.getBitsPerPixel(),
0, 0,
settings.getDepthBits(), settings.getDepthBits(),
settings.getStencilBits(), settings.getStencilBits(),
settings.getSamples()); samples);
frameRate = settings.getFrameRate(); frameRate = settings.getFrameRate();
logger.log(Level.INFO, "Selected display mode: {0}", displayMode); logger.log(Level.INFO, "Selected display mode: {0}", displayMode);

@ -1,194 +1,198 @@
/* /*
* Copyright (c) 2009-2010 jMonkeyEngine * Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.system.lwjgl; package com.jme3.system.lwjgl;
import com.jme3.input.JoyInput; import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput; import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
import com.jme3.input.TouchInput; import com.jme3.input.TouchInput;
import com.jme3.input.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyKeyInput;
import com.jme3.input.dummy.DummyMouseInput; import com.jme3.input.dummy.DummyMouseInput;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
import org.lwjgl.Sys; import org.lwjgl.Sys;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;
public class LwjglOffscreenBuffer extends LwjglContext implements Runnable { public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName()); private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName());
private Pbuffer pbuffer; private Pbuffer pbuffer;
protected AtomicBoolean needClose = new AtomicBoolean(false); protected AtomicBoolean needClose = new AtomicBoolean(false);
private int width; private int width;
private int height; private int height;
private PixelFormat pixelFormat; private PixelFormat pixelFormat;
protected void initInThread(){ protected void initInThread(){
if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0){ if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0){
logger.severe("Offscreen surfaces are not supported."); logger.severe("Offscreen surfaces are not supported.");
return; return;
} }
pixelFormat = new PixelFormat(settings.getBitsPerPixel(), int samples = 0;
0, if (settings.getSamples() > 1){
settings.getDepthBits(), samples = settings.getSamples();
settings.getStencilBits(), }
settings.getSamples()); pixelFormat = new PixelFormat(settings.getBitsPerPixel(),
0,
width = settings.getWidth(); settings.getDepthBits(),
height = settings.getHeight(); settings.getStencilBits(),
try{ settings.getSamples());
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable thrown) { width = settings.getWidth();
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown); height = settings.getHeight();
} try{
}); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable thrown) {
pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs()); listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
pbuffer.makeCurrent(); }
});
renderable.set(true);
pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs());
logger.info("Offscreen buffer created."); pbuffer.makeCurrent();
printContextInitInfo();
} catch (LWJGLException ex){ renderable.set(true);
listener.handleError("Failed to create display", ex);
} finally { logger.info("Offscreen buffer created.");
// TODO: It is possible to avoid "Failed to find pixel format" printContextInitInfo();
// error here by creating a default display. } catch (LWJGLException ex){
} listener.handleError("Failed to create display", ex);
super.internalCreate(); } finally {
listener.initialize(); // TODO: It is possible to avoid "Failed to find pixel format"
} // error here by creating a default display.
}
protected boolean checkGLError(){ super.internalCreate();
try { listener.initialize();
Util.checkGLError(); }
} catch (OpenGLException ex){
listener.handleError("An OpenGL error has occured!", ex); protected boolean checkGLError(){
} try {
// NOTE: Always return true since this is used in an "assert" statement Util.checkGLError();
return true; } catch (OpenGLException ex){
} listener.handleError("An OpenGL error has occured!", ex);
}
protected void runLoop(){ // NOTE: Always return true since this is used in an "assert" statement
if (!created.get()) return true;
throw new IllegalStateException(); }
if (pbuffer.isBufferLost()){ protected void runLoop(){
pbuffer.destroy(); if (!created.get())
try{ throw new IllegalStateException();
pbuffer = new Pbuffer(width, height, pixelFormat, null);
pbuffer.makeCurrent(); if (pbuffer.isBufferLost()){
}catch (LWJGLException ex){ pbuffer.destroy();
listener.handleError("Failed to restore pbuffer content", ex); try{
} pbuffer = new Pbuffer(width, height, pixelFormat, null);
} pbuffer.makeCurrent();
}catch (LWJGLException ex){
listener.update(); listener.handleError("Failed to restore pbuffer content", ex);
assert checkGLError(); }
}
renderer.onFrame();
listener.update();
int frameRate = settings.getFrameRate(); assert checkGLError();
if (frameRate >= 1){
Display.sync(frameRate); renderer.onFrame();
}
} int frameRate = settings.getFrameRate();
if (frameRate >= 1){
protected void deinitInThread(){ Display.sync(frameRate);
renderable.set(false); }
}
listener.destroy();
renderer.cleanup(); protected void deinitInThread(){
pbuffer.destroy(); renderable.set(false);
logger.info("Offscreen buffer destroyed.");
} listener.destroy();
renderer.cleanup();
public void run(){ pbuffer.destroy();
logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion()); logger.info("Offscreen buffer destroyed.");
initInThread(); }
while (!needClose.get()){
runLoop(); public void run(){
} logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
deinitInThread(); initInThread();
} while (!needClose.get()){
runLoop();
public void destroy(boolean waitFor){ }
needClose.set(true); deinitInThread();
if (waitFor) }
waitFor(false);
} public void destroy(boolean waitFor){
needClose.set(true);
public void create(boolean waitFor){ if (waitFor)
if (created.get()){ waitFor(false);
logger.warning("create() called when pbuffer is already created!"); }
return;
} public void create(boolean waitFor){
if (created.get()){
new Thread(this, "LWJGL Renderer Thread").start(); logger.warning("create() called when pbuffer is already created!");
if (waitFor) return;
waitFor(true); }
}
new Thread(this, "LWJGL Renderer Thread").start();
public void restart() { if (waitFor)
} waitFor(true);
}
public void setAutoFlushFrames(boolean enabled){
} public void restart() {
}
public Type getType() {
return Type.OffscreenSurface; public void setAutoFlushFrames(boolean enabled){
} }
public MouseInput getMouseInput() { public Type getType() {
return new DummyMouseInput(); return Type.OffscreenSurface;
} }
public KeyInput getKeyInput() { public MouseInput getMouseInput() {
return new DummyKeyInput(); return new DummyMouseInput();
} }
public JoyInput getJoyInput() { public KeyInput getKeyInput() {
return null; return new DummyKeyInput();
} }
public TouchInput getTouchInput() { public JoyInput getJoyInput() {
return null; return null;
} }
public void setTitle(String title) { public TouchInput getTouchInput() {
} return null;
}
}
public void setTitle(String title) {
}
}

Loading…
Cancel
Save