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.
experimental
Daniel Johansson 9 years ago
parent d8e964b2f0
commit 30cdca7ad7
  1. 3
      common.gradle
  2. 36
      jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java
  3. 1
      jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java
  4. 21
      jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
  5. 6
      jme3-lwjgl3/build.gradle
  6. 369
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java
  7. 25
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
  8. 203
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java
  9. 139
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java
  10. 51
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@ -16,9 +16,6 @@ repositories {
maven { maven {
url "http://nifty-gui.sourceforge.net/nifty-maven-repo" url "http://nifty-gui.sourceforge.net/nifty-maven-repo"
} }
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
}
} }
configurations { configurations {

@ -124,6 +124,42 @@ public final class NativeLibraryLoader {
} }
static { static {
// LWJGL
registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll");
registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll");
registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so");
registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so");
registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib");
registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib");
// OpenAL
// For OSX: Need to add lib prefix when extracting
registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll");
registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll");
registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so");
registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so");
registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib");
registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib");
// LWJGL 3.x
registerNativeLibrary("lwjgl3", Platform.Windows32, "native/windows/lwjgl32.dll");
registerNativeLibrary("lwjgl3", Platform.Windows64, "native/windows/lwjgl.dll");
registerNativeLibrary("lwjgl3", Platform.Linux32, "native/linux/liblwjgl32.so");
registerNativeLibrary("lwjgl3", Platform.Linux64, "native/linux/liblwjgl.so");
registerNativeLibrary("lwjgl3", Platform.MacOSX32, "native/macosx/liblwjgl.dylib");
registerNativeLibrary("lwjgl3", Platform.MacOSX64, "native/macosx/liblwjgl.dylib");
registerNativeLibrary("lwjgl3", Platform.Windows32, "native/windows/jemalloc32.dll");
registerNativeLibrary("lwjgl3", Platform.Windows64, "native/windows/jemalloc.dll");
// OpenAL for LWJGL 3.x
// For OSX: Need to add lib prefix when extracting
registerNativeLibrary("openal-lwjgl3", Platform.Windows32, "native/windows/OpenAL32.dll");
registerNativeLibrary("openal-lwjgl3", Platform.Windows64, "native/windows/OpenAL.dll");
registerNativeLibrary("openal-lwjgl3", Platform.Linux32, "native/linux/libopenal32.so");
registerNativeLibrary("openal-lwjgl3", Platform.Linux64, "native/linux/libopenal.so");
registerNativeLibrary("openal-lwjgl3", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib");
registerNativeLibrary("openal-lwjgl3", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib");
// BulletJme // BulletJme
registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll"); registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll");
registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll"); registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll");

@ -206,7 +206,6 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
+ "Must set with JmeContext.setSystemListner()."); + "Must set with JmeContext.setSystemListner().");
} }
registerNatives();
loadNatives(); loadNatives();
logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion());
if (!initInThread()) { if (!initInThread()) {

@ -162,26 +162,7 @@ public abstract class LwjglContext implements JmeContext {
} }
} }
} }
protected void loadNatives() {
protected void registerNatives() {
// LWJGL
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib");
// For OSX: Need to add lib prefix when extracting
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib");
}
protected void loadNatives() {
if (JmeSystem.isLowPermissions()) { if (JmeSystem.isLowPermissions()) {
return; return;
} }

@ -2,6 +2,12 @@ if (!hasProperty('mainClass')) {
ext.mainClass = '' ext.mainClass = ''
} }
repositories {
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
}
}
dependencies { dependencies {
compile project(':jme3-core') compile project(':jme3-core')
compile project(':jme3-desktop') compile project(':jme3-desktop')

@ -1,369 +0,0 @@
/*
* 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.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import javax.swing.*;
import java.awt.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
public class LwjglCanvas extends LwjglWindow 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(LwjglCanvas.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 long window;
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.FINE, "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, THREAD_NAME);
renderThread.start();
}else if (needClose.get()){
return;
}
logger.log(Level.FINE, "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.FINE, "EDT: OGL has created the display");
}
@Override
public void removeNotify(){
if (needClose.get()){
logger.log(Level.FINE, "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.FINE, "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.FINE, "EDT: Acknowledged receipt of canvas death");
// GL context is dead at this point
super.removeNotify();
}
}
public LwjglCanvas(){
super(Type.Canvas);
canvas = new GLCanvas();
}
public void create(boolean waitFor){
if (renderThread == null){
logger.log(Level.FINE, "MAIN: Creating OGL thread.");
renderThread = new Thread(LwjglCanvas.this, THREAD_NAME);
renderThread.start();
}
// do not do anything.
// superclass's create() will be called at initInThread()
if (waitFor) {
waitFor(true);
}
}
public Canvas getCanvas(){
return canvas;
}
@Override
protected void runLoop(){
if (desiredTask != TASK_NOTHING){
synchronized (taskLock){
switch (desiredTask){
case TASK_CREATE_DISPLAY:
logger.log(Level.FINE, "OGL: Creating display ..");
restoreCanvas();
listener.gainFocus();
desiredTask = TASK_NOTHING;
break;
case TASK_DESTROY_DISPLAY:
logger.log(Level.FINE, "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);
}
}
}
super.runLoop();
}
private void pauseCanvas(){
if (mouseInput != null) {
mouseInput.setCursorVisible(true);
mouseWasCreated = true;
}
/*
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.FINE, "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.FINE, "OGL: Creating display context ..");
// Set renderable to true, since canvas is now displayable.
renderable.set(true);
createContext(settings);
logger.log(Level.FINE, "OGL: Display is active!");
try {
if (mouseWasCreated){
// Mouse.create();
// if (mouseWasGrabbed){
// Mouse.setGrabbed(true);
// mouseWasGrabbed = false;
// }
}
if (keyboardWasCreated){
// Keyboard.create();
// keyboardWasCreated = false;
}
} catch (Exception ex){
logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);
}
SwingUtilities.invokeLater(new Runnable(){
public void run(){
canvas.requestFocus();
}
});
}
/*
*/
/**
* 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.FINE, "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(){
// invalidate the state so renderer can resume operation
if (!USE_SHARED_CONTEXT){
renderer.cleanup();
}
if (window != 0) {
glfwDestroyWindow(window);
}
// TODO: Destroy input
// The canvas is no longer visible,
// but the context thread is still running.
if (!needClose.get()){
renderer.invalidateState();
}
}
/**
* This is called:
* 1) When the context thread starts
* 2) Any time the canvas becomes displayable again.
*/
@Override
protected void createContext(final AppSettings settings) {
// In case canvas is not visible, we still take framerate
// from settings to prevent "100% CPU usage"
allowSwapBuffers = settings.isSwapBuffers();
if (renderable.get()){
if (!runningFirstTime){
// because the display is a different opengl context
// must reset the context state.
if (!USE_SHARED_CONTEXT){
renderer.cleanup();
}
}
super.createContext(settings);
}
// 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;
}
}
}

