Преглед на файлове

LWJGL3 improvements

 * Added key remapping for GLFW key constants
 * Rename AppSettings.getGammaCorrection() to isGammaCorrection()
 * Use LWJGL3 artifacts from maven
 * Minor compatibility changes for LWJGL 3.0.0b
 * Fixed some minor bugs in LwjglWindow
Kirill Vainer преди 9 години
родител
ревизия
2ca55c8b3a

+ 12 - 3
jme3-core/src/main/java/com/jme3/input/KeyInput.java

@@ -36,6 +36,11 @@ package com.jme3.input;
  */
 public interface KeyInput extends Input {
 
+    /**
+     * unmapped key.
+     */
+    public static final int KEY_UNKNOWN = 0x00;
+
     /**
      * escape key.
      */
@@ -518,17 +523,17 @@ public interface KeyInput extends Input {
      * delete key.
      */
     public static final int KEY_DELETE = 0xD3;
-    
+
     /**
      * Left "Windows" key on PC keyboards, left "Option" key on Mac keyboards.
      */
     public static final int KEY_LMETA  = 0xDB;
-    
+
     /**
      * Right "Windows" key on PC keyboards, right "Option" key on Mac keyboards.
      */
     public static final int KEY_RMETA = 0xDC;
-    
+
     public static final int KEY_APPS = 0xDD;
     /**
      * power key.
@@ -539,4 +544,8 @@ public interface KeyInput extends Input {
      */
     public static final int KEY_SLEEP = 0xDF;
 
+    /**
+     * the last key.
+     */
+    public static final int KEY_LAST = 0xE0;
 }

+ 24 - 22
jme3-core/src/main/java/com/jme3/input/KeyNames.java

@@ -34,10 +34,11 @@ package com.jme3.input;
 import static com.jme3.input.KeyInput.*;
 
 public class KeyNames {
-    
+
     private static final String[] KEY_NAMES = new String[0xFF];
-    
+
     static {
+        KEY_NAMES[KEY_UNKNOWN] = "Unknown";
         KEY_NAMES[KEY_0] = "0";
         KEY_NAMES[KEY_1] = "1";
         KEY_NAMES[KEY_2] = "2";
@@ -48,7 +49,7 @@ public class KeyNames {
         KEY_NAMES[KEY_7] = "7";
         KEY_NAMES[KEY_8] = "8";
         KEY_NAMES[KEY_9] = "9";
-        
+
         KEY_NAMES[KEY_Q] = "Q";
         KEY_NAMES[KEY_W] = "W";
         KEY_NAMES[KEY_E] = "E";
@@ -75,7 +76,7 @@ public class KeyNames {
         KEY_NAMES[KEY_B] = "B";
         KEY_NAMES[KEY_N] = "N";
         KEY_NAMES[KEY_M] = "M";
-        
+
         KEY_NAMES[KEY_F1] = "F1";
         KEY_NAMES[KEY_F2] = "F2";
         KEY_NAMES[KEY_F3] = "F3";
@@ -91,7 +92,7 @@ public class KeyNames {
         KEY_NAMES[KEY_F13] = "F13";
         KEY_NAMES[KEY_F14] = "F14";
         KEY_NAMES[KEY_F15] = "F15";
-        
+
         KEY_NAMES[KEY_NUMPAD0] = "Numpad 0";
         KEY_NAMES[KEY_NUMPAD1] = "Numpad 1";
         KEY_NAMES[KEY_NUMPAD2] = "Numpad 2";
@@ -102,25 +103,26 @@ public class KeyNames {
         KEY_NAMES[KEY_NUMPAD7] = "Numpad 7";
         KEY_NAMES[KEY_NUMPAD8] = "Numpad 8";
         KEY_NAMES[KEY_NUMPAD9] = "Numpad 9";
-        
+
         KEY_NAMES[KEY_NUMPADEQUALS] = "Numpad =";
         KEY_NAMES[KEY_NUMPADENTER] = "Numpad Enter";
-        KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad .";
+        KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad ,";
         KEY_NAMES[KEY_DIVIDE] = "Numpad /";
-        
-        
+        KEY_NAMES[KEY_SUBTRACT] = "Numpad -";
+        KEY_NAMES[KEY_DECIMAL] = "Numpad .";
+
         KEY_NAMES[KEY_LMENU] = "Left Alt";
         KEY_NAMES[KEY_RMENU] = "Right Alt";
-        
+
         KEY_NAMES[KEY_LCONTROL] = "Left Ctrl";
         KEY_NAMES[KEY_RCONTROL] = "Right Ctrl";
-        
+
         KEY_NAMES[KEY_LSHIFT] = "Left Shift";
         KEY_NAMES[KEY_RSHIFT] = "Right Shift";
-        
+
         KEY_NAMES[KEY_LMETA] = "Left Option";
         KEY_NAMES[KEY_RMETA] = "Right Option";
-        
+
         KEY_NAMES[KEY_MINUS] = "-";
         KEY_NAMES[KEY_EQUALS] = "=";
         KEY_NAMES[KEY_LBRACKET] = "[";
@@ -137,37 +139,37 @@ public class KeyNames {
         KEY_NAMES[KEY_COLON] = ":";
         KEY_NAMES[KEY_UNDERLINE] = "_";
         KEY_NAMES[KEY_AT] = "@";
-        
+
         KEY_NAMES[KEY_APPS] = "Apps";
         KEY_NAMES[KEY_POWER] = "Power";
         KEY_NAMES[KEY_SLEEP] = "Sleep";
-        
+
         KEY_NAMES[KEY_STOP] = "Stop";
         KEY_NAMES[KEY_ESCAPE] = "Esc";
         KEY_NAMES[KEY_RETURN] = "Enter";
         KEY_NAMES[KEY_SPACE] = "Space";
         KEY_NAMES[KEY_BACK] = "Backspace";
         KEY_NAMES[KEY_TAB] = "Tab";
-        
+
         KEY_NAMES[KEY_SYSRQ] = "SysRq";
         KEY_NAMES[KEY_PAUSE] = "Pause";
-        
+
         KEY_NAMES[KEY_HOME] = "Home";
         KEY_NAMES[KEY_PGUP] = "Page Up";
         KEY_NAMES[KEY_PGDN] = "Page Down";
         KEY_NAMES[KEY_END] = "End";
         KEY_NAMES[KEY_INSERT] = "Insert";
         KEY_NAMES[KEY_DELETE] = "Delete";
-        
+
         KEY_NAMES[KEY_UP] = "Up";
         KEY_NAMES[KEY_LEFT] = "Left";
         KEY_NAMES[KEY_RIGHT] = "Right";
         KEY_NAMES[KEY_DOWN] = "Down";
-        
+
         KEY_NAMES[KEY_NUMLOCK] = "Num Lock";
         KEY_NAMES[KEY_CAPITAL] = "Caps Lock";
         KEY_NAMES[KEY_SCROLL] = "Scroll Lock";
-        
+
         KEY_NAMES[KEY_KANA] = "Kana";
         KEY_NAMES[KEY_CONVERT] = "Convert";
         KEY_NAMES[KEY_NOCONVERT] = "No Convert";
@@ -177,8 +179,8 @@ public class KeyNames {
         KEY_NAMES[KEY_AX] = "Ax";
         KEY_NAMES[KEY_UNLABELED] = "Unlabeled";
     }
-    
-    public String getName(int keyId){
+
+    public static String getName(int keyId) {
         return KEY_NAMES[keyId];
     }
 }

+ 1 - 1
jme3-core/src/main/java/com/jme3/system/AppSettings.java

@@ -963,7 +963,7 @@ public final class AppSettings extends HashMap<String, Object> {
         return getString("SettingsDialogImage");
     }
 
-    public boolean getGammaCorrection() {
+    public boolean isGammaCorrection() {
         return getBoolean("GammaCorrection");
     }
     

+ 1 - 1
jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java

@@ -360,7 +360,7 @@ public final class SettingsDialog extends JFrame {
         vsyncBox.setSelected(source.isVSync());
         
         gammaBox = new JCheckBox(resourceBundle.getString("checkbox.gamma"));
-        gammaBox.setSelected(source.getGammaCorrection());
+        gammaBox.setSelected(source.isGammaCorrection());
         
         gbc = new GridBagConstraints();
         gbc.weightx = 0.5;

+ 19 - 18
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java

@@ -54,6 +54,7 @@ import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.NanoTimer;
 import com.jme3.system.NativeLibraryLoader;
+import com.jme3.system.NullRenderer;
 import com.jme3.system.SystemListener;
 import com.jme3.system.Timer;
 
@@ -69,9 +70,9 @@ import com.jogamp.opengl.GLContext;
 public abstract class JoglContext implements JmeContext {
 
     private static final Logger logger = Logger.getLogger(JoglContext.class.getName());
-    
+
     protected static final String THREAD_NAME = "jME3 Main";
-    
+
     protected AtomicBoolean created = new AtomicBoolean(false);
     protected AtomicBoolean renderable = new AtomicBoolean(false);
     protected final Object createdLock = new Object();
@@ -91,7 +92,7 @@ public abstract class JoglContext implements JmeContext {
             NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
         }
     }
-    
+
     @Override
 	public void setSystemListener(SystemListener listener){
         this.listener = listener;
@@ -101,7 +102,7 @@ public abstract class JoglContext implements JmeContext {
 	public void setSettings(AppSettings settings) {
         this.settings.copyFrom(settings);
     }
-    
+
     @Override
 	public boolean isRenderable(){
         return renderable.get();
@@ -160,50 +161,50 @@ public abstract class JoglContext implements JmeContext {
             }
         }
     }
-    
+
     protected void initContextFirstTime(){
         if (GLContext.getCurrent().getGLVersionNumber().getMajor() < 2) {
-            throw new RendererException("OpenGL 2.0 or higher is " + 
+            throw new RendererException("OpenGL 2.0 or higher is " +
                                         "required for jMonkeyEngine");
         }
-        
+
         if (settings.getRenderer().startsWith("JOGL")) {
         	com.jme3.renderer.opengl.GL gl = new JoglGL();
         	GLExt glext = new JoglGLExt();
         	GLFbo glfbo = new JoglGLFbo();
-            
+
             if (settings.getBoolean("GraphicsDebug")) {
                 gl    = new GLDebugDesktop(gl, glext, glfbo);
                 glext = (GLExt) gl;
                 glfbo = (GLFbo) gl;
             }
-            
+
             if (settings.getBoolean("GraphicsTiming")) {
                 GLTimingState timingState = new GLTimingState();
                 gl    = (com.jme3.renderer.opengl.GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
                 glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
                 glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
             }
-                  
+
             if (settings.getBoolean("GraphicsTrace")) {
                 gl    = (com.jme3.renderer.opengl.GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
                 glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
                 glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
             }
-            
+
             renderer = new GLRenderer(gl, glext, glfbo);
             renderer.initialize();
         } else {
             throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer());
         }
-        
+
         if (GLContext.getCurrentGL().isExtensionAvailable("GL_ARB_debug_output") && settings.getBoolean("GraphicsDebug")) {
         	GLContext.getCurrent().enableGLDebugMessage(true);
         	GLContext.getCurrent().addGLDebugListener(new JoglGLDebugOutputHandler());
         }
-        
-        renderer.setMainFrameBufferSrgb(settings.getGammaCorrection());
-        renderer.setLinearizeSrgbImages(settings.getGammaCorrection());
+
+        renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
+        renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
 
         // Init input
         if (keyInput != null) {
@@ -241,7 +242,7 @@ public abstract class JoglContext implements JmeContext {
             createdLock.notifyAll();
         }
     }
-    
+
     protected int determineMaxSamples(int requestedSamples) {
         GL gl = GLContext.getCurrentGL();
         if (gl.hasFullFBOSupport()) {
@@ -257,7 +258,7 @@ public abstract class JoglContext implements JmeContext {
             }
         }
     }
-    
+
     protected int getNumSamplesToUse() {
         int samples = 0;
         if (settings.getSamples() > 1){
@@ -268,7 +269,7 @@ public abstract class JoglContext implements JmeContext {
                         "Couldn''t satisfy antialiasing samples requirement: x{0}. "
                         + "Video hardware only supports: x{1}",
                         new Object[]{samples, supportedSamples});
-                
+
                 samples = supportedSamples;
             }
         }

+ 62 - 55
jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java

@@ -29,7 +29,6 @@
  * 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.lwjgl.JInputJoyInput;
@@ -53,6 +52,7 @@ import com.jme3.renderer.opengl.GLTiming;
 import com.jme3.renderer.opengl.GLTimingState;
 import com.jme3.renderer.opengl.GLTracer;
 import com.jme3.system.*;
+import java.io.File;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
@@ -69,7 +69,7 @@ public abstract class LwjglContext implements JmeContext {
     private static final Logger logger = Logger.getLogger(LwjglContext.class.getName());
 
     protected static final String THREAD_NAME = "jME3 Main";
-    
+
     protected AtomicBoolean created = new AtomicBoolean(false);
     protected AtomicBoolean renderable = new AtomicBoolean(false);
     protected final Object createdLock = new Object();
@@ -82,18 +82,18 @@ public abstract class LwjglContext implements JmeContext {
     protected Timer timer;
     protected SystemListener listener;
 
-    public void setSystemListener(SystemListener listener){
+    public void setSystemListener(SystemListener listener) {
         this.listener = listener;
     }
 
     protected void printContextInitInfo() {
-        logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" +
-                               " * Graphics Adapter: {2}\n" +
-                               " * Driver Version: {3}\n" +
-                               " * Scaling Factor: {4}",
-                               new Object[]{ Sys.getVersion(), Thread.currentThread().getName(), 
-                                             Display.getAdapter(), Display.getVersion(),
-                                             Display.getPixelScaleFactor() });
+        logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n"
+                + " * Graphics Adapter: {2}\n"
+                + " * Driver Version: {3}\n"
+                + " * Scaling Factor: {4}",
+                new Object[]{Sys.getVersion(), Thread.currentThread().getName(),
+                    Display.getAdapter(), Display.getVersion(),
+                    Display.getPixelScaleFactor()});
     }
 
     protected ContextAttribs createContextAttribs() {
@@ -113,7 +113,7 @@ public abstract class LwjglContext implements JmeContext {
             return null;
         }
     }
-    
+
     protected int determineMaxSamples(int requestedSamples) {
         try {
             // If we already have a valid context, determine samples using current
@@ -131,13 +131,13 @@ public abstract class LwjglContext implements JmeContext {
         } catch (LWJGLException ex) {
             listener.handleError("Failed to check if display is current", ex);
         }
-        
+
         if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) {
             // No pbuffer, assume everything is supported.
             return Integer.MAX_VALUE;
         } else {
             Pbuffer pb = null;
-            
+
             // OpenGL2 method: Create pbuffer and query samples
             // from GL_ARB_framebuffer_object or GL_EXT_framebuffer_multisample.
             try {
@@ -155,33 +155,40 @@ public abstract class LwjglContext implements JmeContext {
             } catch (LWJGLException ex) {
                 // Something else failed.
                 return Integer.MAX_VALUE;
-            } finally { 
+            } finally {
                 if (pb != null) {
                     pb.destroy();
                 }
             }
         }
     }
+
     protected void loadNatives() {
         if (JmeSystem.isLowPermissions()) {
             return;
         }
+
+        String extractPath = NativeLibraryLoader.getExtractionFolder().getAbsolutePath();
+
         if ("LWJGL".equals(settings.getAudioRenderer())) {
             NativeLibraryLoader.loadNativeLibrary("openal", true);
         }
         if (settings.useJoysticks()) {
-            NativeLibraryLoader.loadNativeLibrary("jinput", true);
-            NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true);
+            System.setProperty("net.java.games.input.librarypath", extractPath);
+            NativeLibraryLoader.loadNativeLibrary("jinput", true, false);
+            NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true, false);
         }
         if (NativeLibraryLoader.isUsingNativeBullet()) {
             NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
         }
-        NativeLibraryLoader.loadNativeLibrary("lwjgl", true);
+
+        System.setProperty("org.lwjgl.librarypath", extractPath);
+        NativeLibraryLoader.loadNativeLibrary("lwjgl", true, false);
     }
-    
+
     protected int getNumSamplesToUse() {
         int samples = 0;
-        if (settings.getSamples() > 1){
+        if (settings.getSamples() > 1) {
             samples = settings.getSamples();
             int supportedSamples = determineMaxSamples(samples);
             if (supportedSamples < samples) {
@@ -189,62 +196,62 @@ public abstract class LwjglContext implements JmeContext {
                         "Couldn''t satisfy antialiasing samples requirement: x{0}. "
                         + "Video hardware only supports: x{1}",
                         new Object[]{samples, supportedSamples});
-                
+
                 samples = supportedSamples;
             }
         }
         return samples;
     }
 
-    protected void initContextFirstTime(){
+    protected void initContextFirstTime() {
         if (!GLContext.getCapabilities().OpenGL20) {
-            throw new RendererException("OpenGL 2.0 or higher is " + 
-                                        "required for jMonkeyEngine");
+            throw new RendererException("OpenGL 2.0 or higher is "
+                    + "required for jMonkeyEngine");
         }
-        
+
         if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2)
-         || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) {
+                || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) {
             GL gl = new LwjglGL();
             GLExt glext = new LwjglGLExt();
             GLFbo glfbo;
-            
+
             if (GLContext.getCapabilities().OpenGL30) {
                 glfbo = new LwjglGLFboGL3();
             } else {
                 glfbo = new LwjglGLFboEXT();
             }
-            
+
             if (settings.getBoolean("GraphicsDebug")) {
-                gl    = new GLDebugDesktop(gl, glext, glfbo);
+                gl = new GLDebugDesktop(gl, glext, glfbo);
                 glext = (GLExt) gl;
                 glfbo = (GLFbo) gl;
             }
-            
+
             if (settings.getBoolean("GraphicsTiming")) {
                 GLTimingState timingState = new GLTimingState();
-                gl    = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
+                gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class);
                 glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class);
                 glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class);
             }
-                  
+
             if (settings.getBoolean("GraphicsTrace")) {
-                gl    = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
+                gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class);
                 glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class);
                 glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class);
             }
-            
+
             renderer = new GLRenderer(gl, glext, glfbo);
             renderer.initialize();
         } else {
             throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer());
         }
-        
+
         if (GLContext.getCapabilities().GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) {
             ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new LwjglGLDebugOutputHandler()));
         }
-        
-        renderer.setMainFrameBufferSrgb(settings.getGammaCorrection());
-        renderer.setLinearizeSrgbImages(settings.getGammaCorrection());
+
+        renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
+        renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
 
         // Init input
         if (keyInput != null) {
@@ -260,42 +267,42 @@ public abstract class LwjglContext implements JmeContext {
         }
     }
 
-    public void internalDestroy(){
+    public void internalDestroy() {
         renderer = null;
         timer = null;
         renderable.set(false);
-        synchronized (createdLock){
+        synchronized (createdLock) {
             created.set(false);
             createdLock.notifyAll();
         }
     }
-    
-    public void internalCreate(){
+
+    public void internalCreate() {
         timer = new LwjglTimer();
-        
-        synchronized (createdLock){
+
+        synchronized (createdLock) {
             created.set(true);
             createdLock.notifyAll();
         }
-        
-        if (renderable.get()){
+
+        if (renderable.get()) {
             initContextFirstTime();
-        }else{
+        } else {
             assert getType() == Type.Canvas;
         }
     }
 
-    public void create(){
+    public void create() {
         create(false);
     }
 
-    public void destroy(){
+    public void destroy() {
         destroy(false);
     }
 
-    protected void waitFor(boolean createdVal){
-        synchronized (createdLock){
-            while (created.get() != createdVal){
+    protected void waitFor(boolean createdVal) {
+        synchronized (createdLock) {
+            while (created.get() != createdVal) {
                 try {
                     createdLock.wait();
                 } catch (InterruptedException ex) {
@@ -304,11 +311,11 @@ public abstract class LwjglContext implements JmeContext {
         }
     }
 
-    public boolean isCreated(){
+    public boolean isCreated() {
         return created.get();
     }
-    
-    public boolean isRenderable(){
+
+    public boolean isRenderable() {
         return renderable.get();
     }
 
@@ -316,7 +323,7 @@ public abstract class LwjglContext implements JmeContext {
         this.settings.copyFrom(settings);
     }
 
-    public AppSettings getSettings(){
+    public AppSettings getSettings() {
         return settings;
     }
 

+ 7 - 7
jme3-lwjgl3/build.gradle

@@ -2,14 +2,14 @@ if (!hasProperty('mainClass')) {
     ext.mainClass = ''
 }
 
-repositories {
-    maven {
-        url "https://oss.sonatype.org/content/repositories/snapshots"
-    }
-}
+def lwjglVersion = '3.0.0b'
 
 dependencies {
     compile project(':jme3-core')
     compile project(':jme3-desktop')
-    compile files('lib/lwjgl-3.0.0b-35.jar', 'lib/lwjgl-3.0.0b-35-natives.jar')
-}
+
+    compile "org.lwjgl:lwjgl:${lwjglVersion}"
+    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-windows"
+    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-linux"
+    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-osx"
+}

BIN
jme3-lwjgl3/lib/lwjgl-3.0.0b-35-natives.jar


BIN
jme3-lwjgl3/lib/lwjgl-3.0.0b-35.jar


+ 22 - 18
jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java

@@ -32,32 +32,38 @@
 package com.jme3.audio.lwjgl;
 
 import com.jme3.audio.openal.ALC;
+import java.nio.IntBuffer;
 import org.lwjgl.openal.ALC10;
 import org.lwjgl.openal.ALContext;
 import org.lwjgl.openal.ALDevice;
-
-import java.nio.IntBuffer;
-
-import static org.lwjgl.openal.ALC10.alcGetContextsDevice;
-import static org.lwjgl.openal.ALC10.alcGetCurrentContext;
+import org.lwjgl.openal.SOFTPauseDevice;
 
 public class LwjglALC implements ALC {
 
     private ALDevice device;
     private ALContext context;
 
+    private long contextId;
+    private long deviceId;
+
     public void createALC() {
         device = ALDevice.create();
         context = ALContext.create(device);
+        context.makeCurrent();
+
+        contextId = ALC10.alcGetCurrentContext();
+        deviceId = ALC10.alcGetContextsDevice(contextId);
     }
 
     public void destroyALC() {
         if (context != null) {
             context.destroy();
+            context = null;
         }
 
         if (device != null) {
             device.destroy();
+            device = null;
         }
     }
 
@@ -66,31 +72,29 @@ public class LwjglALC implements ALC {
     }
 
     public String alcGetString(final int parameter) {
-        final long context = alcGetCurrentContext();
-        final long device = alcGetContextsDevice(context);
-        return ALC10.alcGetString(device, parameter);
+        return ALC10.alcGetString(deviceId, parameter);
     }
 
     public boolean alcIsExtensionPresent(final String extension) {
-        final long context = alcGetCurrentContext();
-        final long device = alcGetContextsDevice(context);
-        return ALC10.alcIsExtensionPresent(device, extension);
+        return ALC10.alcIsExtensionPresent(deviceId, extension);
     }
 
     public void alcGetInteger(final int param, final IntBuffer buffer, final int size) {
-        if (buffer.position() != 0) throw new AssertionError();
-        if (buffer.limit() != size) throw new AssertionError();
-
-        final long context = alcGetCurrentContext();
-        final long device = alcGetContextsDevice(context);
-        final int value = ALC10.alcGetInteger(device, param);
-        //buffer.put(value);
+        if (buffer.position() != 0) {
+            throw new AssertionError();
+        }
+        if (buffer.limit() != size) {
+            throw new AssertionError();
+        }
+        ALC10.alcGetIntegerv(deviceId, param, buffer);
     }
 
     public void alcDevicePauseSOFT() {
+        SOFTPauseDevice.alcDevicePauseSOFT(deviceId);
     }
 
     public void alcDeviceResumeSOFT() {
+        SOFTPauseDevice.alcDeviceResumeSOFT(deviceId);
     }
 
 }

+ 2 - 1
jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java

@@ -66,7 +66,8 @@ public class GlfwKeyInput implements KeyInput {
         glfwSetKeyCallback(context.getWindowHandle(), keyCallback = new GLFWKeyCallback() {
             @Override
             public void invoke(long window, int key, int scancode, int action, int mods) {
-                final KeyInputEvent evt = new KeyInputEvent(scancode, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action);
+                int jmeKey = GlfwKeyMap.toJmeKeyCode(key);
+                final KeyInputEvent evt = new KeyInputEvent(jmeKey, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action);
                 evt.setTime(getInputTimeNanos());
                 keyInputEvents.add(evt);
             }

+ 171 - 0
jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java

@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2009-2015 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.input.lwjgl;
+
+import static org.lwjgl.glfw.GLFW.*;
+import static com.jme3.input.KeyInput.*;
+
+public class GlfwKeyMap {
+
+    private static final int[] glfwToJmeKeyMap = new int[GLFW_KEY_LAST + 1];
+
+    private static void reg(int jmeKey, int glfwKey) {
+        glfwToJmeKeyMap[glfwKey] = jmeKey;
+    }
+
+    static {
+        reg(KEY_ESCAPE, GLFW_KEY_ESCAPE);
+        reg(KEY_1, GLFW_KEY_1);
+        reg(KEY_2, GLFW_KEY_2);
+        reg(KEY_3, GLFW_KEY_3);
+        reg(KEY_4, GLFW_KEY_4);
+        reg(KEY_5, GLFW_KEY_5);
+        reg(KEY_6, GLFW_KEY_6);
+        reg(KEY_7, GLFW_KEY_7);
+        reg(KEY_8, GLFW_KEY_8);
+        reg(KEY_9, GLFW_KEY_9);
+        reg(KEY_0, GLFW_KEY_0);
+        reg(KEY_MINUS, GLFW_KEY_MINUS);
+        reg(KEY_EQUALS, GLFW_KEY_EQUAL);
+        reg(KEY_BACK, GLFW_KEY_BACKSPACE);
+        reg(KEY_TAB, GLFW_KEY_TAB);
+        reg(KEY_Q, GLFW_KEY_Q);
+        reg(KEY_W, GLFW_KEY_W);
+        reg(KEY_E, GLFW_KEY_E);
+        reg(KEY_R, GLFW_KEY_R);
+        reg(KEY_T, GLFW_KEY_T);
+        reg(KEY_Y, GLFW_KEY_Y);
+        reg(KEY_U, GLFW_KEY_U);
+        reg(KEY_I, GLFW_KEY_I);
+        reg(KEY_O, GLFW_KEY_O);
+        reg(KEY_P, GLFW_KEY_P);
+        reg(KEY_LBRACKET, GLFW_KEY_LEFT_BRACKET);
+        reg(KEY_RBRACKET, GLFW_KEY_RIGHT_BRACKET);
+        reg(KEY_RETURN, GLFW_KEY_ENTER);
+        reg(KEY_LCONTROL, GLFW_KEY_LEFT_CONTROL);
+        reg(KEY_A, GLFW_KEY_A);
+        reg(KEY_S, GLFW_KEY_S);
+        reg(KEY_D, GLFW_KEY_D);
+        reg(KEY_F, GLFW_KEY_F);
+        reg(KEY_G, GLFW_KEY_G);
+        reg(KEY_H, GLFW_KEY_H);
+        reg(KEY_J, GLFW_KEY_J);
+        reg(KEY_K, GLFW_KEY_K);
+        reg(KEY_L, GLFW_KEY_L);
+        reg(KEY_SEMICOLON, GLFW_KEY_SEMICOLON);
+        reg(KEY_APOSTROPHE, GLFW_KEY_APOSTROPHE);
+        reg(KEY_GRAVE, GLFW_KEY_GRAVE_ACCENT);
+        reg(KEY_LSHIFT, GLFW_KEY_LEFT_SHIFT);
+        reg(KEY_BACKSLASH, GLFW_KEY_BACKSLASH);
+        reg(KEY_Z, GLFW_KEY_Z);
+        reg(KEY_X, GLFW_KEY_X);
+        reg(KEY_C, GLFW_KEY_C);
+        reg(KEY_V, GLFW_KEY_V);
+        reg(KEY_B, GLFW_KEY_B);
+        reg(KEY_N, GLFW_KEY_N);
+        reg(KEY_M, GLFW_KEY_M);
+        reg(KEY_COMMA, GLFW_KEY_COMMA);
+        reg(KEY_PERIOD, GLFW_KEY_PERIOD);
+        reg(KEY_SLASH, GLFW_KEY_SLASH);
+        reg(KEY_RSHIFT, GLFW_KEY_RIGHT_SHIFT);
+        reg(KEY_MULTIPLY, GLFW_KEY_KP_MULTIPLY);
+        reg(KEY_LMENU, GLFW_KEY_LEFT_ALT);
+        reg(KEY_SPACE, GLFW_KEY_SPACE);
+        reg(KEY_CAPITAL, GLFW_KEY_CAPS_LOCK);
+        reg(KEY_F1, GLFW_KEY_F1);
+        reg(KEY_F2, GLFW_KEY_F2);
+        reg(KEY_F3, GLFW_KEY_F3);
+        reg(KEY_F4, GLFW_KEY_F4);
+        reg(KEY_F5, GLFW_KEY_F5);
+        reg(KEY_F6, GLFW_KEY_F6);
+        reg(KEY_F7, GLFW_KEY_F7);
+        reg(KEY_F8, GLFW_KEY_F8);
+        reg(KEY_F9, GLFW_KEY_F9);
+        reg(KEY_F10, GLFW_KEY_F10);
+        reg(KEY_NUMLOCK, GLFW_KEY_NUM_LOCK);
+        reg(KEY_SCROLL, GLFW_KEY_SCROLL_LOCK);
+        reg(KEY_NUMPAD7, GLFW_KEY_KP_7);
+        reg(KEY_NUMPAD8, GLFW_KEY_KP_8);
+        reg(KEY_NUMPAD9, GLFW_KEY_KP_9);
+        reg(KEY_SUBTRACT, GLFW_KEY_KP_SUBTRACT);
+        reg(KEY_NUMPAD4, GLFW_KEY_KP_4);
+        reg(KEY_NUMPAD5, GLFW_KEY_KP_5);
+        reg(KEY_NUMPAD6, GLFW_KEY_KP_6);
+        reg(KEY_ADD, GLFW_KEY_KP_ADD);
+        reg(KEY_NUMPAD1, GLFW_KEY_KP_1);
+        reg(KEY_NUMPAD2, GLFW_KEY_KP_2);
+        reg(KEY_NUMPAD3, GLFW_KEY_KP_3);
+        reg(KEY_NUMPAD0, GLFW_KEY_KP_0);
+        reg(KEY_DECIMAL, GLFW_KEY_KP_DECIMAL);
+        reg(KEY_F11, GLFW_KEY_F11);
+        reg(KEY_F12, GLFW_KEY_F12);
+        reg(KEY_F13, GLFW_KEY_F13);
+        reg(KEY_F14, GLFW_KEY_F14);
+        reg(KEY_F15, GLFW_KEY_F15);
+        //reg(KEY_KANA, GLFW_KEY_);
+        //reg(KEY_CONVERT, GLFW_KEY_);
+        //reg(KEY_NOCONVERT, GLFW_KEY_);
+        //reg(KEY_YEN, GLFW_KEY_);
+        //reg(KEY_NUMPADEQUALS, GLFW_KEY_);
+        //reg(KEY_CIRCUMFLEX, GLFW_KEY_);
+        //reg(KEY_AT, GLFW_KEY_);
+        //reg(KEY_COLON, GLFW_KEY_);
+        //reg(KEY_UNDERLINE, GLFW_KEY_);
+        //reg(KEY_KANJI, GLFW_KEY_);
+        //reg(KEY_STOP, GLFW_KEY_);
+        //reg(KEY_AX, GLFW_KEY_);
+        //reg(KEY_UNLABELED, GLFW_KEY_);
+        reg(KEY_NUMPADENTER, GLFW_KEY_KP_ENTER);
+        reg(KEY_RCONTROL, GLFW_KEY_RIGHT_CONTROL);
+        //reg(KEY_NUMPADCOMMA, GLFW_KEY_);
+        reg(KEY_DIVIDE, GLFW_KEY_KP_DIVIDE);
+        reg(KEY_SYSRQ, GLFW_KEY_PRINT_SCREEN);
+        reg(KEY_RMENU, GLFW_KEY_RIGHT_ALT);
+        reg(KEY_PAUSE, GLFW_KEY_PAUSE);
+        reg(KEY_HOME, GLFW_KEY_HOME);
+        reg(KEY_UP, GLFW_KEY_UP);
+        reg(KEY_PRIOR, GLFW_KEY_PAGE_UP);
+        reg(KEY_LEFT, GLFW_KEY_LEFT);
+        reg(KEY_RIGHT, GLFW_KEY_RIGHT);
+        reg(KEY_END, GLFW_KEY_END);
+        reg(KEY_DOWN, GLFW_KEY_DOWN);
+        reg(KEY_NEXT, GLFW_KEY_PAGE_DOWN);
+        reg(KEY_INSERT, GLFW_KEY_INSERT);
+        reg(KEY_DELETE, GLFW_KEY_DELETE);
+        reg(KEY_LMETA, GLFW_KEY_LEFT_SUPER);
+        reg(KEY_RMETA, GLFW_KEY_RIGHT_SUPER);
+    }
+
+    public static int toJmeKeyCode(int glfwKey) {
+        return glfwToJmeKeyMap[glfwKey];
+    }
+}

+ 91 - 47
jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java

@@ -38,16 +38,22 @@ import com.jme3.input.RawInputListener;
 import com.jme3.input.event.MouseButtonEvent;
 import com.jme3.input.event.MouseMotionEvent;
 import com.jme3.system.lwjgl.LwjglWindow;
+import com.jme3.util.BufferUtils;
 import org.lwjgl.glfw.GLFWCursorPosCallback;
 import org.lwjgl.glfw.GLFWMouseButtonCallback;
 import org.lwjgl.glfw.GLFWScrollCallback;
 
 import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 import java.util.Queue;
 import java.util.logging.Logger;
 
 import static org.lwjgl.glfw.GLFW.*;
+import org.lwjgl.glfw.GLFWImage;
+import org.lwjgl.system.MemoryUtil;
 
 /**
  * Captures mouse input using GLFW callbacks. It then temporarily stores these in event queues which are processed in the
@@ -74,57 +80,70 @@ public class GlfwMouseInput implements MouseInput {
     private Queue<MouseMotionEvent> mouseMotionEvents = new LinkedList<MouseMotionEvent>();
     private Queue<MouseButtonEvent> mouseButtonEvents = new LinkedList<MouseButtonEvent>();
 
-    public GlfwMouseInput(final LwjglWindow context) {
+    private Map<JmeCursor, Long> jmeToGlfwCursorMap = new HashMap<JmeCursor, Long>();
+
+    public GlfwMouseInput(LwjglWindow context) {
         this.context = context;
     }
 
+    private void onCursorPos(long window, double xpos, double ypos) {
+        int xDelta;
+        int yDelta;
+        int x = (int) Math.round(xpos);
+        int y = context.getSettings().getHeight() - (int) Math.round(ypos);
+
+        if (mouseX == 0) {
+            mouseX = x;
+        }
+
+        if (mouseY == 0) {
+            mouseY = y;
+        }
+
+        xDelta = x - mouseX;
+        yDelta = y - mouseY;
+        mouseX = x;
+        mouseY = y;
+
+        if (xDelta != 0 || yDelta != 0) {
+            final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y, xDelta, yDelta, mouseWheel, 0);
+            mouseMotionEvent.setTime(getInputTimeNanos());
+            mouseMotionEvents.add(mouseMotionEvent);
+        }
+    }
+
+    private void onWheelScroll(long window, double xOffset, double yOffset) {
+        mouseWheel += yOffset;
+        final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset));
+        mouseMotionEvent.setTime(getInputTimeNanos());
+        mouseMotionEvents.add(mouseMotionEvent);
+    }
+
+    private void onMouseButton(final long window, final int button, final int action, final int mods) {
+        final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY);
+        mouseButtonEvent.setTime(getInputTimeNanos());
+        mouseButtonEvents.add(mouseButtonEvent);
+    }
+
     public void initialize() {
         glfwSetCursorPosCallback(context.getWindowHandle(), cursorPosCallback = new GLFWCursorPosCallback() {
             @Override
             public void invoke(long window, double xpos, double ypos) {
-                int xDelta;
-                int yDelta;
-                int x = (int) Math.round(xpos);
-                int y = context.getSettings().getHeight() - (int) Math.round(ypos);
-
-                if (mouseX == 0) {
-                    mouseX = x;
-                }
-
-                if (mouseY == 0) {
-                    mouseY = y;
-                }
-
-                xDelta = x - mouseX;
-                yDelta = y - mouseY;
-                mouseX = x;
-                mouseY = y;
-
-                if (xDelta != 0 || yDelta != 0) {
-                    final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y, xDelta, yDelta, mouseWheel, 0);
-                    mouseMotionEvent.setTime(getInputTimeNanos());
-                    mouseMotionEvents.add(mouseMotionEvent);
-                }
+                onCursorPos(window, xpos, ypos);
             }
         });
 
         glfwSetScrollCallback(context.getWindowHandle(), scrollCallback = new GLFWScrollCallback() {
             @Override
             public void invoke(final long window, final double xOffset, final double yOffset) {
-                mouseWheel += yOffset;
-
-                final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset));
-                mouseMotionEvent.setTime(getInputTimeNanos());
-                mouseMotionEvents.add(mouseMotionEvent);
+                onWheelScroll(window, xOffset, yOffset);
             }
         });
 
         glfwSetMouseButtonCallback(context.getWindowHandle(), mouseButtonCallback = new GLFWMouseButtonCallback() {
             @Override
             public void invoke(final long window, final int button, final int action, final int mods) {
-                final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY);
-                mouseButtonEvent.setTime(getInputTimeNanos());
-                mouseButtonEvents.add(mouseButtonEvent);
+                onMouseButton(window, button, action, mods);
             }
         });
 
@@ -160,6 +179,10 @@ public class GlfwMouseInput implements MouseInput {
         scrollCallback.release();
         mouseButtonCallback.release();
 
+        for (long glfwCursor : jmeToGlfwCursorMap.values()) {
+            glfwDestroyCursor(glfwCursor);
+        }
+
         logger.fine("Mouse destroyed.");
     }
 
@@ -185,31 +208,52 @@ public class GlfwMouseInput implements MouseInput {
         return (long) (glfwGetTime() * 1000000000);
     }
 
-    public void setNativeCursor(final JmeCursor jmeCursor) {
+    private long createGlfwCursor(JmeCursor jmeCursor) {
+        GLFWImage glfwImage = new GLFWImage(BufferUtils.createByteBuffer(GLFWImage.SIZEOF));
+
+        // TODO: currently animated cursors are not supported
+        IntBuffer imageData = jmeCursor.getImagesData();
+        ByteBuffer buf = BufferUtils.createByteBuffer(imageData.capacity());
+        buf.asIntBuffer().put(imageData);
+
+        glfwImage.set(jmeCursor.getWidth(), jmeCursor.getHeight(), buf);
+
+        return glfwCreateCursor(glfwImage, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot());
+    }
+
+    public void setNativeCursor(JmeCursor jmeCursor) {
         if (jmeCursor != null) {
-            final ByteBuffer byteBuffer = org.lwjgl.BufferUtils.createByteBuffer(jmeCursor.getImagesData().capacity());
-            byteBuffer.asIntBuffer().put(jmeCursor.getImagesData().array());
-            final long cursor = glfwCreateCursor(byteBuffer, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot());
-            glfwSetCursor(context.getWindowHandle(), cursor);
+            Long glfwCursor = jmeToGlfwCursorMap.get(jmeCursor);
+
+            if (glfwCursor == null) {
+                glfwCursor = createGlfwCursor(jmeCursor);
+                jmeToGlfwCursorMap.put(jmeCursor, glfwCursor);
+            }
+
+            glfwSetCursor(context.getWindowHandle(), glfwCursor);
+        } else {
+            glfwSetCursor(context.getWindowHandle(), MemoryUtil.NULL);
         }
     }
 
     /**
-     * Simply converts the GLFW button code to a JME button code. If there is no match it just returns the GLFW button
-     * code. Bare in mind GLFW supports 8 different mouse buttons.
+     * Simply converts the GLFW button code to a JME button code. If there is no
+     * match it just returns the GLFW button code. Bear in mind GLFW supports 8
+     * different mouse buttons.
      *
      * @param glfwButton the raw GLFW button index.
      * @return the mapped {@link MouseInput} button id.
      */
     private int convertButton(final int glfwButton) {
-        if (glfwButton == GLFW_MOUSE_BUTTON_LEFT) {
-            return MouseInput.BUTTON_LEFT;
-        } else if(glfwButton == GLFW_MOUSE_BUTTON_MIDDLE) {
-            return MouseInput.BUTTON_MIDDLE;
-        } else if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT) {
-            return MouseInput.BUTTON_RIGHT;
+        switch (glfwButton) {
+            case GLFW_MOUSE_BUTTON_LEFT:
+                return MouseInput.BUTTON_LEFT;
+            case GLFW_MOUSE_BUTTON_MIDDLE:
+                return MouseInput.BUTTON_MIDDLE;
+            case GLFW_MOUSE_BUTTON_RIGHT:
+                return MouseInput.BUTTON_RIGHT;
+            default:
+                return glfwButton;
         }
-
-        return glfwButton;
     }
 }

+ 16 - 12
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java

@@ -43,9 +43,7 @@ import com.jme3.renderer.lwjgl.LwjglGLFboEXT;
 import com.jme3.renderer.lwjgl.LwjglGLFboGL3;
 import com.jme3.renderer.opengl.*;
 import com.jme3.system.*;
-import org.lwjgl.Sys;
 import org.lwjgl.glfw.GLFW;
-import org.lwjgl.opengl.ARBDebugOutput;
 import org.lwjgl.opengl.ARBFramebufferObject;
 import org.lwjgl.opengl.EXTFramebufferMultisample;
 import org.lwjgl.opengl.GLCapabilities;
@@ -53,9 +51,10 @@ import org.lwjgl.opengl.GLCapabilities;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
+import org.lwjgl.opengl.ARBDebugOutput;
 
 import static org.lwjgl.opengl.GL.createCapabilities;
-import static org.lwjgl.opengl.GL11.GL_TRUE;
 import static org.lwjgl.opengl.GL11.glGetInteger;
 
 /**
@@ -84,16 +83,16 @@ public abstract class LwjglContext implements JmeContext {
     }
 
     protected void printContextInitInfo() {
-        logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" +
-                        " * Graphics Adapter: GLFW {2}",
-                new Object[]{Sys.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()});
+        logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n"
+                + " * Graphics Adapter: GLFW {2}",
+                new Object[]{org.lwjgl.Version.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()});
     }
 
     protected int determineMaxSamples() {
         // If we already have a valid context, determine samples using current context.
-        if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GL_TRUE) {
+        if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GLFW_TRUE) {
             return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES);
-        } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) {
+        } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GLFW_TRUE) {
             return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT);
         }
 
@@ -180,11 +179,11 @@ public abstract class LwjglContext implements JmeContext {
         }
 
         if (capabilities.GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) {
-            ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0); // User param is zero. Not sure what we could use that for.
+            ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0);
         }
 
-        renderer.setMainFrameBufferSrgb(settings.getGammaCorrection());
-        renderer.setLinearizeSrgbImages(settings.getGammaCorrection());
+        renderer.setMainFrameBufferSrgb(settings.isGammaCorrection());
+        renderer.setLinearizeSrgbImages(settings.isGammaCorrection());
 
         // Init input
         if (keyInput != null) {
@@ -198,7 +197,6 @@ public abstract class LwjglContext implements JmeContext {
         if (joyInput != null) {
             joyInput.initialize();
         }
-
         renderable.set(true);
     }
 
@@ -240,26 +238,32 @@ public abstract class LwjglContext implements JmeContext {
         }
     }
 
+    @Override
     public boolean isCreated() {
         return created.get();
     }
 
+    @Override
     public boolean isRenderable() {
         return renderable.get();
     }
 
+    @Override
     public void setSettings(AppSettings settings) {
         this.settings.copyFrom(settings);
     }
 
+    @Override
     public AppSettings getSettings() {
         return settings;
     }
 
+    @Override
     public Renderer getRenderer() {
         return renderer;
     }
 
+    @Override
     public Timer getTimer() {
         return timer;
     }

+ 84 - 45
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@@ -43,7 +43,6 @@ import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.JmeSystem;
 import com.jme3.system.NanoTimer;
-import org.lwjgl.Sys;
 import org.lwjgl.glfw.*;
 
 import java.awt.*;
@@ -52,6 +51,7 @@ import java.nio.ByteBuffer;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import org.lwjgl.Version;
 
 import static org.lwjgl.glfw.GLFW.*;
 import static org.lwjgl.opengl.GL11.GL_FALSE;
@@ -72,7 +72,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
     protected boolean wasActive = false;
     protected boolean autoFlush = true;
     protected boolean allowSwapBuffers = false;
-    private long window = -1;
+    private long window = NULL;
     private final JmeContext.Type type;
     private int frameRateLimit = -1;
     private double frameSleepTime;
@@ -102,7 +102,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
      * @param title the title to set
      */
     public void setTitle(final String title) {
-        if (created.get() && window != -1) {
+        if (created.get() && window != NULL) {
             glfwSetWindowTitle(window, title);
         }
     }
@@ -127,45 +127,45 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() {
             @Override
             public void invoke(int error, long description) {
-                final String message = Callbacks.errorCallbackDescriptionString(description);
+                final String message = GLFWErrorCallback.getDescription(description);
                 listener.handleError(message, new Exception(message));
             }
         });
 
-        if (glfwInit() != GL_TRUE) {
+        if (glfwInit() != GLFW_TRUE) {
             throw new IllegalStateException("Unable to initialize GLFW");
         }
 
         glfwDefaultWindowHints();
-        glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
 
-        // TODO: Add support for monitor selection
-        long monitor = NULL;
-
-        if (settings.isFullscreen()) {
-            monitor = glfwGetPrimaryMonitor();
+        if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) {
+            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+            glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
+            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
+        } else {
+            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
+            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
         }
 
-        final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
-
-        if (settings.getWidth() <= 0 || settings.getHeight() <= 0) {
-            settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode));
+        if (settings.getBoolean("RendererDebug")) {
+            glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
         }
 
-        window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL);
-
-        if (window == NULL) {
-            throw new RuntimeException("Failed to create the GLFW window");
+        if (settings.isGammaCorrection()) {
+            glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE);
         }
 
-        glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE);
+        glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
+        glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GLFW_TRUE : GLFW_FALSE);
+
+        glfwWindowHint(GLFW_DOUBLE_BUFFER, GLFW_TRUE);
         glfwWindowHint(GLFW_DEPTH_BITS, settings.getDepthBits());
         glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits());
         glfwWindowHint(GLFW_SAMPLES, settings.getSamples());
-        glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE);
+        glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GLFW_TRUE : GLFW_FALSE);
         glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency());
 
-        // Not sure how else to support bits per pixel
         if (settings.getBitsPerPixel() == 24) {
             glfwWindowHint(GLFW_RED_BITS, 8);
             glfwWindowHint(GLFW_GREEN_BITS, 8);
@@ -178,6 +178,34 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
         glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits());
 
+        // TODO: Add support for monitor selection
+        long monitor = NULL;
+
+        if (settings.isFullscreen()) {
+            monitor = glfwGetPrimaryMonitor();
+        }
+
+        final GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
+
+        if (settings.getWidth() <= 0 || settings.getHeight() <= 0) {
+            settings.setResolution(videoMode.width(), videoMode.height());
+        }
+
+        window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL);
+
+        if (window == NULL) {
+            throw new RuntimeException("Failed to create the GLFW window");
+        }
+
+        // Add a resize callback which delegates to the listener
+        glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() {
+            @Override
+            public void invoke(final long window, final int width, final int height) {
+                settings.setResolution(width, height);
+                listener.reshape(width, height);
+            }
+        });
+
         glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() {
             @Override
             public void invoke(final long window, final int focused) {
@@ -197,8 +225,10 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         });
 
         // Center the window
-        if (!settings.isFullscreen() && Type.Display.equals(type)) {
-            glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2);
+        if (!settings.isFullscreen()) {
+            glfwSetWindowPos(window,
+                    (videoMode.width() - settings.getWidth()) / 2,
+                    (videoMode.height() - settings.getHeight()) / 2);
         }
 
         // Make the OpenGL context current
@@ -216,14 +246,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
             glfwShowWindow(window);
         }
 
-        // Add a resize callback which delegates to the listener
-        glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() {
-            @Override
-            public void invoke(final long window, final int width, final int height) {
-                settings.setResolution(width, height);
-                listener.reshape(width, height);
-            }
-        });
+        glfwShowWindow(window);
 
         allowSwapBuffers = settings.isSwapBuffers();
 
@@ -239,12 +262,24 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
                 renderer.cleanup();
             }
 
-            errorCallback.release();
-            windowSizeCallback.release();
-            windowFocusCallback.release();
+            if (errorCallback != null) {
+                errorCallback.release();
+                errorCallback = null;
+            }
+
+            if (windowSizeCallback != null) {
+                windowSizeCallback.release();
+                windowSizeCallback = null;
+            }
 
-            if (window != 0) {
+            if (windowFocusCallback != null) {
+                windowFocusCallback.release();
+                windowFocusCallback = null;
+            }
+
+            if (window != NULL) {
                 glfwDestroyWindow(window);
+                window = NULL;
             }
         } catch (Exception ex) {
             listener.handleError("Failed to destroy context", ex);
@@ -296,8 +331,9 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
             super.internalCreate();
         } catch (Exception ex) {
             try {
-                if (window != -1) {
+                if (window != NULL) {
                     glfwDestroyWindow(window);
+                    window = NULL;
                 }
             } catch (Exception ex2) {
                 LOGGER.log(Level.WARNING, null, ex2);
@@ -318,6 +354,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         // If a restart is required, lets recreate the context.
         if (needRestart.getAndSet(false)) {
             try {
+                destroyContext();
                 createContext(settings);
             } catch (Exception ex) {
                 LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex);
@@ -346,8 +383,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
             }
         }
 
-        glfwPollEvents();
-
         // Subclasses just call GLObjectManager clean up objects here
         // it is safe .. for now.
         if (renderer != null) {
@@ -377,6 +412,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
                 }
             }
         }
+
+        glfwPollEvents();
     }
 
     private void setFrameRateLimit(int frameRateLimit) {
@@ -389,11 +426,12 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
      */
 
     protected void deinitInThread() {
+        listener.destroy();
+
         destroyContext();
+        super.internalDestroy();
 
-        listener.destroy();
         LOGGER.fine("Display destroyed.");
-        super.internalDestroy();
     }
 
     public void run() {
@@ -403,7 +441,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         }
 
         loadNatives();
-        LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion());
+        LOGGER.log(Level.FINE, "Using LWJGL {0}", Version.getVersion());
 
         if (!initInThread()) {
             LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue.");
@@ -411,15 +449,16 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         }
 
         while (true) {
-            if (glfwWindowShouldClose(window) == GL_TRUE) {
-                listener.requestClose(false);
-            }
 
             runLoop();
 
             if (needClose.get()) {
                 break;
             }
+
+            if (glfwWindowShouldClose(window) == GL_TRUE) {
+                listener.requestClose(false);
+            }
         }
 
         deinitInThread();