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
experimental
Kirill Vainer 9 years ago
parent 6cb691592d
commit 2ca55c8b3a
  1. 15
      jme3-core/src/main/java/com/jme3/input/KeyInput.java
  2. 46
      jme3-core/src/main/java/com/jme3/input/KeyNames.java
  3. 2
      jme3-core/src/main/java/com/jme3/system/AppSettings.java
  4. 2
      jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java
  5. 37
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java
  6. 117
      jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
  7. 14
      jme3-lwjgl3/build.gradle
  8. BIN
      jme3-lwjgl3/lib/lwjgl-3.0.0b-35-natives.jar
  9. BIN
      jme3-lwjgl3/lib/lwjgl-3.0.0b-35.jar
  10. 40
      jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java
  11. 3
      jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java
  12. 171
      jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java
  13. 138
      jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java
  14. 28
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java
  15. 129
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.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;
}

@ -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];
}
}

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

@ -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;

@ -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;
}
}

@ -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;
}

@ -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"
}

@ -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);
}
}

@ -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);
}

@ -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];
}
}

@ -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;
}
}

@ -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;
}

@ -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();

Loading…
Cancel
Save