@ -98,41 +98,20 @@ public abstract class LwjglContext implements JmeContext {
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
protected void registerNatives() {
// LWJGL
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl32.dll");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl.dll");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl32.so");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl.so");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/jemalloc32.dll");
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/jemalloc.dll");
// OpenAL
// For OSX: Need to add lib prefix when extracting
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL.dll");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal32.so");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal.so");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib");
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib");
}
protected void loadNatives() { protected void loadNatives() {
if (JmeSystem.isLowPermissions()) { if (JmeSystem.isLowPermissions()) {
return; return;
} }
if ("LWJGL".equals(settings.getAudioRenderer())) { if ("LWJGL".equals(settings.getAudioRenderer())) {
NativeLibraryLoader.loadNativeLibrary("openal", true); NativeLibraryLoader.loadNativeLibrary("openal-lwjgl3", true);
} }
if (NativeLibraryLoader.isUsingNativeBullet()) { if (NativeLibraryLoader.isUsingNativeBullet()) {
NativeLibraryLoader.loadNativeLibrary("bulletjme", true); NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
} }
NativeLibraryLoader.loadNativeLibrary("lwjgl", true); NativeLibraryLoader.loadNativeLibrary("lwjgl3", true);
} }
protected int getNumSamplesToUse() { protected int getNumSamplesToUse() {

@ -1,203 +0,0 @@
/*
* 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.math.FastMath;
import com.jme3.system.Timer;
import org.lwjgl.glfw.GLFW;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <code>Timer</code> handles the system's time related functionality. This
* allows the calculation of the framerate. To keep the framerate calculation
* accurate, a call to update each frame is required. <code>Timer</code> is a
* singleton object and must be created via the <code>getTimer</code> method.
*
* @author Mark Powell
* @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $
*/
public class LwjglSmoothingTimer extends LwjglTimer {
private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class
.getName());
private long lastFrameDiff;
//frame rate parameters.
private long oldTime;
private float lastTPF, lastFPS;
public static int TIMER_SMOOTHNESS = 32;
private long[] tpf;
private int smoothIndex;
private final static long LWJGL_TIMER_RES = 1;
private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES );
private static float invTimerRezSmooth;
public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES);
private long startTime;
private boolean allSmooth = false;
/**
* Constructor builds a <code>Timer</code> object. All values will be
* initialized to it's default values.
*/
public LwjglSmoothingTimer() {
reset();
//print timer resolution info
logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES);
}
public void reset() {
lastFrameDiff = 0;
lastFPS = 0;
lastTPF = 0;
// init to -1 to indicate this is a new timer.
oldTime = -1;
//reset time
startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS);
tpf = new long[TIMER_SMOOTHNESS];
smoothIndex = TIMER_SMOOTHNESS - 1;
invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS));
// set tpf... -1 values will not be used for calculating the average in update()
for ( int i = tpf.length; --i >= 0; ) {
tpf[i] = -1;
}
}
/**
* @see Timer#getResolution()
*/
public long getResolution() {
return LWJGL_TIMER_RES;
}
/**
* <code>getFrameRate</code> returns the current frame rate since the last
* call to <code>update</code>.
*
* @return the current frame rate.
*/
public float getFrameRate() {
return lastFPS;
}
public float getTimePerFrame() {
return lastTPF;
}
/**
* <code>update</code> recalulates the frame rate based on the previous
* call to update. It is assumed that update is called each frame.
*/
public void update() {
long newTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS);
long oldTime = this.oldTime;
this.oldTime = newTime;
if ( oldTime == -1 ) {
// For the first frame use 60 fps. This value will not be counted in further averages.
// This is done so initialization code between creating the timer and the first
// frame is not counted as a single frame on it's own.
lastTPF = 1 / 60f;
lastFPS = 1f / lastTPF;
return;
}
long frameDiff = newTime - oldTime;
long lastFrameDiff = this.lastFrameDiff;
if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) {
frameDiff = lastFrameDiff *100;
}
this.lastFrameDiff = frameDiff;
tpf[smoothIndex] = frameDiff;
smoothIndex--;
if ( smoothIndex < 0 ) {
smoothIndex = tpf.length - 1;
}
lastTPF = 0.0f;
if (!allSmooth) {
int smoothCount = 0;
for ( int i = tpf.length; --i >= 0; ) {
if ( tpf[i] != -1 ) {
lastTPF += tpf[i];
smoothCount++;
}
}
if (smoothCount == tpf.length)
allSmooth = true;
lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount );
} else {
for ( int i = tpf.length; --i >= 0; ) {
if ( tpf[i] != -1 ) {
lastTPF += tpf[i];
}
}
lastTPF *= invTimerRezSmooth;
}
if ( lastTPF < FastMath.FLT_EPSILON ) {
lastTPF = FastMath.FLT_EPSILON;
}
lastFPS = 1f / lastTPF;
}
/**
* <code>toString</code> returns the string representation of this timer
* in the format: <br>
* <br>
* jme.utility.Timer@1db699b <br>
* Time: {LONG} <br>
* FPS: {LONG} <br>
*
* @return the string representation of this object.
*/
@Override
public String toString() {
String string = super.toString();
string += "\nTime: " + oldTime;
string += "\nFPS: " + getFrameRate();
return string;
}
}

