* 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
This commit is contained in:
parent
9c6ca69b34
commit
bd828d629c
@ -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 <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){
|
||||
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 <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){
|
||||
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?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user