jmonkeyengine/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java
Daniel Johansson 30cdca7ad7 Native library loading is back to the way it used to be with the addition of LWJGL 3.x libraries added with a different key.
Moved LWJGL 3.x repository definition to build.grade in that module.
Fixed an issue where frame rate limit would cause GLFW frequency window hint to be set rather than use a software limiter.
Removed LWJGLTimer for lwjgl3 module, no need for it any more, we'll just use the NanoTimer.
Removed LWJGLCanvas for lwjgl3 module, can't implement this so we'll leave it for now.
2015-09-17 11:59:44 +01:00

276 lines
8.5 KiB
Java

/*
* Copyright (c) 2009-2012 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.lwjgl.JInputJoyInput;
import com.jme3.input.lwjgl.LwjglKeyInput;
import com.jme3.input.lwjgl.LwjglMouseInput;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
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.Display;
import org.lwjgl.opengl.OpenGLException;
import org.lwjgl.opengl.Util;
public abstract class LwjglAbstractDisplay extends LwjglContext implements Runnable {
private static final Logger logger = Logger.getLogger(LwjglAbstractDisplay.class.getName());
protected AtomicBoolean needClose = new AtomicBoolean(false);
protected boolean wasActive = false;
protected int frameRate = 0;
protected boolean autoFlush = true;
protected boolean allowSwapBuffers = false;
/**
* @return Type.Display or Type.Canvas
*/
public abstract Type getType();
/**
* Set the title if its a windowed display
* @param title
*/
public abstract void setTitle(String title);
/**
* Restart if its a windowed or full-screen display.
*/
public abstract void restart();
/**
* Apply the settings, changing resolution, etc.
* @param settings
*/
protected abstract void createContext(AppSettings settings) throws LWJGLException;
/**
* Destroy the context.
*/
protected abstract void destroyContext();
/**
* Does LWJGL display initialization in the OpenGL thread
*/
protected boolean initInThread(){
try {
if (!JmeSystem.isLowPermissions()){
// Enable uncaught exception handler only for current thread
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable thrown) {
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
if (needClose.get()){
// listener.handleError() has requested the
// context to close. Satisfy request.
deinitInThread();
}
}
});
}
// For canvas, this will create a pbuffer,
// allowing us to query information.
// When the canvas context becomes available, it will
// be replaced seamlessly.
createContext(settings);
printContextInitInfo();
created.set(true);
super.internalCreate();
} catch (Exception ex){
try {
if (Display.isCreated())
Display.destroy();
} catch (Exception ex2){
logger.log(Level.WARNING, null, ex2);
}
listener.handleError("Failed to create display", ex);
return false; // if we failed to create display, do not continue
}
listener.initialize();
return true;
}
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;
}
/**
* execute one iteration of the render loop in the OpenGL thread
*/
protected void runLoop(){
if (!created.get())
throw new IllegalStateException();
listener.update();
// All this does is call swap buffers
// If the canvas is not active, there's no need to waste time
// doing that ..
if (renderable.get()){
assert checkGLError();
// calls swap buffers, etc.
try {
if (allowSwapBuffers && autoFlush) {
Display.update(false);
}
} catch (Throwable ex){
listener.handleError("Error while swapping buffers", ex);
}
}
int frameRateCap;
if (autoFlush) {
frameRateCap = frameRate;
} else {
frameRateCap = 20;
}
if (frameRateCap > 0) {
// Cap framerate
Display.sync(frameRateCap);
}
// check input after we synchronize with framerate.
// this reduces input lag.
if (renderable.get()){
Display.processMessages();
}
// Subclasses just call GLObjectManager clean up objects here
// it is safe .. for now.
renderer.postFrame();
}
/**
* De-initialize in the OpenGL thread.
*/
protected void deinitInThread(){
destroyContext();
listener.destroy();
logger.fine("Display destroyed.");
super.internalDestroy();
}
public void run(){
if (listener == null) {
throw new IllegalStateException("SystemListener is not set on context!"
+ "Must set with JmeContext.setSystemListner().");
}
loadNatives();
logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion());
if (!initInThread()) {
logger.log(Level.SEVERE, "Display initialization failed. Cannot continue.");
return;
}
while (true){
if (renderable.get()){
if (Display.isCloseRequested())
listener.requestClose(false);
if (wasActive != Display.isActive()) {
if (!wasActive) {
listener.gainFocus();
timer.reset();
wasActive = true;
} else {
listener.loseFocus();
wasActive = false;
}
}
}
runLoop();
if (needClose.get())
break;
}
deinitInThread();
}
public JoyInput getJoyInput() {
if (joyInput == null){
joyInput = new JInputJoyInput();
}
return joyInput;
}
public MouseInput getMouseInput() {
if (mouseInput == null){
mouseInput = new LwjglMouseInput(this);
}
return mouseInput;
}
public KeyInput getKeyInput() {
if (keyInput == null){
keyInput = new LwjglKeyInput(this);
}
return keyInput;
}
public TouchInput getTouchInput() {
return null;
}
public void setAutoFlushFrames(boolean enabled){
this.autoFlush = enabled;
}
public void destroy(boolean waitFor){
needClose.set(true);
if (waitFor)
waitFor(false);
}
}