@ -1,139 +0,0 @@
/*
* 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.system.Timer;
import org.lwjgl.glfw.GLFW;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <code>Timer</code> handles the system's time related functionality. This
* allows the calculation of the framerate. To keep the framerate calculation
* accurate, a call to update each frame is required. <code>Timer</code> is a
* singleton object and must be created via the <code>getTimer</code> method.
*
* @author Mark Powell
* @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $
*/
public class LwjglTimer extends Timer {
private static final Logger logger = Logger.getLogger(LwjglTimer.class.getName());
//frame rate parameters.
private long oldTime;
private long startTime;
private float lastTPF, lastFPS;
private final static long LWJGL_TIMER_RES = 1;
private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES );
public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES);
/**
* Constructor builds a <code>Timer</code> object. All values will be
* initialized to it's default values.
*/
public LwjglTimer() {
reset();
logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES);
}
public void reset() {
startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS);
oldTime = getTime();
}
@Override
public float getTimeInSeconds() {
return getTime() * INV_LWJGL_TIMER_RES;
}
/**
* @see Timer#getTime()
*/
public long getTime() {
return ((long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS) - startTime);
}
/**
* @see Timer#getResolution()
*/
public long getResolution() {
return LWJGL_TIMER_RES;
}
/**
* <code>getFrameRate</code> returns the current frame rate since the last
* call to <code>update</code>.
*
* @return the current frame rate.
*/
public float getFrameRate() {
return lastFPS;
}
public float getTimePerFrame() {
return lastTPF;
}
/**
* <code>update</code> recalulates the frame rate based on the previous
* call to update. It is assumed that update is called each frame.
*/
public void update() {
long curTime = getTime();
lastTPF = (curTime - oldTime) * (1.0f / LWJGL_TIMER_RES);
lastFPS = 1.0f / lastTPF;
oldTime = curTime;
}
/**
* <code>toString</code> returns the string representation of this timer
* in the format: <br>
* <br>
* jme.utility.Timer@1db699b <br>
* Time: {LONG} <br>
* FPS: {LONG} <br>
*
* @return the string representation of this object.
*/
@Override
public String toString() {
String string = super.toString();
string += "\nTime: " + oldTime;
string += "\nFPS: " + getFrameRate();
return string;
}
}

@ -42,6 +42,7 @@ import com.jme3.input.lwjgl.GlfwMouseInput;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext; import com.jme3.system.JmeContext;
import com.jme3.system.JmeSystem; import com.jme3.system.JmeSystem;
import com.jme3.system.NanoTimer;
import org.lwjgl.Sys; import org.lwjgl.Sys;
import org.lwjgl.glfw.*; import org.lwjgl.glfw.*;
@ -73,6 +74,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
protected boolean allowSwapBuffers = false; protected boolean allowSwapBuffers = false;
private long window = -1; private long window = -1;
private final JmeContext.Type type; private final JmeContext.Type type;
private int frameRateLimit = -1;
private double frameSleepTime;
private GLFWErrorCallback errorCallback; private GLFWErrorCallback errorCallback;
private GLFWWindowSizeCallback windowSizeCallback; private GLFWWindowSizeCallback windowSizeCallback;
@ -160,16 +163,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits()); glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits());
glfwWindowHint(GLFW_SAMPLES, settings.getSamples()); glfwWindowHint(GLFW_SAMPLES, settings.getSamples());
glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE); glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE);
glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency());
int frameRateCap = settings.getFrameRate();
if (!autoFlush) {
frameRateCap = 20;
}
if (frameRateCap > 0) {
glfwWindowHint(GLFW_REFRESH_RATE, frameRateCap);
}
// Not sure how else to support bits per pixel // Not sure how else to support bits per pixel
if (settings.getBitsPerPixel() == 24) { if (settings.getBitsPerPixel() == 24) {
@ -289,7 +283,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
}); });
} }
timer = new LwjglTimer(); timer = new NanoTimer();
// For canvas, this will create a pbuffer, // For canvas, this will create a pbuffer,
// allowing us to query information. // allowing us to query information.
@ -303,7 +297,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
} catch (Exception ex) { } catch (Exception ex) {
try { try {
if (window != -1) { if (window != -1) {
//glfwSetWindowShouldClose(window, GL_TRUE);
glfwDestroyWindow(window); glfwDestroyWindow(window);
} }
} catch (Exception ex2) { } catch (Exception ex2) {
@ -360,11 +353,41 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
if (renderer != null) { if (renderer != null) {
renderer.postFrame(); renderer.postFrame();
} }
if (autoFlush) {
if (frameRateLimit != getSettings().getFrameRate()) {
setFrameRateLimit(getSettings().getFrameRate());
}
} else if (frameRateLimit != 20) {
setFrameRateLimit(20);
}
// If software frame rate limiting has been asked for, lets calculate sleep time based on a base value calculated
// from 1000 / frameRateLimit in milliseconds subtracting the time it has taken to render last frame.
// This gives an approximate limit within 3 fps of the given frame rate limit.
if (frameRateLimit > 0) {
final double sleep = frameSleepTime - (timer.getTimePerFrame() / 1000.0);
final long sleepMillis = (long) sleep;
final int additionalNanos = (int) ((sleep - sleepMillis) * 1000000.0);
if (sleepMillis >= 0 && additionalNanos >= 0) {
try {
Thread.sleep(sleepMillis, additionalNanos);
} catch (InterruptedException ignored) {
}
}
}
}
private void setFrameRateLimit(int frameRateLimit) {
this.frameRateLimit = frameRateLimit;
frameSleepTime = 1000.0 / this.frameRateLimit;
} }
/** /**
* De-initialize in the OpenGL thread. * De-initialize in the OpenGL thread.
*/ */
protected void deinitInThread() { protected void deinitInThread() {
destroyContext(); destroyContext();
@ -379,7 +402,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
+ "Must set with JmeContext.setSystemListener()."); + "Must set with JmeContext.setSystemListener().");
} }
registerNatives();
loadNatives(); loadNatives();
LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion());
@ -445,6 +467,9 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
return window; return window;
} }
// TODO: Implement support for window icon when GLFW supports it.
private ByteBuffer[] imagesToByteBuffers(Object[] images) { private ByteBuffer[] imagesToByteBuffers(Object[] images) {
ByteBuffer[] out = new ByteBuffer[images.length]; ByteBuffer[] out = new ByteBuffer[images.length];
for (int i = 0; i < images.length; i++) { for (int i = 0; i < images.length; i++) {

Loading…
Cancel
Save