From 0869880c8e0167e4a765ab05b7b1f85a455e20bd Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Wed, 15 Jul 2015 10:24:04 +0100 Subject: [PATCH 01/13] Reverted changes to build script regarding bullet libs. --- jme3-bullet-native-android/build.gradle | 3 ++- jme3-jbullet/build.gradle | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jme3-bullet-native-android/build.gradle b/jme3-bullet-native-android/build.gradle index a640fcf93..3aa000c1e 100644 --- a/jme3-bullet-native-android/build.gradle +++ b/jme3-bullet-native-android/build.gradle @@ -21,7 +21,7 @@ if (!hasProperty('mainClass')) { } dependencies { - compile project(':jme3-bullet-native') +// compile project(':jme3-bullet-native') compile project(':jme3-bullet') } @@ -29,6 +29,7 @@ dependencies { sourceSets { main { java { + srcDir jmeCppPath srcDir jmeAndroidPath } } diff --git a/jme3-jbullet/build.gradle b/jme3-jbullet/build.gradle index 763a9e57b..0e3967ab2 100644 --- a/jme3-jbullet/build.gradle +++ b/jme3-jbullet/build.gradle @@ -6,6 +6,7 @@ sourceSets { main { java { srcDir 'src/main/java' + srcDir '../jme3-bullet/src/common/java' } } } @@ -15,5 +16,5 @@ dependencies { compile files('../lib/jbullet.jar', '../lib/stack-alloc.jar') compile project(':jme3-core') compile project(':jme3-terrain') - compile project(':jme3-bullet') +// compile project(':jme3-bullet') } From e33d2539edbac1adebe0bf34b318f2d1bde2ae4c Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Wed, 15 Jul 2015 13:08:36 +0100 Subject: [PATCH 02/13] Added additional convenience constructors to Light, AmbientLight, DirectionalLight, PointLight and SpotLight as mentioned in #297 --- .../java/com/jme3/light/AmbientLight.java | 16 ++++++++ .../java/com/jme3/light/DirectionalLight.java | 27 ++++++++++++ .../src/main/java/com/jme3/light/Light.java | 16 ++++++++ .../main/java/com/jme3/light/PointLight.java | 36 ++++++++++++++++ .../main/java/com/jme3/light/SpotLight.java | 41 +++++++++++++++++-- 5 files changed, 132 insertions(+), 4 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java index e147c6590..fb52301f9 100644 --- a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java +++ b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java @@ -32,6 +32,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Spatial; @@ -49,6 +50,21 @@ import com.jme3.util.TempVars; */ public class AmbientLight extends Light { + /** + * Default constructor for AmbientLight. + */ + public AmbientLight() { + } + + /** + * Constructor which allows setting of the color. + * + * @param color the color to apply to this light. + */ + public AmbientLight(final ColorRGBA color) { + super(color); + } + @Override public boolean intersectsBox(BoundingBox box, TempVars vars) { return true; diff --git a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java index c4258a67f..7f1541fda 100644 --- a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java +++ b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java @@ -36,6 +36,7 @@ import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Spatial; @@ -53,6 +54,32 @@ public class DirectionalLight extends Light { protected Vector3f direction = new Vector3f(0f, -1f, 0f); + /** + * Default constructor for DirectionalLight. Direction will be defaulted to -1 on the Y axis. + */ + public DirectionalLight() { + } + + /** + * Constructor which allows setting of the direction. + * + * @param direction the direction vector for the light. + */ + public DirectionalLight(final Vector3f direction) { + this.direction = direction; + } + + /** + * Constructor which allows setting of the color and direction. + * + * @param color the color to apply to this light. + * @param direction the direction vector for the light. + */ + public DirectionalLight(final ColorRGBA color, final Vector3f direction) { + super(color); + this.direction = direction; + } + @Override public void computeLastDistance(Spatial owner) { lastDistance = 0; // directional lights are always closest to their owner diff --git a/jme3-core/src/main/java/com/jme3/light/Light.java b/jme3-core/src/main/java/com/jme3/light/Light.java index 4217e1b62..7738c1721 100644 --- a/jme3-core/src/main/java/com/jme3/light/Light.java +++ b/jme3-core/src/main/java/com/jme3/light/Light.java @@ -115,6 +115,22 @@ public abstract class Light implements Savable, Cloneable { boolean frustumCheckNeeded = true; boolean intersectsFrustum = false; + /** + * Default constructor for Light. + */ + public Light() { + + } + + /** + * Constructor which allows setting of the color. + * + * @param color the color to apply to this light. + */ + public Light(final ColorRGBA color) { + this.color = color; + } + /** * Returns the color of the light. * diff --git a/jme3-core/src/main/java/com/jme3/light/PointLight.java b/jme3-core/src/main/java/com/jme3/light/PointLight.java index 55a129275..1e93e1f1e 100644 --- a/jme3-core/src/main/java/com/jme3/light/PointLight.java +++ b/jme3-core/src/main/java/com/jme3/light/PointLight.java @@ -38,6 +38,7 @@ import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; import com.jme3.math.Plane; import com.jme3.math.Vector3f; @@ -62,6 +63,41 @@ public class PointLight extends Light { protected float radius = 0; protected float invRadius = 0; + /** + * Default constructor for PointLight. + *

+ *

+ *

+ */ + public PointLight() { + } + + /** + * Constructor which allows setting of the color and position. + * + * @param color the color to apply to this light. + * @param position the position of the light. + */ + public PointLight(final ColorRGBA color, final Vector3f position) { + this(color, position, 0); + } + + /** + * Constructor which allows setting of the color, position and radius. + * + * @param color the color to apply to this light. + * @param position the position of the light. + * @param radius the radius of the light. + */ + public PointLight(final ColorRGBA color, final Vector3f position, final float radius) { + super(color); + this.position = position; + this.radius = radius; + } + @Override public void computeLastDistance(Spatial owner) { if (owner.getWorldBound() != null) { diff --git a/jme3-core/src/main/java/com/jme3/light/SpotLight.java b/jme3-core/src/main/java/com/jme3/light/SpotLight.java index e6443df7c..b4531fb1c 100644 --- a/jme3-core/src/main/java/com/jme3/light/SpotLight.java +++ b/jme3-core/src/main/java/com/jme3/light/SpotLight.java @@ -34,6 +34,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingVolume; import com.jme3.export.*; +import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; import com.jme3.math.Plane; import com.jme3.math.Vector3f; @@ -51,8 +52,8 @@ import java.io.IOException; * can be used to attenuate the influence of the light depending on the * distance between the light and the effected object. * Also the angle of the cone can be tweaked by changing the spot inner angle and the spot outer angle. - * the spot inner angle determin the cone of light where light has full influence. - * the spot outer angle determin the cone global cone of light of the spot light. + * the spot inner angle determine the cone of light where light has full influence. + * the spot outer angle determine the cone global cone of light of the spot light. * the light intensity slowly decrease between the inner cone and the outer cone. * @author Nehon */ @@ -64,16 +65,48 @@ public class SpotLight extends Light { protected float spotOuterAngle = FastMath.QUARTER_PI / 6; protected float spotRange = 100; protected float invSpotRange = 1f / 100; - protected float packedAngleCos=0; + protected float packedAngleCos = 0; protected float outerAngleCosSqr, outerAngleSinSqr; protected float outerAngleSinRcp, outerAngleSin, outerAngleCos; - + + /** + * Default constructor for SpotLight. + *

+ *

+ *

+ */ public SpotLight() { super(); computeAngleParameters(); } + /** + * Constructor which allows setting color, position, direction, inner angle, outer angle and range. + * + * @param color the color of the spotlight. + * @param position the position of the spotlight. + * @param direction the direction of the spotlight. + * @param spotInnerAngle the inner angle of the spotlight. + * @param spotOuterAngle the outer angle of the spotlight. + * @param spotRange the range of the spotlight. + */ + public SpotLight(final ColorRGBA color, final Vector3f position, final Vector3f direction, final float spotInnerAngle, + final float spotOuterAngle, final float spotRange) + { + super(color); + this.position = position; + this.direction = direction; + this.spotInnerAngle = spotInnerAngle; + this.spotOuterAngle = spotOuterAngle; + this.spotRange = spotRange; + computeAngleParameters(); + } + private void computeAngleParameters() { float innerCos = FastMath.cos(spotInnerAngle); outerAngleCos = FastMath.cos(spotOuterAngle); From 89f10eca58afd4c9645b60f8781e5578fa92b2c8 Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Wed, 26 Aug 2015 22:24:24 +0100 Subject: [PATCH 03/13] Added jme3-lwjgl3 module which ultimately adds support for LWJGL 3.x and GLFW. --- common.gradle | 3 + .../resources/joystick-mapping.properties | 6 + .../com/jme3/system/NativeLibraryLoader.java | 22 +- .../system/lwjgl/LwjglAbstractDisplay.java | 2 +- .../com/jme3/system/lwjgl/LwjglContext.java | 28 +- jme3-lwjgl3/build.gradle | 12 + .../java/com/jme3/audio/lwjgl/LwjglAL.java | 140 +++++ .../java/com/jme3/audio/lwjgl/LwjglALC.java | 58 +++ .../java/com/jme3/audio/lwjgl/LwjglEFX.java | 66 +++ .../jme3/input/lwjgl/GlfwJoystickInput.java | 213 ++++++++ .../com/jme3/input/lwjgl/LwjglKeyInput.java | 116 +++++ .../com/jme3/input/lwjgl/LwjglMouseInput.java | 189 +++++++ .../java/com/jme3/renderer/lwjgl/LwjglGL.java | 458 ++++++++++++++++ .../com/jme3/renderer/lwjgl/LwjglGLExt.java | 83 +++ .../jme3/renderer/lwjgl/LwjglGLFboEXT.java | 99 ++++ .../jme3/renderer/lwjgl/LwjglGLFboGL3.java | 97 ++++ .../com/jme3/system/lwjgl/LwjglCanvas.java | 369 +++++++++++++ .../com/jme3/system/lwjgl/LwjglContext.java | 289 +++++++++++ .../com/jme3/system/lwjgl/LwjglDisplay.java | 12 + .../lwjgl/LwjglGLDebugOutputHandler.java | 78 +++ .../system/lwjgl/LwjglOffscreenBuffer.java | 14 + .../system/lwjgl/LwjglSmoothingTimer.java | 203 ++++++++ .../com/jme3/system/lwjgl/LwjglTimer.java | 139 +++++ .../com/jme3/system/lwjgl/LwjglWindow.java | 489 ++++++++++++++++++ settings.gradle | 1 + 25 files changed, 3158 insertions(+), 28 deletions(-) create mode 100644 jme3-lwjgl3/build.gradle create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java diff --git a/common.gradle b/common.gradle index 6af4c664f..da38174d3 100644 --- a/common.gradle +++ b/common.gradle @@ -17,6 +17,9 @@ repositories { maven { url "http://nifty-gui.sourceforge.net/nifty-maven-repo" } + maven { + url "https://oss.sonatype.org/content/repositories/snapshots" + } } dependencies { diff --git a/jme3-core/src/main/resources/joystick-mapping.properties b/jme3-core/src/main/resources/joystick-mapping.properties index d7ce2f50a..966832036 100644 --- a/jme3-core/src/main/resources/joystick-mapping.properties +++ b/jme3-core/src/main/resources/joystick-mapping.properties @@ -63,3 +63,9 @@ Xbox\ 360\ Wireless\ Receiver.AXIS_RX=z Xbox\ 360\ Wireless\ Receiver.AXIS_RY=rz Xbox\ 360\ Wireless\ Receiver.z=AXIS_RX Xbox\ 360\ Wireless\ Receiver.rz=AXIS_RY + +# Microsoft PC-joystick driver +Microsoft\ PC-joystick\ driver.12=POV +Y +Microsoft\ PC-joystick\ driver.13=POV +X +Microsoft\ PC-joystick\ driver.14=POV -Y +Microsoft\ PC-joystick\ driver.15=POV -X diff --git a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java index 2917350f6..6e83e0e6b 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java +++ b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java @@ -48,9 +48,8 @@ import java.util.logging.Logger; /** * Utility class to register, extract, and load native libraries. *
- * Register your own libraries via the - * {@link #registerNativeLibrary(java.lang.String, com.jme3.system.Platform, java.lang.String, boolean) } - * method, for each platform. + * Register your own libraries via the {@link #registerNativeLibrary(String, Platform, String, String)} method, for + * each platform. * You can then extract this library (depending on platform), by * using {@link #loadNativeLibrary(java.lang.String, boolean) }. *
@@ -125,23 +124,6 @@ public final class NativeLibraryLoader { } static { - // LWJGL - registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); - registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); - registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); - registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); - registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); - registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); - - // OpenAL - // For OSX: Need to add lib prefix when extracting - registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); - registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); - registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); - registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); - registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); - registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); - // BulletJme registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll"); registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll"); diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index 7cdca0a57..415084788 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -40,7 +40,6 @@ import com.jme3.input.lwjgl.JInputJoyInput; import com.jme3.input.lwjgl.LwjglKeyInput; import com.jme3.input.lwjgl.LwjglMouseInput; import com.jme3.system.AppSettings; -import com.jme3.system.JmeContext.Type; import com.jme3.system.JmeSystem; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -207,6 +206,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna + "Must set with JmeContext.setSystemListner()."); } + registerNatives(); loadNatives(); logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); if (!initInThread()) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index c88f7b734..70885c39b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -52,12 +52,8 @@ import com.jme3.renderer.opengl.GLRenderer; import com.jme3.renderer.opengl.GLTiming; import com.jme3.renderer.opengl.GLTimingState; import com.jme3.renderer.opengl.GLTracer; -import com.jme3.system.AppSettings; -import com.jme3.system.JmeContext; -import com.jme3.system.JmeSystem; -import com.jme3.system.NativeLibraryLoader; -import com.jme3.system.SystemListener; -import com.jme3.system.Timer; +import com.jme3.system.*; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -166,7 +162,25 @@ public abstract class LwjglContext implements JmeContext { } } } - + + protected void registerNatives() { + // LWJGL + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + + // For OSX: Need to add lib prefix when extracting + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + } + protected void loadNatives() { if (JmeSystem.isLowPermissions()) { return; diff --git a/jme3-lwjgl3/build.gradle b/jme3-lwjgl3/build.gradle new file mode 100644 index 000000000..c9b43e0de --- /dev/null +++ b/jme3-lwjgl3/build.gradle @@ -0,0 +1,12 @@ +if (!hasProperty('mainClass')) { + ext.mainClass = '' +} + +dependencies { + compile project(':jme3-core') + compile project(':jme3-desktop') + compile 'org.lwjgl:lwjgl:3.0.0b-SNAPSHOT' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-windows' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-linux' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-osx' +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java new file mode 100644 index 000000000..313bdd5ee --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.AL; +import com.jme3.system.NativeLibraryLoader; +import com.jme3.system.Platform; +import org.lwjgl.openal.AL10; +import org.lwjgl.openal.AL11; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public final class LwjglAL implements AL { + + public LwjglAL() { + } + + public String alGetString(int parameter) { + return AL10.alGetString(parameter); + } + + public int alGenSources() { + return AL10.alGenSources(); + } + + public int alGetError() { + return AL10.alGetError(); + } + + public void alDeleteSources(int numSources, IntBuffer sources) { + if (sources.position() != 0) throw new AssertionError(); + if (sources.limit() != numSources) throw new AssertionError(); + AL10.alDeleteSources(sources); + } + + public void alGenBuffers(int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alGenBuffers(buffers); + } + + public void alDeleteBuffers(int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alDeleteBuffers(buffers); + } + + public void alSourceStop(int source) { + AL10.alSourceStop(source); + } + + public void alSourcei(int source, int param, int value) { + AL10.alSourcei(source, param, value); + } + + public void alBufferData(int buffer, int format, ByteBuffer data, int size, int frequency) { + if (data.position() != 0) throw new AssertionError(); + if (data.limit() != size) throw new AssertionError(); + AL10.alBufferData(buffer, format, data, frequency); + } + + public void alSourcePlay(int source) { + AL10.alSourcePlay(source); + } + + public void alSourcePause(int source) { + AL10.alSourcePause(source); + } + + public void alSourcef(int source, int param, float value) { + AL10.alSourcef(source, param, value); + } + + public void alSource3f(int source, int param, float value1, float value2, float value3) { + AL10.alSource3f(source, param, value1, value2, value3); + } + + public int alGetSourcei(int source, int param) { + return AL10.alGetSourcei(source, param); + } + + public void alSourceUnqueueBuffers(int source, int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alSourceUnqueueBuffers(source, buffers); + } + + public void alSourceQueueBuffers(int source, int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alSourceQueueBuffers(source, buffers); + } + + public void alListener(int param, FloatBuffer data) { + AL10.alListenerfv(param, data); + } + + public void alListenerf(int param, float value) { + AL10.alListenerf(param, value); + } + + public void alListener3f(int param, float value1, float value2, float value3) { + AL10.alListener3f(param, value1, value2, value3); + } + + public void alSource3i(int source, int param, int value1, int value2, int value3) { + AL11.alSource3i(source, param, value1, value2, value3); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java new file mode 100644 index 000000000..e0aed80ee --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java @@ -0,0 +1,58 @@ +package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.ALC; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALContext; + +import java.nio.IntBuffer; + +import static org.lwjgl.openal.ALC10.alcGetContextsDevice; +import static org.lwjgl.openal.ALC10.alcGetCurrentContext; + +public class LwjglALC implements ALC { + + private ALContext context; + + public void createALC() { + context = ALContext.create(); + } + + public void destroyALC() { + if (context != null) { + context.destroy(); + } + } + + public boolean isCreated() { + return context != null; + } + + public String alcGetString(final int parameter) { + final long context = alcGetCurrentContext(); + final long device = alcGetContextsDevice(context); + return ALC10.alcGetString(device, parameter); + } + + public boolean alcIsExtensionPresent(final String extension) { + final long context = alcGetCurrentContext(); + final long device = alcGetContextsDevice(context); + return ALC10.alcIsExtensionPresent(device, 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); + } + + public void alcDevicePauseSOFT() { + } + + public void alcDeviceResumeSOFT() { + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java new file mode 100644 index 000000000..2ddd09ed8 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java @@ -0,0 +1,66 @@ +package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.EFX; +import org.lwjgl.openal.EXTEfx; + +import java.nio.IntBuffer; + +public class LwjglEFX implements EFX { + + public void alGenAuxiliaryEffectSlots(int numSlots, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numSlots) throw new AssertionError(); + EXTEfx.alGenAuxiliaryEffectSlots(buffers); + } + + public void alGenEffects(int numEffects, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffects) throw new AssertionError(); + EXTEfx.alGenEffects(buffers); + } + + public void alEffecti(int effect, int param, int value) { + EXTEfx.alEffecti(effect, param, value); + } + + public void alAuxiliaryEffectSloti(int effectSlot, int param, int value) { + EXTEfx.alAuxiliaryEffectSloti(effectSlot, param, value); + } + + public void alDeleteEffects(int numEffects, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffects) throw new AssertionError(); + EXTEfx.alDeleteEffects(buffers); + } + + public void alDeleteAuxiliaryEffectSlots(int numEffectSlots, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffectSlots) throw new AssertionError(); + EXTEfx.alDeleteAuxiliaryEffectSlots(buffers); + } + + public void alGenFilters(int numFilters, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numFilters) throw new AssertionError(); + EXTEfx.alGenFilters(buffers); + } + + public void alFilteri(int filter, int param, int value) { + EXTEfx.alFilteri(filter, param, value); + } + + public void alFilterf(int filter, int param, float value) { + EXTEfx.alFilterf(filter, param, value); + } + + public void alDeleteFilters(int numFilters, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numFilters) throw new AssertionError(); + EXTEfx.alDeleteFilters(buffers); + } + + public void alEffectf(int effect, int param, float value) { + EXTEfx.alEffectf(effect, param, value); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java new file mode 100644 index 000000000..f17c08534 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input.lwjgl; + +import com.jme3.input.*; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +/** + * @author Daniel Johansson (dannyjo) + * @since 3.1 + */ +public class GlfwJoystickInput implements JoyInput { + + private static final Logger LOGGER = Logger.getLogger(InputManager.class.getName()); + + private boolean initialized = false; + private RawInputListener listener; + private Map joysticks = new HashMap(); + + public void setJoyRumble(int joyId, float amount) { + if (joyId >= joysticks.size()) { + throw new IllegalArgumentException(); + } + } + + @Override + public Joystick[] loadJoysticks(final InputManager inputManager) { + // TODO: Implement + + for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) { + if (glfwJoystickPresent(i) == GL11.GL_TRUE) { + final String name = glfwGetJoystickName(i); + final GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name); + joysticks.put(i, joystick); + + final FloatBuffer floatBuffer = glfwGetJoystickAxes(i); + + int axisIndex = 0; + while (floatBuffer.hasRemaining()) { + floatBuffer.get(); + + final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), convertAxisIndex(axisIndex)); + final JoystickAxis joystickAxis = new DefaultJoystickAxis(inputManager, joystick, axisIndex, convertAxisIndex(axisIndex), logicalId, true, false, 0.0f); + joystick.addAxis(axisIndex, joystickAxis); + axisIndex++; + } + + final ByteBuffer byteBuffer = glfwGetJoystickButtons(i); + + int buttonIndex = 0; + while (byteBuffer.hasRemaining()) { + byteBuffer.get(); + final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), String.valueOf(buttonIndex)); + joystick.addButton(new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId)); + buttonIndex++; + } + } + } + + return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]); + } + + private String convertAxisIndex(final int index) { + if (index == 0) { + return "pov_x"; + } else if (index == 1) { + return "pov_y"; + } else if (index == 2) { + return "z"; + } else if (index == 3) { + return "rz"; + } + + return String.valueOf(index); + } + + public void initialize() { + initialized = true; + } + + public void update() { + for (final Map.Entry entry : joysticks.entrySet()) { + // Axes + final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey()); + + for (final JoystickAxis axis : entry.getValue().getAxes()) { + final float value = axisValues.get(axis.getAxisId()); + listener.onJoyAxisEvent(new JoyAxisEvent(axis, value)); + } + + // Buttons + final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey()); + + for (final JoystickButton button : entry.getValue().getButtons()) { + final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS; + listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed)); + } + } + } + + public void destroy() { + initialized = false; + } + + public boolean isInitialized() { + return initialized; + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return 0; + } + + protected class GlfwJoystick extends AbstractJoystick { + + private JoystickAxis povAxisX; + private JoystickAxis povAxisY; + + public GlfwJoystick(InputManager inputManager, JoyInput joyInput, int joyId, String name) { + super(inputManager, joyInput, joyId, name); + } + + public void addAxis(final int index, final JoystickAxis axis) { + super.addAxis(axis); + + if (index == 0) { + povAxisX = axis; + } else if (index == 1) { + povAxisY = axis; + } + } + + @Override + protected void addButton(JoystickButton button) { + super.addButton(button); + } + + @Override + public JoystickAxis getXAxis() { + return povAxisX; + } + + @Override + public JoystickAxis getYAxis() { + return povAxisY; + } + + @Override + public JoystickAxis getPovXAxis() { + return povAxisX; + } + + @Override + public JoystickAxis getPovYAxis() { + return povAxisY; + } + + @Override + public int getXAxisIndex() { + return povAxisX.getAxisId(); + } + + @Override + public int getYAxisIndex() { + return povAxisY.getAxisId(); + } + } +} + + + diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java new file mode 100644 index 000000000..a39010c95 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.lwjgl; + +import com.jme3.input.KeyInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.system.lwjgl.LwjglTimer; +import com.jme3.system.lwjgl.LwjglWindow; +import org.lwjgl.glfw.GLFWKeyCallback; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +public class LwjglKeyInput implements KeyInput { + + private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName()); + + private LwjglWindow context; + private RawInputListener listener; + private boolean initialized; + private GLFWKeyCallback keyCallback; + private Queue keyInputEvents = new LinkedList(); + + public LwjglKeyInput(LwjglWindow context) { + this.context = context; + } + + public void initialize() { + if (!context.isRenderable()) { + return; + } + + 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); + evt.setTime(getInputTimeNanos()); + keyInputEvents.add(evt); + } + }); + + glfwSetInputMode(context.getWindowHandle(), GLFW_STICKY_KEYS, 1); + + initialized = true; + logger.fine("Keyboard created."); + } + + public int getKeyCount() { + return 0; // TODO: How do we figure this out? + } + + public void update() { + if (!context.isRenderable()) { + return; + } + + while (!keyInputEvents.isEmpty()) { + listener.onKeyEvent(keyInputEvents.poll()); + } + } + + public void destroy() { + if (!context.isRenderable()) { + return; + } + + keyCallback.release(); + logger.fine("Keyboard destroyed."); + } + + public boolean isInitialized() { + return initialized; + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java new file mode 100644 index 000000000..45262ffbc --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.lwjgl; + +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.MouseInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.system.lwjgl.LwjglTimer; +import com.jme3.system.lwjgl.LwjglWindow; +import org.lwjgl.glfw.GLFWCursorPosCallback; +import org.lwjgl.glfw.GLFWMouseButtonCallback; +import org.lwjgl.glfw.GLFWScrollCallback; + +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +public class LwjglMouseInput implements MouseInput { + + private static final Logger logger = Logger.getLogger(LwjglMouseInput.class.getName()); + + private LwjglWindow context; + private RawInputListener listener; + private boolean cursorVisible = true; + private int mouseX; + private int mouseY; + private int mouseWheel; + private boolean initialized; + private GLFWCursorPosCallback cursorPosCallback; + private GLFWScrollCallback scrollCallback; + private GLFWMouseButtonCallback mouseButtonCallback; + private Queue mouseMotionEvents = new LinkedList(); + private Queue mouseButtonEvents = new LinkedList(); + + public LwjglMouseInput(LwjglWindow context) { + this.context = context; + } + + 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 = (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 * -1, xDelta, yDelta * -1, mouseWheel, 0); + mouseMotionEvent.setTime(getInputTimeNanos()); + mouseMotionEvents.add(mouseMotionEvent); + } + } + }); + + 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); + } + }); + + 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(button, action == GLFW_PRESS, mouseX, mouseY); + mouseButtonEvent.setTime(getInputTimeNanos()); + mouseButtonEvents.add(mouseButtonEvent); + } + }); + + setCursorVisible(cursorVisible); + logger.fine("Mouse created."); + initialized = true; + } + + public boolean isInitialized() { + return initialized; + } + + public int getButtonCount() { + return 2; // TODO: How to determine this? + } + + public void update() { + while (!mouseMotionEvents.isEmpty()) { + listener.onMouseMotionEvent(mouseMotionEvents.poll()); + } + + while (!mouseButtonEvents.isEmpty()) { + listener.onMouseButtonEvent(mouseButtonEvents.poll()); + } + } + + public void destroy() { + if (!context.isRenderable()) { + return; + } + + cursorPosCallback.release(); + scrollCallback.release(); + mouseButtonCallback.release(); + + logger.fine("Mouse destroyed."); + } + + public void setCursorVisible(boolean visible) { + cursorVisible = visible; + + if (!context.isRenderable()) { + return; + } + + if (cursorVisible) { + glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } else { + glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + } + + public void setNativeCursor(final 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); + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java new file mode 100644 index 000000000..80e7f3513 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -0,0 +1,458 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GL2; +import com.jme3.renderer.opengl.GL3; +import com.jme3.renderer.opengl.GL4; +import com.jme3.system.NativeLibraryLoader; +import com.jme3.system.Platform; +import org.lwjgl.opengl.*; + +import java.nio.*; + +public class LwjglGL implements GL, GL2, GL3, GL4 { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + public void resetStats() { + } + + public void glActiveTexture(int param1) { + GL13.glActiveTexture(param1); + } + + public void glAlphaFunc(int param1, float param2) { + GL11.glAlphaFunc(param1, param2); + } + + public void glAttachShader(int param1, int param2) { + GL20.glAttachShader(param1, param2); + } + + public void glBindBuffer(int param1, int param2) { + GL15.glBindBuffer(param1, param2); + } + + public void glBindTexture(int param1, int param2) { + GL11.glBindTexture(param1, param2); + } + + public void glBlendFunc(int param1, int param2) { + GL11.glBlendFunc(param1, param2); + } + + public void glBufferData(int param1, long param2, int param3) { + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, FloatBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, ShortBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, ByteBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, FloatBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, ShortBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, ByteBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glClear(int param1) { + GL11.glClear(param1); + } + + public void glClearColor(float param1, float param2, float param3, float param4) { + GL11.glClearColor(param1, param2, param3, param4); + } + + public void glColorMask(boolean param1, boolean param2, boolean param3, boolean param4) { + GL11.glColorMask(param1, param2, param3, param4); + } + + public void glCompileShader(int param1) { + GL20.glCompileShader(param1); + } + + public void glCompressedTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { + checkLimit(param7); + GL13.glCompressedTexImage2D(param1, param2, param3, param4, param5, param6, param7); + } + + public void glCompressedTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { + checkLimit(param8); + GL13.glCompressedTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8); + } + + public void glCompressedTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { + checkLimit(param8); + GL13.glCompressedTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8); + } + + public void glCompressedTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { + checkLimit(param10); + GL13.glCompressedTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); + } + + public int glCreateProgram() { + return GL20.glCreateProgram(); + } + + public int glCreateShader(int param1) { + return GL20.glCreateShader(param1); + } + + public void glCullFace(int param1) { + GL11.glCullFace(param1); + } + + public void glDeleteBuffers(IntBuffer param1) { + checkLimit(param1); + GL15.glDeleteBuffers(param1); + } + + public void glDeleteProgram(int param1) { + GL20.glDeleteProgram(param1); + } + + public void glDeleteShader(int param1) { + GL20.glDeleteShader(param1); + } + + public void glDeleteTextures(IntBuffer param1) { + checkLimit(param1); + GL11.glDeleteTextures(param1); + } + + public void glDepthFunc(int param1) { + GL11.glDepthFunc(param1); + } + + public void glDepthMask(boolean param1) { + GL11.glDepthMask(param1); + } + + public void glDepthRange(double param1, double param2) { + GL11.glDepthRange(param1, param2); + } + + public void glDetachShader(int param1, int param2) { + GL20.glDetachShader(param1, param2); + } + + public void glDisable(int param1) { + GL11.glDisable(param1); + } + + public void glDisableVertexAttribArray(int param1) { + GL20.glDisableVertexAttribArray(param1); + } + + public void glDrawArrays(int param1, int param2, int param3) { + GL11.glDrawArrays(param1, param2, param3); + } + + public void glDrawBuffer(int param1) { + GL11.glDrawBuffer(param1); + } + + public void glDrawRangeElements(int param1, int param2, int param3, int param4, int param5, long param6) { + GL12.glDrawRangeElements(param1, param2, param3, param4, param5, param6); + } + + public void glEnable(int param1) { + GL11.glEnable(param1); + } + + public void glEnableVertexAttribArray(int param1) { + GL20.glEnableVertexAttribArray(param1); + } + + public void glGenBuffers(IntBuffer param1) { + checkLimit(param1); + GL15.glGenBuffers(param1); + } + + public void glGenTextures(IntBuffer param1) { + checkLimit(param1); + GL11.glGenTextures(param1); + } + + public void glGetBoolean(int param1, ByteBuffer param2) { + checkLimit(param2); + GL11.glGetBooleanv(param1, param2); + } + + public void glGetBufferSubData(int target, long offset, ByteBuffer data) { + checkLimit(data); + GL15.glGetBufferSubData(target, offset, data); + } + + public int glGetError() { + return GL11.glGetError(); + } + + public void glGetInteger(int param1, IntBuffer param2) { + checkLimit(param2); + GL11.glGetIntegerv(param1, param2); + } + + public void glGetProgram(int param1, int param2, IntBuffer param3) { + checkLimit(param3); + GL20.glGetProgramiv(param1, param2, param3); + } + + public void glGetShader(int param1, int param2, IntBuffer param3) { + checkLimit(param3); + GL20.glGetShaderiv(param1, param2, param3); + } + + public String glGetString(int param1) { + return GL11.glGetString(param1); + } + + public String glGetString(int param1, int param2) { + return GL30.glGetStringi(param1, param2); + } + + public boolean glIsEnabled(int param1) { + return GL11.glIsEnabled(param1); + } + + public void glLineWidth(float param1) { + GL11.glLineWidth(param1); + } + + public void glLinkProgram(int param1) { + GL20.glLinkProgram(param1); + } + + public void glPixelStorei(int param1, int param2) { + GL11.glPixelStorei(param1, param2); + } + + public void glPointSize(float param1) { + GL11.glPointSize(param1); + } + + public void glPolygonMode(int param1, int param2) { + GL11.glPolygonMode(param1, param2); + } + + public void glPolygonOffset(float param1, float param2) { + GL11.glPolygonOffset(param1, param2); + } + + public void glReadBuffer(int param1) { + GL11.glReadBuffer(param1); + } + + public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { + checkLimit(param7); + GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); + } + + public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, long param7) { + GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); + } + + public void glScissor(int param1, int param2, int param3, int param4) { + GL11.glScissor(param1, param2, param3, param4); + } + + public void glStencilFuncSeparate(int param1, int param2, int param3, int param4) { + GL20.glStencilFuncSeparate(param1, param2, param3, param4); + } + + public void glStencilOpSeparate(int param1, int param2, int param3, int param4) { + GL20.glStencilOpSeparate(param1, param2, param3, param4); + } + + public void glTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { + checkLimit(param9); + GL11.glTexImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + public void glTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { + checkLimit(param10); + GL12.glTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); + } + + public void glTexParameterf(int param1, int param2, float param3) { + GL11.glTexParameterf(param1, param2, param3); + } + + public void glTexParameteri(int param1, int param2, int param3) { + GL11.glTexParameteri(param1, param2, param3); + } + + public void glTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { + checkLimit(param9); + GL11.glTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + public void glTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10, ByteBuffer param11) { + checkLimit(param11); + GL12.glTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11); + } + + public void glUniform1(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform1fv(param1, param2); + } + + public void glUniform1(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform1iv(param1, param2); + } + + public void glUniform1f(int param1, float param2) { + GL20.glUniform1f(param1, param2); + } + + public void glUniform1i(int param1, int param2) { + GL20.glUniform1i(param1, param2); + } + + public void glUniform2(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform2iv(param1, param2); + } + + public void glUniform2(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform2fv(param1, param2); + } + + public void glUniform2f(int param1, float param2, float param3) { + GL20.glUniform2f(param1, param2, param3); + } + + public void glUniform3(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform3iv(param1, param2); + } + + public void glUniform3(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform3fv(param1, param2); + } + + public void glUniform3f(int param1, float param2, float param3, float param4) { + GL20.glUniform3f(param1, param2, param3, param4); + } + + public void glUniform4(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform4fv(param1, param2); + } + + public void glUniform4(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform4iv(param1, param2); + } + + public void glUniform4f(int param1, float param2, float param3, float param4, float param5) { + GL20.glUniform4f(param1, param2, param3, param4, param5); + } + + public void glUniformMatrix3(int param1, boolean param2, FloatBuffer param3) { + checkLimit(param3); + GL20.glUniformMatrix3fv(param1, param2, param3); + } + + public void glUniformMatrix4(int param1, boolean param2, FloatBuffer param3) { + checkLimit(param3); + GL20.glUniformMatrix4fv(param1, param2, param3); + } + + public void glUseProgram(int param1) { + GL20.glUseProgram(param1); + } + + public void glVertexAttribPointer(int param1, int param2, int param3, boolean param4, int param5, long param6) { + GL20.glVertexAttribPointer(param1, param2, param3, param4, param5, param6); + } + + public void glViewport(int param1, int param2, int param3, int param4) { + GL11.glViewport(param1, param2, param3, param4); + } + + public int glGetAttribLocation(int param1, String param2) { + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetAttribLocation(param1, param2 + "\0"); + } + + public int glGetUniformLocation(int param1, String param2) { + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetUniformLocation(param1, param2 + "\0"); + } + + public void glShaderSource(int param1, String[] param2, IntBuffer param3) { + checkLimit(param3); + GL20.glShaderSource(param1, param2); + } + + public String glGetProgramInfoLog(int program, int maxSize) { + return GL20.glGetProgramInfoLog(program, maxSize); + } + + public String glGetShaderInfoLog(int shader, int maxSize) { + return GL20.glGetShaderInfoLog(shader, maxSize); + } + + @Override + public void glBindFragDataLocation(int param1, int param2, String param3) { + GL30.glBindFragDataLocation(param1, param2, param3); + } + + @Override + public void glBindVertexArray(int param1) { + GL30.glBindVertexArray(param1); + } + + @Override + public void glGenVertexArrays(IntBuffer param1) { + checkLimit(param1); + GL30.glGenVertexArrays(param1); + } + + @Override + public void glPatchParameter(int count) { + GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES,count); + } + + @Override + public void glDeleteVertexArrays(IntBuffer arrays) { + checkLimit(arrays); + ARBVertexArrayObject.glDeleteVertexArrays(arrays); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java new file mode 100644 index 000000000..00b3f688c --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java @@ -0,0 +1,83 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLExt; +import org.lwjgl.opengl.*; + +import java.nio.Buffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public class LwjglGLExt implements GLExt { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBufferData(int target, IntBuffer data, int usage) { + checkLimit(data); + GL15.glBufferData(target, data, usage); + } + + @Override + public void glBufferSubData(int target, long offset, IntBuffer data) { + checkLimit(data); + GL15.glBufferSubData(target, offset, data); + } + + @Override + public void glDrawArraysInstancedARB(int mode, int first, int count, int primcount) { + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); + } + + @Override + public void glDrawBuffers(IntBuffer bufs) { + checkLimit(bufs); + GL20.glDrawBuffers(bufs); + } + + @Override + public void glDrawElementsInstancedARB(int mode, int indices_count, int type, long indices_buffer_offset, int primcount) { + ARBDrawInstanced.glDrawElementsInstancedARB(mode, indices_count, type, indices_buffer_offset, primcount); + } + + @Override + public void glGetMultisample(int pname, int index, FloatBuffer val) { + checkLimit(val); + ARBTextureMultisample.glGetMultisamplefv(pname, index, val); + } + + @Override + public void glTexImage2DMultisample(int target, int samples, int internalformat, int width, int height, boolean fixedsamplelocations) { + ARBTextureMultisample.glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); + } + + @Override + public void glVertexAttribDivisorARB(int index, int divisor) { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } + + @Override + public Object glFenceSync(int condition, int flags) { + return ARBSync.glFenceSync(condition, flags); + } + + @Override + public int glClientWaitSync(final Object sync, final int flags, final long timeout) { + return ARBSync.glClientWaitSync((Long) sync, flags, timeout); + } + + @Override + public void glDeleteSync(final Object sync) { + ARBSync.glDeleteSync((Long) sync); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java new file mode 100644 index 000000000..969d7ae1d --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java @@ -0,0 +1,99 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLFbo; +import org.lwjgl.opengl.EXTFramebufferBlit; +import org.lwjgl.opengl.EXTFramebufferMultisample; +import org.lwjgl.opengl.EXTFramebufferObject; + +import java.nio.Buffer; +import java.nio.IntBuffer; + +/** + * Implements GLFbo via GL_EXT_framebuffer_object. + * + * @author Kirill Vainer + */ +public class LwjglGLFboEXT implements GLFbo { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + EXTFramebufferBlit.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + + @Override + public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { + EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height); + } + + @Override + public void glBindFramebufferEXT(int param1, int param2) { + EXTFramebufferObject.glBindFramebufferEXT(param1, param2); + } + + @Override + public void glBindRenderbufferEXT(int param1, int param2) { + EXTFramebufferObject.glBindRenderbufferEXT(param1, param2); + } + + @Override + public int glCheckFramebufferStatusEXT(int param1) { + return EXTFramebufferObject.glCheckFramebufferStatusEXT(param1); + } + + @Override + public void glDeleteFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glDeleteFramebuffersEXT(param1); + } + + @Override + public void glDeleteRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glDeleteRenderbuffersEXT(param1); + } + + @Override + public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { + EXTFramebufferObject.glFramebufferRenderbufferEXT(param1, param2, param3, param4); + } + + @Override + public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { + EXTFramebufferObject.glFramebufferTexture2DEXT(param1, param2, param3, param4, param5); + } + + @Override + public void glGenFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glGenFramebuffersEXT(param1); + } + + @Override + public void glGenRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glGenRenderbuffersEXT(param1); + } + + @Override + public void glGenerateMipmapEXT(int param1) { + EXTFramebufferObject.glGenerateMipmapEXT(param1); + } + + @Override + public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { + EXTFramebufferObject.glRenderbufferStorageEXT(param1, param2, param3, param4); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java new file mode 100644 index 000000000..aa15aeb09 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java @@ -0,0 +1,97 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLFbo; +import org.lwjgl.opengl.GL30; + +import java.nio.Buffer; +import java.nio.IntBuffer; + +/** + * Implements GLFbo via OpenGL3+. + * + * @author Kirill Vainer + */ +public class LwjglGLFboGL3 implements GLFbo { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + + @Override + public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { + GL30.glRenderbufferStorageMultisample(target, samples, internalformat, width, height); + } + + @Override + public void glBindFramebufferEXT(int param1, int param2) { + GL30.glBindFramebuffer(param1, param2); + } + + @Override + public void glBindRenderbufferEXT(int param1, int param2) { + GL30.glBindRenderbuffer(param1, param2); + } + + @Override + public int glCheckFramebufferStatusEXT(int param1) { + return GL30.glCheckFramebufferStatus(param1); + } + + @Override + public void glDeleteFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glDeleteFramebuffers(param1); + } + + @Override + public void glDeleteRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glDeleteRenderbuffers(param1); + } + + @Override + public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { + GL30.glFramebufferRenderbuffer(param1, param2, param3, param4); + } + + @Override + public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { + GL30.glFramebufferTexture2D(param1, param2, param3, param4, param5); + } + + @Override + public void glGenFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glGenFramebuffers(param1); + } + + @Override + public void glGenRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glGenRenderbuffers(param1); + } + + @Override + public void glGenerateMipmapEXT(int param1) { + GL30.glGenerateMipmap(param1); + } + + @Override + public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { + GL30.glRenderbufferStorage(param1, param2, param3, param4); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java new file mode 100644 index 000000000..1f1ef2ab5 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; + +import javax.swing.*; +import java.awt.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; + +public class LwjglCanvas extends LwjglWindow implements JmeCanvasContext { + + protected static final int TASK_NOTHING = 0, + TASK_DESTROY_DISPLAY = 1, + TASK_CREATE_DISPLAY = 2, + TASK_COMPLETE = 3; + +// protected static final boolean USE_SHARED_CONTEXT = +// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true")); + + protected static final boolean USE_SHARED_CONTEXT = false; + + private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName()); + private Canvas canvas; + private int width; + private int height; + + private final Object taskLock = new Object(); + private int desiredTask = TASK_NOTHING; + + private Thread renderThread; + private boolean runningFirstTime = true; + private boolean mouseWasGrabbed = false; + + private boolean mouseWasCreated = false; + private boolean keyboardWasCreated = false; + + private long window; + + private class GLCanvas extends Canvas { + @Override + public void addNotify(){ + super.addNotify(); + + if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED) { + return; // already destroyed. + } + + if (renderThread == null){ + logger.log(Level.FINE, "EDT: Creating OGL thread."); + + // Also set some settings on the canvas here. + // So we don't do it outside the AWT thread. + canvas.setFocusable(true); + canvas.setIgnoreRepaint(true); + + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); + renderThread.start(); + }else if (needClose.get()){ + return; + } + + logger.log(Level.FINE, "EDT: Telling OGL to create display .."); + synchronized (taskLock){ + desiredTask = TASK_CREATE_DISPLAY; +// while (desiredTask != TASK_COMPLETE){ +// try { +// taskLock.wait(); +// } catch (InterruptedException ex) { +// return; +// } +// } +// desiredTask = TASK_NOTHING; + } +// logger.log(Level.FINE, "EDT: OGL has created the display"); + } + + @Override + public void removeNotify(){ + if (needClose.get()){ + logger.log(Level.FINE, "EDT: Application is stopped. Not restoring canvas."); + super.removeNotify(); + return; + } + + // We must tell GL context to shutdown and wait for it to + // shutdown, otherwise, issues will occur. + logger.log(Level.FINE, "EDT: Telling OGL to destroy display .."); + synchronized (taskLock){ + desiredTask = TASK_DESTROY_DISPLAY; + while (desiredTask != TASK_COMPLETE){ + try { + taskLock.wait(); + } catch (InterruptedException ex){ + super.removeNotify(); + return; + } + } + desiredTask = TASK_NOTHING; + } + + logger.log(Level.FINE, "EDT: Acknowledged receipt of canvas death"); + // GL context is dead at this point + + super.removeNotify(); + } + } + + public LwjglCanvas(){ + super(Type.Canvas); + canvas = new GLCanvas(); + } + + public void create(boolean waitFor){ + if (renderThread == null){ + logger.log(Level.FINE, "MAIN: Creating OGL thread."); + + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); + renderThread.start(); + } + // do not do anything. + // superclass's create() will be called at initInThread() + if (waitFor) { + waitFor(true); + } + } + + public Canvas getCanvas(){ + return canvas; + } + + @Override + protected void runLoop(){ + if (desiredTask != TASK_NOTHING){ + synchronized (taskLock){ + switch (desiredTask){ + case TASK_CREATE_DISPLAY: + logger.log(Level.FINE, "OGL: Creating display .."); + restoreCanvas(); + listener.gainFocus(); + desiredTask = TASK_NOTHING; + break; + case TASK_DESTROY_DISPLAY: + logger.log(Level.FINE, "OGL: Destroying display .."); + listener.loseFocus(); + pauseCanvas(); + break; + } + desiredTask = TASK_COMPLETE; + taskLock.notifyAll(); + } + } + + if (renderable.get()){ + int newWidth = Math.max(canvas.getWidth(), 1); + int newHeight = Math.max(canvas.getHeight(), 1); + + if (width != newWidth || height != newHeight){ + width = newWidth; + height = newHeight; + if (listener != null){ + listener.reshape(width, height); + } + } + } + + super.runLoop(); + } + + private void pauseCanvas(){ + if (mouseInput != null) { + mouseInput.setCursorVisible(true); + mouseWasCreated = true; + } + +/* + if (Mouse.isCreated()){ + if (Mouse.isGrabbed()){ + Mouse.setGrabbed(false); + mouseWasGrabbed = true; + } + mouseWasCreated = true; + Mouse.destroy(); + } + if (Keyboard.isCreated()){ + keyboardWasCreated = true; + Keyboard.destroy(); + } +*/ + + renderable.set(false); + destroyContext(); + } + + /** + * Called to restore the canvas. + */ + private void restoreCanvas(){ + logger.log(Level.FINE, "OGL: Waiting for canvas to become displayable.."); + while (!canvas.isDisplayable()){ + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "OGL: Interrupted! ", ex); + } + } + + logger.log(Level.FINE, "OGL: Creating display context .."); + + // Set renderable to true, since canvas is now displayable. + renderable.set(true); + createContext(settings); + + logger.log(Level.FINE, "OGL: Display is active!"); + + try { + if (mouseWasCreated){ +// Mouse.create(); +// if (mouseWasGrabbed){ +// Mouse.setGrabbed(true); +// mouseWasGrabbed = false; +// } + } + if (keyboardWasCreated){ +// Keyboard.create(); +// keyboardWasCreated = false; + } + } catch (Exception ex){ + logger.log(Level.SEVERE, "Encountered exception when restoring input", ex); + } + + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + canvas.requestFocus(); + } + }); + } + +/* + */ +/** + * Makes sure the pbuffer is available and ready for use + *//* + + protected void makePbufferAvailable() throws LWJGLException{ + if (pbuffer != null && pbuffer.isBufferLost()){ + logger.log(Level.WARNING, "PBuffer was lost!"); + pbuffer.destroy(); + pbuffer = null; + } + + if (pbuffer == null) { + pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); + pbuffer.makeCurrent(); + logger.log(Level.FINE, "OGL: Pbuffer has been created"); + + // Any created objects are no longer valid + if (!runningFirstTime){ + renderer.resetGLObjects(); + } + } + + pbuffer.makeCurrent(); + if (!pbuffer.isCurrent()){ + throw new LWJGLException("Pbuffer cannot be made current"); + } + } + + protected void destroyPbuffer(){ + if (pbuffer != null){ + if (!pbuffer.isBufferLost()){ + pbuffer.destroy(); + } + pbuffer = null; + } + } +*/ + + /** + * This is called: + * 1) When the context thread ends + * 2) Any time the canvas becomes non-displayable + */ + protected void destroyContext(){ + // invalidate the state so renderer can resume operation + if (!USE_SHARED_CONTEXT){ + renderer.cleanup(); + } + + if (window != 0) { + glfwDestroyWindow(window); + } + + // TODO: Destroy input + + + // The canvas is no longer visible, + // but the context thread is still running. + if (!needClose.get()){ + renderer.invalidateState(); + } + } + + /** + * This is called: + * 1) When the context thread starts + * 2) Any time the canvas becomes displayable again. + */ + @Override + protected void createContext(final AppSettings settings) { + // In case canvas is not visible, we still take framerate + // from settings to prevent "100% CPU usage" + allowSwapBuffers = settings.isSwapBuffers(); + + if (renderable.get()){ + if (!runningFirstTime){ + // because the display is a different opengl context + // must reset the context state. + if (!USE_SHARED_CONTEXT){ + renderer.cleanup(); + } + } + + super.createContext(settings); + } + + // At this point, the OpenGL context is active. + if (runningFirstTime) { + // THIS is the part that creates the renderer. + // It must always be called, now that we have the pbuffer workaround. + initContextFirstTime(); + runningFirstTime = false; + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java new file mode 100644 index 000000000..3f6491e5f --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.input.lwjgl.GlfwJoystickInput; +import com.jme3.input.lwjgl.LwjglKeyInput; +import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.RendererException; +import com.jme3.renderer.lwjgl.LwjglGL; +import com.jme3.renderer.lwjgl.LwjglGLExt; +import com.jme3.renderer.lwjgl.LwjglGLFboEXT; +import com.jme3.renderer.lwjgl.LwjglGLFboGL3; +import com.jme3.renderer.opengl.*; +import com.jme3.renderer.opengl.GL; +import com.jme3.system.*; +import org.lwjgl.Sys; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.*; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.opengl.GL.createCapabilities; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.opengl.GL11.glGetInteger; + +/** + * A LWJGL implementation of a graphics context. + */ +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(); + + protected AppSettings settings = new AppSettings(true); + protected Renderer renderer; + protected LwjglKeyInput keyInput; + protected LwjglMouseInput mouseInput; + protected GlfwJoystickInput joyInput; + protected Timer timer; + protected 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: GLFW {2}", + new Object[]{Sys.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) { + return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES); + } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) { + return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT); + } + + return Integer.MAX_VALUE; + } + + protected void registerNatives() { + // LWJGL + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl32.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl32.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/jemalloc32.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/jemalloc.dll"); + + // OpenAL + // For OSX: Need to add lib prefix when extracting + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal32.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + } + + protected void loadNatives() { + if (JmeSystem.isLowPermissions()) { + return; + } + if ("LWJGL".equals(settings.getAudioRenderer())) { + NativeLibraryLoader.loadNativeLibrary("openal", true); + } + if (settings.useJoysticks()) { + //NativeLibraryLoader.loadNativeLibrary("jinput", true); + //NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true); + } + if (NativeLibraryLoader.isUsingNativeBullet()) { + NativeLibraryLoader.loadNativeLibrary("bulletjme", true); + } + NativeLibraryLoader.loadNativeLibrary("lwjgl", true); + } + + protected int getNumSamplesToUse() { + int samples = 0; + if (settings.getSamples() > 1) { + samples = settings.getSamples(); + final int supportedSamples = determineMaxSamples(); + if (supportedSamples < samples) { + logger.log(Level.WARNING, + "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() { + final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)); + + if (!capabilities.OpenGL20) { + 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)) { + GL gl = new LwjglGL(); + GLExt glext = new LwjglGLExt(); + GLFbo glfbo; + + if (capabilities.OpenGL30) { + glfbo = new LwjglGLFboGL3(); + } else { + glfbo = new LwjglGLFboEXT(); + } + + 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 = (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); + 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 (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. + } + + renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); + renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); + + // Init input + if (keyInput != null) { + keyInput.initialize(); + } + + if (mouseInput != null) { + mouseInput.initialize(); + } + + if (joyInput != null) { + joyInput.initialize(); + } + + renderable.set(true); + } + + public void internalDestroy() { + renderer = null; + timer = null; + renderable.set(false); + synchronized (createdLock) { + created.set(false); + createdLock.notifyAll(); + } + } + + public void internalCreate() { + synchronized (createdLock) { + created.set(true); + createdLock.notifyAll(); + } + + //if (renderable.get()) { + initContextFirstTime(); + //} else { +// assert getType() == Type.Canvas; +// } + } + + public void create() { + create(false); + } + + public void destroy() { + destroy(false); + } + + protected void waitFor(boolean createdVal) { + synchronized (createdLock) { + while (created.get() != createdVal) { + try { + createdLock.wait(); + } catch (InterruptedException ex) { + } + } + } + } + + public boolean isCreated() { + return created.get(); + } + + public boolean isRenderable() { + return renderable.get(); + } + + public void setSettings(AppSettings settings) { + this.settings.copyFrom(settings); + } + + public AppSettings getSettings() { + return settings; + } + + public Renderer getRenderer() { + return renderer; + } + + public Timer getTimer() { + return timer; + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java new file mode 100644 index 000000000..4a13c30af --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java @@ -0,0 +1,12 @@ +package com.jme3.system.lwjgl; + +/** + * @author Daniel Johansson + * @since 2015-08-11 + */ +public class LwjglDisplay extends LwjglWindow { + + public LwjglDisplay() { + super(Type.Display); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java new file mode 100644 index 000000000..aa9c46511 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java @@ -0,0 +1,78 @@ +/* + * 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.system.lwjgl; + +import org.lwjgl.opengl.ARBDebugOutput; +import org.lwjgl.opengl.GLDebugMessageARBCallback; + +import java.util.HashMap; + +class LwjglGLDebugOutputHandler extends GLDebugMessageARBCallback { + + private static final HashMap constMap = new HashMap(); + private static final String MESSAGE_FORMAT = + "[JME3] OpenGL debug message\r\n" + + " ID: %d\r\n" + + " Source: %s\r\n" + + " Type: %s\r\n" + + " Severity: %s\r\n" + + " Message: %s"; + + static { + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_API_ARB, "API"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_APPLICATION_ARB, "APPLICATION"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_OTHER_ARB, "OTHER"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, "SHADER_COMPILER"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_THIRD_PARTY_ARB, "THIRD_PARTY"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB, "WINDOW_SYSTEM"); + + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, "DEPRECATED_BEHAVIOR"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_ERROR_ARB, "ERROR"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_OTHER_ARB, "OTHER"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PERFORMANCE_ARB, "PERFORMANCE"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PORTABILITY_ARB, "PORTABILITY"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, "UNDEFINED_BEHAVIOR"); + + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB, "HIGH"); + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB, "MEDIUM"); + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB, "LOW"); + } + + @Override + public void invoke(int source, int type, int id, int severity, int length, long message, long userParam) { + String sourceStr = constMap.get(source); + String typeStr = constMap.get(type); + String severityStr = constMap.get(severity); + + System.err.println(String.format(MESSAGE_FORMAT, id, sourceStr, typeStr, severityStr, message)); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java new file mode 100644 index 000000000..e374e1841 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java @@ -0,0 +1,14 @@ +package com.jme3.system.lwjgl; + +import com.jme3.system.JmeContext; + +/** + * @author Daniel Johansson + * @since 2015-08-11 + */ +public class LwjglOffscreenBuffer extends LwjglWindow { + + public LwjglOffscreenBuffer() { + super(JmeContext.Type.OffscreenSurface); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java new file mode 100644 index 000000000..a7960a261 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.math.FastMath; +import com.jme3.system.Timer; +import org.lwjgl.glfw.GLFW; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Timer handles the system's time related functionality. This + * allows the calculation of the framerate. To keep the framerate calculation + * accurate, a call to update each frame is required. Timer is a + * singleton object and must be created via the getTimer method. + * + * @author Mark Powell + * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ + */ +public class LwjglSmoothingTimer extends LwjglTimer { + private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class + .getName()); + + private long lastFrameDiff; + + //frame rate parameters. + private long oldTime; + + private float lastTPF, lastFPS; + + public static int TIMER_SMOOTHNESS = 32; + + private long[] tpf; + + private int smoothIndex; + + private final static long LWJGL_TIMER_RES = 1; + private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); + private static float invTimerRezSmooth; + + public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); + + private long startTime; + + private boolean allSmooth = false; + + /** + * Constructor builds a Timer object. All values will be + * initialized to it's default values. + */ + public LwjglSmoothingTimer() { + reset(); + + //print timer resolution info + logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); + } + + public void reset() { + lastFrameDiff = 0; + lastFPS = 0; + lastTPF = 0; + + // init to -1 to indicate this is a new timer. + oldTime = -1; + //reset time + startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + + tpf = new long[TIMER_SMOOTHNESS]; + smoothIndex = TIMER_SMOOTHNESS - 1; + invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS)); + + // set tpf... -1 values will not be used for calculating the average in update() + for ( int i = tpf.length; --i >= 0; ) { + tpf[i] = -1; + } + } + + /** + * @see Timer#getResolution() + */ + public long getResolution() { + return LWJGL_TIMER_RES; + } + + /** + * getFrameRate returns the current frame rate since the last + * call to update. + * + * @return the current frame rate. + */ + public float getFrameRate() { + return lastFPS; + } + + public float getTimePerFrame() { + return lastTPF; + } + + /** + * update recalulates the frame rate based on the previous + * call to update. It is assumed that update is called each frame. + */ + public void update() { + long newTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + long oldTime = this.oldTime; + this.oldTime = newTime; + if ( oldTime == -1 ) { + // For the first frame use 60 fps. This value will not be counted in further averages. + // This is done so initialization code between creating the timer and the first + // frame is not counted as a single frame on it's own. + lastTPF = 1 / 60f; + lastFPS = 1f / lastTPF; + return; + } + + long frameDiff = newTime - oldTime; + long lastFrameDiff = this.lastFrameDiff; + if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) { + frameDiff = lastFrameDiff *100; + } + this.lastFrameDiff = frameDiff; + tpf[smoothIndex] = frameDiff; + smoothIndex--; + if ( smoothIndex < 0 ) { + smoothIndex = tpf.length - 1; + } + + lastTPF = 0.0f; + if (!allSmooth) { + int smoothCount = 0; + for ( int i = tpf.length; --i >= 0; ) { + if ( tpf[i] != -1 ) { + lastTPF += tpf[i]; + smoothCount++; + } + } + if (smoothCount == tpf.length) + allSmooth = true; + lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount ); + } else { + for ( int i = tpf.length; --i >= 0; ) { + if ( tpf[i] != -1 ) { + lastTPF += tpf[i]; + } + } + lastTPF *= invTimerRezSmooth; + } + if ( lastTPF < FastMath.FLT_EPSILON ) { + lastTPF = FastMath.FLT_EPSILON; + } + + lastFPS = 1f / lastTPF; + } + + /** + * toString returns the string representation of this timer + * in the format:
+ *
+ * jme.utility.Timer@1db699b
+ * Time: {LONG}
+ * FPS: {LONG}
+ * + * @return the string representation of this object. + */ + @Override + public String toString() { + String string = super.toString(); + string += "\nTime: " + oldTime; + string += "\nFPS: " + getFrameRate(); + return string; + } +} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java new file mode 100644 index 000000000..c4a0e5025 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.system.Timer; +import org.lwjgl.glfw.GLFW; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Timer handles the system's time related functionality. This + * allows the calculation of the framerate. To keep the framerate calculation + * accurate, a call to update each frame is required. Timer is a + * singleton object and must be created via the getTimer method. + * + * @author Mark Powell + * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ + */ +public class LwjglTimer extends Timer { + + private static final Logger logger = Logger.getLogger(LwjglTimer.class.getName()); + + //frame rate parameters. + private long oldTime; + private long startTime; + + private float lastTPF, lastFPS; + + private final static long LWJGL_TIMER_RES = 1; + private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); + public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); + + /** + * Constructor builds a Timer object. All values will be + * initialized to it's default values. + */ + public LwjglTimer() { + reset(); + logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); + } + + public void reset() { + startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + oldTime = getTime(); + } + + @Override + public float getTimeInSeconds() { + return getTime() * INV_LWJGL_TIMER_RES; + } + + /** + * @see Timer#getTime() + */ + public long getTime() { + return ((long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS) - startTime); + } + + /** + * @see Timer#getResolution() + */ + public long getResolution() { + return LWJGL_TIMER_RES; + } + + /** + * getFrameRate returns the current frame rate since the last + * call to update. + * + * @return the current frame rate. + */ + public float getFrameRate() { + return lastFPS; + } + + public float getTimePerFrame() { + return lastTPF; + } + + /** + * update recalulates the frame rate based on the previous + * call to update. It is assumed that update is called each frame. + */ + public void update() { + long curTime = getTime(); + lastTPF = (curTime - oldTime) * (1.0f / LWJGL_TIMER_RES); + lastFPS = 1.0f / lastTPF; + oldTime = curTime; + } + + /** + * toString returns the string representation of this timer + * in the format:
+ *
+ * jme.utility.Timer@1db699b
+ * Time: {LONG}
+ * FPS: {LONG}
+ * + * @return the string representation of this object. + */ + @Override + public String toString() { + String string = super.toString(); + string += "\nTime: " + oldTime; + string += "\nFPS: " + getFrameRate(); + return string; + } +} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java new file mode 100644 index 000000000..c089bf28d --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.input.JoyInput; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.TouchInput; +import com.jme3.input.lwjgl.GlfwJoystickInput; +import com.jme3.input.lwjgl.LwjglKeyInput; +import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext; +import com.jme3.system.JmeSystem; +import org.lwjgl.PointerBuffer; +import org.lwjgl.Sys; +import org.lwjgl.glfw.*; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; +import static org.lwjgl.opengl.GL11.GL_FALSE; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.system.MemoryUtil.NULL; + +/** + * A wrapper class over the GLFW framework in LWJGL 3. + * + * @author Daniel Johansson (dannyjo) + * @since 3.1 + */ +public abstract class LwjglWindow extends LwjglContext implements Runnable { + + private static final Logger LOGGER = Logger.getLogger(LwjglWindow.class.getName()); + + protected AtomicBoolean needClose = new AtomicBoolean(false); + protected final AtomicBoolean needRestart = new AtomicBoolean(false); + protected boolean wasActive = false; + protected boolean autoFlush = true; + protected boolean allowSwapBuffers = false; + private long window = -1; + private final JmeContext.Type type; + + private GLFWErrorCallback errorCallback; + private GLFWWindowSizeCallback windowSizeCallback; + private GLFWWindowFocusCallback windowFocusCallback; + + public LwjglWindow(final JmeContext.Type type) { + if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) { + throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided"); + } + + this.type = type; + } + + /** + * @return Type.Display or Type.Canvas + */ + public JmeContext.Type getType() { + return type; + } + + /** + * Set the title if its a windowed display + * + * @param title + */ + public void setTitle(final String title) { + if (created.get() && window != -1) { + glfwSetWindowTitle(window, title); + } + } + + /** + * Restart if its a windowed or full-screen display. + */ + public void restart() { + if (created.get()) { + needRestart.set(true); + } else { + LOGGER.warning("Display is not created, cannot restart window."); + } + } + + /** + * Apply the settings, changing resolution, etc. + * + * @param settings + */ + protected void createContext(final AppSettings settings) { + glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { + @Override + public void invoke(int error, long description) { + final String message = Callbacks.errorCallbackDescriptionString(description); + listener.handleError(message, new Exception(message)); + } + }); + + if (glfwInit() != GL_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(); + } + + final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + + if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { + settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode)); + } + + window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); + + if (window == NULL) { + throw new RuntimeException("Failed to create the GLFW window"); + } + + glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE); + 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); + + int frameRateCap = settings.getFrameRate(); + + if (!autoFlush) { + frameRateCap = 20; + } + + if (frameRateCap > 0) { + glfwWindowHint(GLFW_REFRESH_RATE, frameRateCap); + } + + // Not sure how else to support bits per pixel + if (settings.getBitsPerPixel() == 24) { + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + } else if (settings.getBitsPerPixel() == 16) { + glfwWindowHint(GLFW_RED_BITS, 5); + glfwWindowHint(GLFW_GREEN_BITS, 6); + glfwWindowHint(GLFW_BLUE_BITS, 5); + } + + glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits()); + + glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { + @Override + public void invoke(final long window, final int focused) { + final boolean focus = (focused == 1); + + if (wasActive != focus) { + if (!wasActive) { + listener.gainFocus(); + timer.reset(); + } else { + listener.loseFocus(); + } + + wasActive = !wasActive; + } + + } + }); + + // Center the window + if (!settings.isFullscreen() && Type.Display.equals(type)) { + glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2); + } + + // Make the OpenGL context current + glfwMakeContextCurrent(window); + + // Enable vsync + if (settings.isVSync()) { + glfwSwapInterval(1); + } else { + glfwSwapInterval(0); + } + + + // Make the window visible + if (Type.Display.equals(type)) { + 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); + } + }); + + allowSwapBuffers = settings.isSwapBuffers(); + + // TODO: When GLFW 3.2 is released and included in LWJGL 3.x then we should hopefully be able to set the window icon. + } + + /** + * Destroy the context. + */ + protected void destroyContext() { + try { + if (renderer != null) { + renderer.cleanup(); + } + + errorCallback.release(); + windowSizeCallback.release(); + windowFocusCallback.release(); + + if (window != 0) { + glfwDestroyWindow(window); + } + //glfwTerminate(); + } catch (Exception ex) { + listener.handleError("Failed to destroy context", ex); + } + } + + public void create(boolean waitFor) { + if (created.get()) { + LOGGER.warning("create() called when display is already created!"); + return; + } + + new Thread(this, THREAD_NAME).start(); + if (waitFor) + waitFor(true); + } + + /** + * Does LWJGL display initialization in the OpenGL thread + */ + protected boolean initInThread() { + try { + if (!JmeSystem.isLowPermissions()) { + // Enable uncaught exception handler only for current thread + Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread thread, Throwable thrown) { + listener.handleError("Uncaught exception thrown in " + thread.toString(), thrown); + if (needClose.get()) { + // listener.handleError() has requested the + // context to close. Satisfy request. + deinitInThread(); + } + } + }); + } + + timer = new LwjglTimer(); + + // For canvas, this will create a pbuffer, + // allowing us to query information. + // When the canvas context becomes available, it will + // be replaced seamlessly. + createContext(settings); + printContextInitInfo(); + + created.set(true); + super.internalCreate(); + } catch (Exception ex) { + try { + if (window != -1) { + //glfwSetWindowShouldClose(window, GL_TRUE); + glfwDestroyWindow(window); + } + } catch (Exception ex2) { + LOGGER.log(Level.WARNING, null, ex2); + } + + listener.handleError("Failed to create display", ex); + return false; // if we failed to create display, do not continue + } + + listener.initialize(); + return true; + } + + /** + * execute one iteration of the render loop in the OpenGL thread + */ + protected void runLoop() { + // If a restart is required, lets recreate the context. + if (needRestart.getAndSet(false)) { + try { + createContext(settings); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); + } + + LOGGER.fine("Display restarted."); + } + + if (!created.get()) { + throw new IllegalStateException(); + } + + listener.update(); + + // All this does is call swap buffers + // If the canvas is not active, there's no need to waste time + // doing that .. + if (renderable.get()) { + // calls swap buffers, etc. + try { + if (allowSwapBuffers && autoFlush) { + glfwSwapBuffers(window); + } + } catch (Throwable ex) { + listener.handleError("Error while swapping buffers", ex); + } + } + + if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_TRUE) { + glfwPollEvents(); + } + + // Subclasses just call GLObjectManager clean up objects here + // it is safe .. for now. + if (renderer != null) { + renderer.postFrame(); + } + } + + /** + * De-initialize in the OpenGL thread. + */ + protected void deinitInThread() { + destroyContext(); + + listener.destroy(); + LOGGER.fine("Display destroyed."); + super.internalDestroy(); + } + + public void run() { + if (listener == null) { + throw new IllegalStateException("SystemListener is not set on context!" + + "Must set with JmeContext.setSystemListner()."); + } + + registerNatives(); + loadNatives(); + LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); + + if (!initInThread()) { + LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue."); + return; + } + + while (true) { + if (glfwWindowShouldClose(window) == GL_TRUE) { + listener.requestClose(false); + } + + runLoop(); + + if (needClose.get()) { + break; + } + } + + deinitInThread(); + } + + public JoyInput getJoyInput() { + if (joyInput == null) { + joyInput = new GlfwJoystickInput(); + } + return joyInput; + } + + public MouseInput getMouseInput() { + if (mouseInput == null) { + mouseInput = new LwjglMouseInput(this); + } + return mouseInput; + } + + public KeyInput getKeyInput() { + if (keyInput == null) { + keyInput = new LwjglKeyInput(this); + } + + return keyInput; + } + + public TouchInput getTouchInput() { + return null; + } + + public void setAutoFlushFrames(boolean enabled) { + this.autoFlush = enabled; + } + + public void destroy(boolean waitFor) { + needClose.set(true); + + if (waitFor) { + waitFor(false); + } + } + + public long getWindowHandle() { + return window; + } + + private ByteBuffer[] imagesToByteBuffers(Object[] images) { + ByteBuffer[] out = new ByteBuffer[images.length]; + for (int i = 0; i < images.length; i++) { + BufferedImage image = (BufferedImage) images[i]; + out[i] = imageToByteBuffer(image); + } + return out; + } + + private ByteBuffer imageToByteBuffer(BufferedImage image) { + if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { + BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE); + Graphics2D g = convertedImage.createGraphics(); + double width = image.getWidth() * (double) 1; + double height = image.getHeight() * (double) 1; + g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2), + (int) ((convertedImage.getHeight() - height) / 2), + (int) (width), (int) (height), null); + g.dispose(); + image = convertedImage; + } + + byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4]; + int counter = 0; + for (int i = 0; i < image.getHeight(); i++) { + for (int j = 0; j < image.getWidth(); j++) { + int colorSpace = image.getRGB(j, i); + imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24); + imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24); + imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24); + imageBuffer[counter + 3] = (byte) (colorSpace >> 24); + counter += 4; + } + } + return ByteBuffer.wrap(imageBuffer); + } +} diff --git a/settings.gradle b/settings.gradle index 89b8fc075..8b9000340 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,7 @@ include 'jme3-desktop' include 'jme3-blender' include 'jme3-jogl' include 'jme3-lwjgl' +include 'jme3-lwjgl3' // Other external dependencies include 'jme3-jbullet' From 8f77dca9314e4b2090acc4d30e80df50547cff1a Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Wed, 26 Aug 2015 22:24:24 +0100 Subject: [PATCH 04/13] Added jme3-lwjgl3 module which ultimately adds support for LWJGL 3.x and GLFW. --- common.gradle | 3 + .../resources/joystick-mapping.properties | 6 + .../com/jme3/system/NativeLibraryLoader.java | 22 +- .../system/lwjgl/LwjglAbstractDisplay.java | 2 +- .../com/jme3/system/lwjgl/LwjglContext.java | 28 +- jme3-lwjgl3/build.gradle | 12 + .../java/com/jme3/audio/lwjgl/LwjglAL.java | 140 +++++ .../java/com/jme3/audio/lwjgl/LwjglALC.java | 58 +++ .../java/com/jme3/audio/lwjgl/LwjglEFX.java | 66 +++ .../jme3/input/lwjgl/GlfwJoystickInput.java | 213 ++++++++ .../com/jme3/input/lwjgl/LwjglKeyInput.java | 116 +++++ .../com/jme3/input/lwjgl/LwjglMouseInput.java | 189 +++++++ .../java/com/jme3/renderer/lwjgl/LwjglGL.java | 458 ++++++++++++++++ .../com/jme3/renderer/lwjgl/LwjglGLExt.java | 83 +++ .../jme3/renderer/lwjgl/LwjglGLFboEXT.java | 99 ++++ .../jme3/renderer/lwjgl/LwjglGLFboGL3.java | 97 ++++ .../com/jme3/system/lwjgl/LwjglCanvas.java | 369 +++++++++++++ .../com/jme3/system/lwjgl/LwjglContext.java | 289 +++++++++++ .../com/jme3/system/lwjgl/LwjglDisplay.java | 12 + .../lwjgl/LwjglGLDebugOutputHandler.java | 78 +++ .../system/lwjgl/LwjglOffscreenBuffer.java | 14 + .../system/lwjgl/LwjglSmoothingTimer.java | 203 ++++++++ .../com/jme3/system/lwjgl/LwjglTimer.java | 139 +++++ .../com/jme3/system/lwjgl/LwjglWindow.java | 489 ++++++++++++++++++ settings.gradle | 1 + 25 files changed, 3158 insertions(+), 28 deletions(-) create mode 100644 jme3-lwjgl3/build.gradle create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java diff --git a/common.gradle b/common.gradle index 69b695ecd..1102f49ad 100644 --- a/common.gradle +++ b/common.gradle @@ -16,6 +16,9 @@ repositories { maven { url "http://nifty-gui.sourceforge.net/nifty-maven-repo" } + maven { + url "https://oss.sonatype.org/content/repositories/snapshots" + } } configurations { diff --git a/jme3-core/src/main/resources/joystick-mapping.properties b/jme3-core/src/main/resources/joystick-mapping.properties index d7ce2f50a..966832036 100644 --- a/jme3-core/src/main/resources/joystick-mapping.properties +++ b/jme3-core/src/main/resources/joystick-mapping.properties @@ -63,3 +63,9 @@ Xbox\ 360\ Wireless\ Receiver.AXIS_RX=z Xbox\ 360\ Wireless\ Receiver.AXIS_RY=rz Xbox\ 360\ Wireless\ Receiver.z=AXIS_RX Xbox\ 360\ Wireless\ Receiver.rz=AXIS_RY + +# Microsoft PC-joystick driver +Microsoft\ PC-joystick\ driver.12=POV +Y +Microsoft\ PC-joystick\ driver.13=POV +X +Microsoft\ PC-joystick\ driver.14=POV -Y +Microsoft\ PC-joystick\ driver.15=POV -X diff --git a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java index 2917350f6..6e83e0e6b 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java +++ b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java @@ -48,9 +48,8 @@ import java.util.logging.Logger; /** * Utility class to register, extract, and load native libraries. *
- * Register your own libraries via the - * {@link #registerNativeLibrary(java.lang.String, com.jme3.system.Platform, java.lang.String, boolean) } - * method, for each platform. + * Register your own libraries via the {@link #registerNativeLibrary(String, Platform, String, String)} method, for + * each platform. * You can then extract this library (depending on platform), by * using {@link #loadNativeLibrary(java.lang.String, boolean) }. *
@@ -125,23 +124,6 @@ public final class NativeLibraryLoader { } static { - // LWJGL - registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); - registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); - registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); - registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); - registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); - registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); - - // OpenAL - // For OSX: Need to add lib prefix when extracting - registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); - registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); - registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); - registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); - registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); - registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); - // BulletJme registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll"); registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll"); diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index 7cdca0a57..415084788 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -40,7 +40,6 @@ import com.jme3.input.lwjgl.JInputJoyInput; import com.jme3.input.lwjgl.LwjglKeyInput; import com.jme3.input.lwjgl.LwjglMouseInput; import com.jme3.system.AppSettings; -import com.jme3.system.JmeContext.Type; import com.jme3.system.JmeSystem; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -207,6 +206,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna + "Must set with JmeContext.setSystemListner()."); } + registerNatives(); loadNatives(); logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); if (!initInThread()) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index c88f7b734..70885c39b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -52,12 +52,8 @@ import com.jme3.renderer.opengl.GLRenderer; import com.jme3.renderer.opengl.GLTiming; import com.jme3.renderer.opengl.GLTimingState; import com.jme3.renderer.opengl.GLTracer; -import com.jme3.system.AppSettings; -import com.jme3.system.JmeContext; -import com.jme3.system.JmeSystem; -import com.jme3.system.NativeLibraryLoader; -import com.jme3.system.SystemListener; -import com.jme3.system.Timer; +import com.jme3.system.*; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -166,7 +162,25 @@ public abstract class LwjglContext implements JmeContext { } } } - + + protected void registerNatives() { + // LWJGL + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + + // For OSX: Need to add lib prefix when extracting + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + } + protected void loadNatives() { if (JmeSystem.isLowPermissions()) { return; diff --git a/jme3-lwjgl3/build.gradle b/jme3-lwjgl3/build.gradle new file mode 100644 index 000000000..c9b43e0de --- /dev/null +++ b/jme3-lwjgl3/build.gradle @@ -0,0 +1,12 @@ +if (!hasProperty('mainClass')) { + ext.mainClass = '' +} + +dependencies { + compile project(':jme3-core') + compile project(':jme3-desktop') + compile 'org.lwjgl:lwjgl:3.0.0b-SNAPSHOT' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-windows' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-linux' + compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-osx' +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java new file mode 100644 index 000000000..313bdd5ee --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglAL.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.AL; +import com.jme3.system.NativeLibraryLoader; +import com.jme3.system.Platform; +import org.lwjgl.openal.AL10; +import org.lwjgl.openal.AL11; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public final class LwjglAL implements AL { + + public LwjglAL() { + } + + public String alGetString(int parameter) { + return AL10.alGetString(parameter); + } + + public int alGenSources() { + return AL10.alGenSources(); + } + + public int alGetError() { + return AL10.alGetError(); + } + + public void alDeleteSources(int numSources, IntBuffer sources) { + if (sources.position() != 0) throw new AssertionError(); + if (sources.limit() != numSources) throw new AssertionError(); + AL10.alDeleteSources(sources); + } + + public void alGenBuffers(int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alGenBuffers(buffers); + } + + public void alDeleteBuffers(int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alDeleteBuffers(buffers); + } + + public void alSourceStop(int source) { + AL10.alSourceStop(source); + } + + public void alSourcei(int source, int param, int value) { + AL10.alSourcei(source, param, value); + } + + public void alBufferData(int buffer, int format, ByteBuffer data, int size, int frequency) { + if (data.position() != 0) throw new AssertionError(); + if (data.limit() != size) throw new AssertionError(); + AL10.alBufferData(buffer, format, data, frequency); + } + + public void alSourcePlay(int source) { + AL10.alSourcePlay(source); + } + + public void alSourcePause(int source) { + AL10.alSourcePause(source); + } + + public void alSourcef(int source, int param, float value) { + AL10.alSourcef(source, param, value); + } + + public void alSource3f(int source, int param, float value1, float value2, float value3) { + AL10.alSource3f(source, param, value1, value2, value3); + } + + public int alGetSourcei(int source, int param) { + return AL10.alGetSourcei(source, param); + } + + public void alSourceUnqueueBuffers(int source, int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alSourceUnqueueBuffers(source, buffers); + } + + public void alSourceQueueBuffers(int source, int numBuffers, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numBuffers) throw new AssertionError(); + AL10.alSourceQueueBuffers(source, buffers); + } + + public void alListener(int param, FloatBuffer data) { + AL10.alListenerfv(param, data); + } + + public void alListenerf(int param, float value) { + AL10.alListenerf(param, value); + } + + public void alListener3f(int param, float value1, float value2, float value3) { + AL10.alListener3f(param, value1, value2, value3); + } + + public void alSource3i(int source, int param, int value1, int value2, int value3) { + AL11.alSource3i(source, param, value1, value2, value3); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java new file mode 100644 index 000000000..e0aed80ee --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java @@ -0,0 +1,58 @@ +package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.ALC; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALContext; + +import java.nio.IntBuffer; + +import static org.lwjgl.openal.ALC10.alcGetContextsDevice; +import static org.lwjgl.openal.ALC10.alcGetCurrentContext; + +public class LwjglALC implements ALC { + + private ALContext context; + + public void createALC() { + context = ALContext.create(); + } + + public void destroyALC() { + if (context != null) { + context.destroy(); + } + } + + public boolean isCreated() { + return context != null; + } + + public String alcGetString(final int parameter) { + final long context = alcGetCurrentContext(); + final long device = alcGetContextsDevice(context); + return ALC10.alcGetString(device, parameter); + } + + public boolean alcIsExtensionPresent(final String extension) { + final long context = alcGetCurrentContext(); + final long device = alcGetContextsDevice(context); + return ALC10.alcIsExtensionPresent(device, 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); + } + + public void alcDevicePauseSOFT() { + } + + public void alcDeviceResumeSOFT() { + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java new file mode 100644 index 000000000..2ddd09ed8 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java @@ -0,0 +1,66 @@ +package com.jme3.audio.lwjgl; + +import com.jme3.audio.openal.EFX; +import org.lwjgl.openal.EXTEfx; + +import java.nio.IntBuffer; + +public class LwjglEFX implements EFX { + + public void alGenAuxiliaryEffectSlots(int numSlots, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numSlots) throw new AssertionError(); + EXTEfx.alGenAuxiliaryEffectSlots(buffers); + } + + public void alGenEffects(int numEffects, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffects) throw new AssertionError(); + EXTEfx.alGenEffects(buffers); + } + + public void alEffecti(int effect, int param, int value) { + EXTEfx.alEffecti(effect, param, value); + } + + public void alAuxiliaryEffectSloti(int effectSlot, int param, int value) { + EXTEfx.alAuxiliaryEffectSloti(effectSlot, param, value); + } + + public void alDeleteEffects(int numEffects, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffects) throw new AssertionError(); + EXTEfx.alDeleteEffects(buffers); + } + + public void alDeleteAuxiliaryEffectSlots(int numEffectSlots, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numEffectSlots) throw new AssertionError(); + EXTEfx.alDeleteAuxiliaryEffectSlots(buffers); + } + + public void alGenFilters(int numFilters, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numFilters) throw new AssertionError(); + EXTEfx.alGenFilters(buffers); + } + + public void alFilteri(int filter, int param, int value) { + EXTEfx.alFilteri(filter, param, value); + } + + public void alFilterf(int filter, int param, float value) { + EXTEfx.alFilterf(filter, param, value); + } + + public void alDeleteFilters(int numFilters, IntBuffer buffers) { + if (buffers.position() != 0) throw new AssertionError(); + if (buffers.limit() != numFilters) throw new AssertionError(); + EXTEfx.alDeleteFilters(buffers); + } + + public void alEffectf(int effect, int param, float value) { + EXTEfx.alEffectf(effect, param, value); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java new file mode 100644 index 000000000..f17c08534 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input.lwjgl; + +import com.jme3.input.*; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +/** + * @author Daniel Johansson (dannyjo) + * @since 3.1 + */ +public class GlfwJoystickInput implements JoyInput { + + private static final Logger LOGGER = Logger.getLogger(InputManager.class.getName()); + + private boolean initialized = false; + private RawInputListener listener; + private Map joysticks = new HashMap(); + + public void setJoyRumble(int joyId, float amount) { + if (joyId >= joysticks.size()) { + throw new IllegalArgumentException(); + } + } + + @Override + public Joystick[] loadJoysticks(final InputManager inputManager) { + // TODO: Implement + + for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) { + if (glfwJoystickPresent(i) == GL11.GL_TRUE) { + final String name = glfwGetJoystickName(i); + final GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name); + joysticks.put(i, joystick); + + final FloatBuffer floatBuffer = glfwGetJoystickAxes(i); + + int axisIndex = 0; + while (floatBuffer.hasRemaining()) { + floatBuffer.get(); + + final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), convertAxisIndex(axisIndex)); + final JoystickAxis joystickAxis = new DefaultJoystickAxis(inputManager, joystick, axisIndex, convertAxisIndex(axisIndex), logicalId, true, false, 0.0f); + joystick.addAxis(axisIndex, joystickAxis); + axisIndex++; + } + + final ByteBuffer byteBuffer = glfwGetJoystickButtons(i); + + int buttonIndex = 0; + while (byteBuffer.hasRemaining()) { + byteBuffer.get(); + final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), String.valueOf(buttonIndex)); + joystick.addButton(new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId)); + buttonIndex++; + } + } + } + + return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]); + } + + private String convertAxisIndex(final int index) { + if (index == 0) { + return "pov_x"; + } else if (index == 1) { + return "pov_y"; + } else if (index == 2) { + return "z"; + } else if (index == 3) { + return "rz"; + } + + return String.valueOf(index); + } + + public void initialize() { + initialized = true; + } + + public void update() { + for (final Map.Entry entry : joysticks.entrySet()) { + // Axes + final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey()); + + for (final JoystickAxis axis : entry.getValue().getAxes()) { + final float value = axisValues.get(axis.getAxisId()); + listener.onJoyAxisEvent(new JoyAxisEvent(axis, value)); + } + + // Buttons + final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey()); + + for (final JoystickButton button : entry.getValue().getButtons()) { + final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS; + listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed)); + } + } + } + + public void destroy() { + initialized = false; + } + + public boolean isInitialized() { + return initialized; + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return 0; + } + + protected class GlfwJoystick extends AbstractJoystick { + + private JoystickAxis povAxisX; + private JoystickAxis povAxisY; + + public GlfwJoystick(InputManager inputManager, JoyInput joyInput, int joyId, String name) { + super(inputManager, joyInput, joyId, name); + } + + public void addAxis(final int index, final JoystickAxis axis) { + super.addAxis(axis); + + if (index == 0) { + povAxisX = axis; + } else if (index == 1) { + povAxisY = axis; + } + } + + @Override + protected void addButton(JoystickButton button) { + super.addButton(button); + } + + @Override + public JoystickAxis getXAxis() { + return povAxisX; + } + + @Override + public JoystickAxis getYAxis() { + return povAxisY; + } + + @Override + public JoystickAxis getPovXAxis() { + return povAxisX; + } + + @Override + public JoystickAxis getPovYAxis() { + return povAxisY; + } + + @Override + public int getXAxisIndex() { + return povAxisX.getAxisId(); + } + + @Override + public int getYAxisIndex() { + return povAxisY.getAxisId(); + } + } +} + + + diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java new file mode 100644 index 000000000..a39010c95 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.lwjgl; + +import com.jme3.input.KeyInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.system.lwjgl.LwjglTimer; +import com.jme3.system.lwjgl.LwjglWindow; +import org.lwjgl.glfw.GLFWKeyCallback; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +public class LwjglKeyInput implements KeyInput { + + private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName()); + + private LwjglWindow context; + private RawInputListener listener; + private boolean initialized; + private GLFWKeyCallback keyCallback; + private Queue keyInputEvents = new LinkedList(); + + public LwjglKeyInput(LwjglWindow context) { + this.context = context; + } + + public void initialize() { + if (!context.isRenderable()) { + return; + } + + 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); + evt.setTime(getInputTimeNanos()); + keyInputEvents.add(evt); + } + }); + + glfwSetInputMode(context.getWindowHandle(), GLFW_STICKY_KEYS, 1); + + initialized = true; + logger.fine("Keyboard created."); + } + + public int getKeyCount() { + return 0; // TODO: How do we figure this out? + } + + public void update() { + if (!context.isRenderable()) { + return; + } + + while (!keyInputEvents.isEmpty()) { + listener.onKeyEvent(keyInputEvents.poll()); + } + } + + public void destroy() { + if (!context.isRenderable()) { + return; + } + + keyCallback.release(); + logger.fine("Keyboard destroyed."); + } + + public boolean isInitialized() { + return initialized; + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java new file mode 100644 index 000000000..45262ffbc --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.lwjgl; + +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.MouseInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.system.lwjgl.LwjglTimer; +import com.jme3.system.lwjgl.LwjglWindow; +import org.lwjgl.glfw.GLFWCursorPosCallback; +import org.lwjgl.glfw.GLFWMouseButtonCallback; +import org.lwjgl.glfw.GLFWScrollCallback; + +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; + +public class LwjglMouseInput implements MouseInput { + + private static final Logger logger = Logger.getLogger(LwjglMouseInput.class.getName()); + + private LwjglWindow context; + private RawInputListener listener; + private boolean cursorVisible = true; + private int mouseX; + private int mouseY; + private int mouseWheel; + private boolean initialized; + private GLFWCursorPosCallback cursorPosCallback; + private GLFWScrollCallback scrollCallback; + private GLFWMouseButtonCallback mouseButtonCallback; + private Queue mouseMotionEvents = new LinkedList(); + private Queue mouseButtonEvents = new LinkedList(); + + public LwjglMouseInput(LwjglWindow context) { + this.context = context; + } + + 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 = (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 * -1, xDelta, yDelta * -1, mouseWheel, 0); + mouseMotionEvent.setTime(getInputTimeNanos()); + mouseMotionEvents.add(mouseMotionEvent); + } + } + }); + + 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); + } + }); + + 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(button, action == GLFW_PRESS, mouseX, mouseY); + mouseButtonEvent.setTime(getInputTimeNanos()); + mouseButtonEvents.add(mouseButtonEvent); + } + }); + + setCursorVisible(cursorVisible); + logger.fine("Mouse created."); + initialized = true; + } + + public boolean isInitialized() { + return initialized; + } + + public int getButtonCount() { + return 2; // TODO: How to determine this? + } + + public void update() { + while (!mouseMotionEvents.isEmpty()) { + listener.onMouseMotionEvent(mouseMotionEvents.poll()); + } + + while (!mouseButtonEvents.isEmpty()) { + listener.onMouseButtonEvent(mouseButtonEvents.poll()); + } + } + + public void destroy() { + if (!context.isRenderable()) { + return; + } + + cursorPosCallback.release(); + scrollCallback.release(); + mouseButtonCallback.release(); + + logger.fine("Mouse destroyed."); + } + + public void setCursorVisible(boolean visible) { + cursorVisible = visible; + + if (!context.isRenderable()) { + return; + } + + if (cursorVisible) { + glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } else { + glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public long getInputTimeNanos() { + return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + } + + public void setNativeCursor(final 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); + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java new file mode 100644 index 000000000..80e7f3513 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -0,0 +1,458 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GL2; +import com.jme3.renderer.opengl.GL3; +import com.jme3.renderer.opengl.GL4; +import com.jme3.system.NativeLibraryLoader; +import com.jme3.system.Platform; +import org.lwjgl.opengl.*; + +import java.nio.*; + +public class LwjglGL implements GL, GL2, GL3, GL4 { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + public void resetStats() { + } + + public void glActiveTexture(int param1) { + GL13.glActiveTexture(param1); + } + + public void glAlphaFunc(int param1, float param2) { + GL11.glAlphaFunc(param1, param2); + } + + public void glAttachShader(int param1, int param2) { + GL20.glAttachShader(param1, param2); + } + + public void glBindBuffer(int param1, int param2) { + GL15.glBindBuffer(param1, param2); + } + + public void glBindTexture(int param1, int param2) { + GL11.glBindTexture(param1, param2); + } + + public void glBlendFunc(int param1, int param2) { + GL11.glBlendFunc(param1, param2); + } + + public void glBufferData(int param1, long param2, int param3) { + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, FloatBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, ShortBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferData(int param1, ByteBuffer param2, int param3) { + checkLimit(param2); + GL15.glBufferData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, FloatBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, ShortBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glBufferSubData(int param1, long param2, ByteBuffer param3) { + checkLimit(param3); + GL15.glBufferSubData(param1, param2, param3); + } + + public void glClear(int param1) { + GL11.glClear(param1); + } + + public void glClearColor(float param1, float param2, float param3, float param4) { + GL11.glClearColor(param1, param2, param3, param4); + } + + public void glColorMask(boolean param1, boolean param2, boolean param3, boolean param4) { + GL11.glColorMask(param1, param2, param3, param4); + } + + public void glCompileShader(int param1) { + GL20.glCompileShader(param1); + } + + public void glCompressedTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { + checkLimit(param7); + GL13.glCompressedTexImage2D(param1, param2, param3, param4, param5, param6, param7); + } + + public void glCompressedTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { + checkLimit(param8); + GL13.glCompressedTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8); + } + + public void glCompressedTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { + checkLimit(param8); + GL13.glCompressedTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8); + } + + public void glCompressedTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { + checkLimit(param10); + GL13.glCompressedTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); + } + + public int glCreateProgram() { + return GL20.glCreateProgram(); + } + + public int glCreateShader(int param1) { + return GL20.glCreateShader(param1); + } + + public void glCullFace(int param1) { + GL11.glCullFace(param1); + } + + public void glDeleteBuffers(IntBuffer param1) { + checkLimit(param1); + GL15.glDeleteBuffers(param1); + } + + public void glDeleteProgram(int param1) { + GL20.glDeleteProgram(param1); + } + + public void glDeleteShader(int param1) { + GL20.glDeleteShader(param1); + } + + public void glDeleteTextures(IntBuffer param1) { + checkLimit(param1); + GL11.glDeleteTextures(param1); + } + + public void glDepthFunc(int param1) { + GL11.glDepthFunc(param1); + } + + public void glDepthMask(boolean param1) { + GL11.glDepthMask(param1); + } + + public void glDepthRange(double param1, double param2) { + GL11.glDepthRange(param1, param2); + } + + public void glDetachShader(int param1, int param2) { + GL20.glDetachShader(param1, param2); + } + + public void glDisable(int param1) { + GL11.glDisable(param1); + } + + public void glDisableVertexAttribArray(int param1) { + GL20.glDisableVertexAttribArray(param1); + } + + public void glDrawArrays(int param1, int param2, int param3) { + GL11.glDrawArrays(param1, param2, param3); + } + + public void glDrawBuffer(int param1) { + GL11.glDrawBuffer(param1); + } + + public void glDrawRangeElements(int param1, int param2, int param3, int param4, int param5, long param6) { + GL12.glDrawRangeElements(param1, param2, param3, param4, param5, param6); + } + + public void glEnable(int param1) { + GL11.glEnable(param1); + } + + public void glEnableVertexAttribArray(int param1) { + GL20.glEnableVertexAttribArray(param1); + } + + public void glGenBuffers(IntBuffer param1) { + checkLimit(param1); + GL15.glGenBuffers(param1); + } + + public void glGenTextures(IntBuffer param1) { + checkLimit(param1); + GL11.glGenTextures(param1); + } + + public void glGetBoolean(int param1, ByteBuffer param2) { + checkLimit(param2); + GL11.glGetBooleanv(param1, param2); + } + + public void glGetBufferSubData(int target, long offset, ByteBuffer data) { + checkLimit(data); + GL15.glGetBufferSubData(target, offset, data); + } + + public int glGetError() { + return GL11.glGetError(); + } + + public void glGetInteger(int param1, IntBuffer param2) { + checkLimit(param2); + GL11.glGetIntegerv(param1, param2); + } + + public void glGetProgram(int param1, int param2, IntBuffer param3) { + checkLimit(param3); + GL20.glGetProgramiv(param1, param2, param3); + } + + public void glGetShader(int param1, int param2, IntBuffer param3) { + checkLimit(param3); + GL20.glGetShaderiv(param1, param2, param3); + } + + public String glGetString(int param1) { + return GL11.glGetString(param1); + } + + public String glGetString(int param1, int param2) { + return GL30.glGetStringi(param1, param2); + } + + public boolean glIsEnabled(int param1) { + return GL11.glIsEnabled(param1); + } + + public void glLineWidth(float param1) { + GL11.glLineWidth(param1); + } + + public void glLinkProgram(int param1) { + GL20.glLinkProgram(param1); + } + + public void glPixelStorei(int param1, int param2) { + GL11.glPixelStorei(param1, param2); + } + + public void glPointSize(float param1) { + GL11.glPointSize(param1); + } + + public void glPolygonMode(int param1, int param2) { + GL11.glPolygonMode(param1, param2); + } + + public void glPolygonOffset(float param1, float param2) { + GL11.glPolygonOffset(param1, param2); + } + + public void glReadBuffer(int param1) { + GL11.glReadBuffer(param1); + } + + public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { + checkLimit(param7); + GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); + } + + public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, long param7) { + GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); + } + + public void glScissor(int param1, int param2, int param3, int param4) { + GL11.glScissor(param1, param2, param3, param4); + } + + public void glStencilFuncSeparate(int param1, int param2, int param3, int param4) { + GL20.glStencilFuncSeparate(param1, param2, param3, param4); + } + + public void glStencilOpSeparate(int param1, int param2, int param3, int param4) { + GL20.glStencilOpSeparate(param1, param2, param3, param4); + } + + public void glTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { + checkLimit(param9); + GL11.glTexImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + public void glTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { + checkLimit(param10); + GL12.glTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); + } + + public void glTexParameterf(int param1, int param2, float param3) { + GL11.glTexParameterf(param1, param2, param3); + } + + public void glTexParameteri(int param1, int param2, int param3) { + GL11.glTexParameteri(param1, param2, param3); + } + + public void glTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { + checkLimit(param9); + GL11.glTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); + } + + public void glTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10, ByteBuffer param11) { + checkLimit(param11); + GL12.glTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11); + } + + public void glUniform1(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform1fv(param1, param2); + } + + public void glUniform1(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform1iv(param1, param2); + } + + public void glUniform1f(int param1, float param2) { + GL20.glUniform1f(param1, param2); + } + + public void glUniform1i(int param1, int param2) { + GL20.glUniform1i(param1, param2); + } + + public void glUniform2(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform2iv(param1, param2); + } + + public void glUniform2(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform2fv(param1, param2); + } + + public void glUniform2f(int param1, float param2, float param3) { + GL20.glUniform2f(param1, param2, param3); + } + + public void glUniform3(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform3iv(param1, param2); + } + + public void glUniform3(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform3fv(param1, param2); + } + + public void glUniform3f(int param1, float param2, float param3, float param4) { + GL20.glUniform3f(param1, param2, param3, param4); + } + + public void glUniform4(int param1, FloatBuffer param2) { + checkLimit(param2); + GL20.glUniform4fv(param1, param2); + } + + public void glUniform4(int param1, IntBuffer param2) { + checkLimit(param2); + GL20.glUniform4iv(param1, param2); + } + + public void glUniform4f(int param1, float param2, float param3, float param4, float param5) { + GL20.glUniform4f(param1, param2, param3, param4, param5); + } + + public void glUniformMatrix3(int param1, boolean param2, FloatBuffer param3) { + checkLimit(param3); + GL20.glUniformMatrix3fv(param1, param2, param3); + } + + public void glUniformMatrix4(int param1, boolean param2, FloatBuffer param3) { + checkLimit(param3); + GL20.glUniformMatrix4fv(param1, param2, param3); + } + + public void glUseProgram(int param1) { + GL20.glUseProgram(param1); + } + + public void glVertexAttribPointer(int param1, int param2, int param3, boolean param4, int param5, long param6) { + GL20.glVertexAttribPointer(param1, param2, param3, param4, param5, param6); + } + + public void glViewport(int param1, int param2, int param3, int param4) { + GL11.glViewport(param1, param2, param3, param4); + } + + public int glGetAttribLocation(int param1, String param2) { + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetAttribLocation(param1, param2 + "\0"); + } + + public int glGetUniformLocation(int param1, String param2) { + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetUniformLocation(param1, param2 + "\0"); + } + + public void glShaderSource(int param1, String[] param2, IntBuffer param3) { + checkLimit(param3); + GL20.glShaderSource(param1, param2); + } + + public String glGetProgramInfoLog(int program, int maxSize) { + return GL20.glGetProgramInfoLog(program, maxSize); + } + + public String glGetShaderInfoLog(int shader, int maxSize) { + return GL20.glGetShaderInfoLog(shader, maxSize); + } + + @Override + public void glBindFragDataLocation(int param1, int param2, String param3) { + GL30.glBindFragDataLocation(param1, param2, param3); + } + + @Override + public void glBindVertexArray(int param1) { + GL30.glBindVertexArray(param1); + } + + @Override + public void glGenVertexArrays(IntBuffer param1) { + checkLimit(param1); + GL30.glGenVertexArrays(param1); + } + + @Override + public void glPatchParameter(int count) { + GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES,count); + } + + @Override + public void glDeleteVertexArrays(IntBuffer arrays) { + checkLimit(arrays); + ARBVertexArrayObject.glDeleteVertexArrays(arrays); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java new file mode 100644 index 000000000..00b3f688c --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java @@ -0,0 +1,83 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLExt; +import org.lwjgl.opengl.*; + +import java.nio.Buffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public class LwjglGLExt implements GLExt { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBufferData(int target, IntBuffer data, int usage) { + checkLimit(data); + GL15.glBufferData(target, data, usage); + } + + @Override + public void glBufferSubData(int target, long offset, IntBuffer data) { + checkLimit(data); + GL15.glBufferSubData(target, offset, data); + } + + @Override + public void glDrawArraysInstancedARB(int mode, int first, int count, int primcount) { + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); + } + + @Override + public void glDrawBuffers(IntBuffer bufs) { + checkLimit(bufs); + GL20.glDrawBuffers(bufs); + } + + @Override + public void glDrawElementsInstancedARB(int mode, int indices_count, int type, long indices_buffer_offset, int primcount) { + ARBDrawInstanced.glDrawElementsInstancedARB(mode, indices_count, type, indices_buffer_offset, primcount); + } + + @Override + public void glGetMultisample(int pname, int index, FloatBuffer val) { + checkLimit(val); + ARBTextureMultisample.glGetMultisamplefv(pname, index, val); + } + + @Override + public void glTexImage2DMultisample(int target, int samples, int internalformat, int width, int height, boolean fixedsamplelocations) { + ARBTextureMultisample.glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); + } + + @Override + public void glVertexAttribDivisorARB(int index, int divisor) { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } + + @Override + public Object glFenceSync(int condition, int flags) { + return ARBSync.glFenceSync(condition, flags); + } + + @Override + public int glClientWaitSync(final Object sync, final int flags, final long timeout) { + return ARBSync.glClientWaitSync((Long) sync, flags, timeout); + } + + @Override + public void glDeleteSync(final Object sync) { + ARBSync.glDeleteSync((Long) sync); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java new file mode 100644 index 000000000..969d7ae1d --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java @@ -0,0 +1,99 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLFbo; +import org.lwjgl.opengl.EXTFramebufferBlit; +import org.lwjgl.opengl.EXTFramebufferMultisample; +import org.lwjgl.opengl.EXTFramebufferObject; + +import java.nio.Buffer; +import java.nio.IntBuffer; + +/** + * Implements GLFbo via GL_EXT_framebuffer_object. + * + * @author Kirill Vainer + */ +public class LwjglGLFboEXT implements GLFbo { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + EXTFramebufferBlit.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + + @Override + public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { + EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height); + } + + @Override + public void glBindFramebufferEXT(int param1, int param2) { + EXTFramebufferObject.glBindFramebufferEXT(param1, param2); + } + + @Override + public void glBindRenderbufferEXT(int param1, int param2) { + EXTFramebufferObject.glBindRenderbufferEXT(param1, param2); + } + + @Override + public int glCheckFramebufferStatusEXT(int param1) { + return EXTFramebufferObject.glCheckFramebufferStatusEXT(param1); + } + + @Override + public void glDeleteFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glDeleteFramebuffersEXT(param1); + } + + @Override + public void glDeleteRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glDeleteRenderbuffersEXT(param1); + } + + @Override + public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { + EXTFramebufferObject.glFramebufferRenderbufferEXT(param1, param2, param3, param4); + } + + @Override + public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { + EXTFramebufferObject.glFramebufferTexture2DEXT(param1, param2, param3, param4, param5); + } + + @Override + public void glGenFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glGenFramebuffersEXT(param1); + } + + @Override + public void glGenRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + EXTFramebufferObject.glGenRenderbuffersEXT(param1); + } + + @Override + public void glGenerateMipmapEXT(int param1) { + EXTFramebufferObject.glGenerateMipmapEXT(param1); + } + + @Override + public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { + EXTFramebufferObject.glRenderbufferStorageEXT(param1, param2, param3, param4); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java new file mode 100644 index 000000000..aa15aeb09 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java @@ -0,0 +1,97 @@ +package com.jme3.renderer.lwjgl; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.opengl.GLFbo; +import org.lwjgl.opengl.GL30; + +import java.nio.Buffer; +import java.nio.IntBuffer; + +/** + * Implements GLFbo via OpenGL3+. + * + * @author Kirill Vainer + */ +public class LwjglGLFboGL3 implements GLFbo { + + private static void checkLimit(Buffer buffer) { + if (buffer == null) { + return; + } + if (buffer.limit() == 0) { + throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); + } + if (buffer.remaining() == 0) { + throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); + } + } + + @Override + public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + + @Override + public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { + GL30.glRenderbufferStorageMultisample(target, samples, internalformat, width, height); + } + + @Override + public void glBindFramebufferEXT(int param1, int param2) { + GL30.glBindFramebuffer(param1, param2); + } + + @Override + public void glBindRenderbufferEXT(int param1, int param2) { + GL30.glBindRenderbuffer(param1, param2); + } + + @Override + public int glCheckFramebufferStatusEXT(int param1) { + return GL30.glCheckFramebufferStatus(param1); + } + + @Override + public void glDeleteFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glDeleteFramebuffers(param1); + } + + @Override + public void glDeleteRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glDeleteRenderbuffers(param1); + } + + @Override + public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { + GL30.glFramebufferRenderbuffer(param1, param2, param3, param4); + } + + @Override + public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { + GL30.glFramebufferTexture2D(param1, param2, param3, param4, param5); + } + + @Override + public void glGenFramebuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glGenFramebuffers(param1); + } + + @Override + public void glGenRenderbuffersEXT(IntBuffer param1) { + checkLimit(param1); + GL30.glGenRenderbuffers(param1); + } + + @Override + public void glGenerateMipmapEXT(int param1) { + GL30.glGenerateMipmap(param1); + } + + @Override + public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { + GL30.glRenderbufferStorage(param1, param2, param3, param4); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java new file mode 100644 index 000000000..1f1ef2ab5 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; + +import javax.swing.*; +import java.awt.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; + +public class LwjglCanvas extends LwjglWindow implements JmeCanvasContext { + + protected static final int TASK_NOTHING = 0, + TASK_DESTROY_DISPLAY = 1, + TASK_CREATE_DISPLAY = 2, + TASK_COMPLETE = 3; + +// protected static final boolean USE_SHARED_CONTEXT = +// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true")); + + protected static final boolean USE_SHARED_CONTEXT = false; + + private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName()); + private Canvas canvas; + private int width; + private int height; + + private final Object taskLock = new Object(); + private int desiredTask = TASK_NOTHING; + + private Thread renderThread; + private boolean runningFirstTime = true; + private boolean mouseWasGrabbed = false; + + private boolean mouseWasCreated = false; + private boolean keyboardWasCreated = false; + + private long window; + + private class GLCanvas extends Canvas { + @Override + public void addNotify(){ + super.addNotify(); + + if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED) { + return; // already destroyed. + } + + if (renderThread == null){ + logger.log(Level.FINE, "EDT: Creating OGL thread."); + + // Also set some settings on the canvas here. + // So we don't do it outside the AWT thread. + canvas.setFocusable(true); + canvas.setIgnoreRepaint(true); + + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); + renderThread.start(); + }else if (needClose.get()){ + return; + } + + logger.log(Level.FINE, "EDT: Telling OGL to create display .."); + synchronized (taskLock){ + desiredTask = TASK_CREATE_DISPLAY; +// while (desiredTask != TASK_COMPLETE){ +// try { +// taskLock.wait(); +// } catch (InterruptedException ex) { +// return; +// } +// } +// desiredTask = TASK_NOTHING; + } +// logger.log(Level.FINE, "EDT: OGL has created the display"); + } + + @Override + public void removeNotify(){ + if (needClose.get()){ + logger.log(Level.FINE, "EDT: Application is stopped. Not restoring canvas."); + super.removeNotify(); + return; + } + + // We must tell GL context to shutdown and wait for it to + // shutdown, otherwise, issues will occur. + logger.log(Level.FINE, "EDT: Telling OGL to destroy display .."); + synchronized (taskLock){ + desiredTask = TASK_DESTROY_DISPLAY; + while (desiredTask != TASK_COMPLETE){ + try { + taskLock.wait(); + } catch (InterruptedException ex){ + super.removeNotify(); + return; + } + } + desiredTask = TASK_NOTHING; + } + + logger.log(Level.FINE, "EDT: Acknowledged receipt of canvas death"); + // GL context is dead at this point + + super.removeNotify(); + } + } + + public LwjglCanvas(){ + super(Type.Canvas); + canvas = new GLCanvas(); + } + + public void create(boolean waitFor){ + if (renderThread == null){ + logger.log(Level.FINE, "MAIN: Creating OGL thread."); + + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); + renderThread.start(); + } + // do not do anything. + // superclass's create() will be called at initInThread() + if (waitFor) { + waitFor(true); + } + } + + public Canvas getCanvas(){ + return canvas; + } + + @Override + protected void runLoop(){ + if (desiredTask != TASK_NOTHING){ + synchronized (taskLock){ + switch (desiredTask){ + case TASK_CREATE_DISPLAY: + logger.log(Level.FINE, "OGL: Creating display .."); + restoreCanvas(); + listener.gainFocus(); + desiredTask = TASK_NOTHING; + break; + case TASK_DESTROY_DISPLAY: + logger.log(Level.FINE, "OGL: Destroying display .."); + listener.loseFocus(); + pauseCanvas(); + break; + } + desiredTask = TASK_COMPLETE; + taskLock.notifyAll(); + } + } + + if (renderable.get()){ + int newWidth = Math.max(canvas.getWidth(), 1); + int newHeight = Math.max(canvas.getHeight(), 1); + + if (width != newWidth || height != newHeight){ + width = newWidth; + height = newHeight; + if (listener != null){ + listener.reshape(width, height); + } + } + } + + super.runLoop(); + } + + private void pauseCanvas(){ + if (mouseInput != null) { + mouseInput.setCursorVisible(true); + mouseWasCreated = true; + } + +/* + if (Mouse.isCreated()){ + if (Mouse.isGrabbed()){ + Mouse.setGrabbed(false); + mouseWasGrabbed = true; + } + mouseWasCreated = true; + Mouse.destroy(); + } + if (Keyboard.isCreated()){ + keyboardWasCreated = true; + Keyboard.destroy(); + } +*/ + + renderable.set(false); + destroyContext(); + } + + /** + * Called to restore the canvas. + */ + private void restoreCanvas(){ + logger.log(Level.FINE, "OGL: Waiting for canvas to become displayable.."); + while (!canvas.isDisplayable()){ + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "OGL: Interrupted! ", ex); + } + } + + logger.log(Level.FINE, "OGL: Creating display context .."); + + // Set renderable to true, since canvas is now displayable. + renderable.set(true); + createContext(settings); + + logger.log(Level.FINE, "OGL: Display is active!"); + + try { + if (mouseWasCreated){ +// Mouse.create(); +// if (mouseWasGrabbed){ +// Mouse.setGrabbed(true); +// mouseWasGrabbed = false; +// } + } + if (keyboardWasCreated){ +// Keyboard.create(); +// keyboardWasCreated = false; + } + } catch (Exception ex){ + logger.log(Level.SEVERE, "Encountered exception when restoring input", ex); + } + + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + canvas.requestFocus(); + } + }); + } + +/* + */ +/** + * Makes sure the pbuffer is available and ready for use + *//* + + protected void makePbufferAvailable() throws LWJGLException{ + if (pbuffer != null && pbuffer.isBufferLost()){ + logger.log(Level.WARNING, "PBuffer was lost!"); + pbuffer.destroy(); + pbuffer = null; + } + + if (pbuffer == null) { + pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); + pbuffer.makeCurrent(); + logger.log(Level.FINE, "OGL: Pbuffer has been created"); + + // Any created objects are no longer valid + if (!runningFirstTime){ + renderer.resetGLObjects(); + } + } + + pbuffer.makeCurrent(); + if (!pbuffer.isCurrent()){ + throw new LWJGLException("Pbuffer cannot be made current"); + } + } + + protected void destroyPbuffer(){ + if (pbuffer != null){ + if (!pbuffer.isBufferLost()){ + pbuffer.destroy(); + } + pbuffer = null; + } + } +*/ + + /** + * This is called: + * 1) When the context thread ends + * 2) Any time the canvas becomes non-displayable + */ + protected void destroyContext(){ + // invalidate the state so renderer can resume operation + if (!USE_SHARED_CONTEXT){ + renderer.cleanup(); + } + + if (window != 0) { + glfwDestroyWindow(window); + } + + // TODO: Destroy input + + + // The canvas is no longer visible, + // but the context thread is still running. + if (!needClose.get()){ + renderer.invalidateState(); + } + } + + /** + * This is called: + * 1) When the context thread starts + * 2) Any time the canvas becomes displayable again. + */ + @Override + protected void createContext(final AppSettings settings) { + // In case canvas is not visible, we still take framerate + // from settings to prevent "100% CPU usage" + allowSwapBuffers = settings.isSwapBuffers(); + + if (renderable.get()){ + if (!runningFirstTime){ + // because the display is a different opengl context + // must reset the context state. + if (!USE_SHARED_CONTEXT){ + renderer.cleanup(); + } + } + + super.createContext(settings); + } + + // At this point, the OpenGL context is active. + if (runningFirstTime) { + // THIS is the part that creates the renderer. + // It must always be called, now that we have the pbuffer workaround. + initContextFirstTime(); + runningFirstTime = false; + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java new file mode 100644 index 000000000..3f6491e5f --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.input.lwjgl.GlfwJoystickInput; +import com.jme3.input.lwjgl.LwjglKeyInput; +import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.RendererException; +import com.jme3.renderer.lwjgl.LwjglGL; +import com.jme3.renderer.lwjgl.LwjglGLExt; +import com.jme3.renderer.lwjgl.LwjglGLFboEXT; +import com.jme3.renderer.lwjgl.LwjglGLFboGL3; +import com.jme3.renderer.opengl.*; +import com.jme3.renderer.opengl.GL; +import com.jme3.system.*; +import org.lwjgl.Sys; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.*; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.opengl.GL.createCapabilities; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.opengl.GL11.glGetInteger; + +/** + * A LWJGL implementation of a graphics context. + */ +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(); + + protected AppSettings settings = new AppSettings(true); + protected Renderer renderer; + protected LwjglKeyInput keyInput; + protected LwjglMouseInput mouseInput; + protected GlfwJoystickInput joyInput; + protected Timer timer; + protected 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: GLFW {2}", + new Object[]{Sys.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) { + return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES); + } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) { + return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT); + } + + return Integer.MAX_VALUE; + } + + protected void registerNatives() { + // LWJGL + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl32.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl32.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl.so"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/jemalloc32.dll"); + NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/jemalloc.dll"); + + // OpenAL + // For OSX: Need to add lib prefix when extracting + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL.dll"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal32.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal.so"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + } + + protected void loadNatives() { + if (JmeSystem.isLowPermissions()) { + return; + } + if ("LWJGL".equals(settings.getAudioRenderer())) { + NativeLibraryLoader.loadNativeLibrary("openal", true); + } + if (settings.useJoysticks()) { + //NativeLibraryLoader.loadNativeLibrary("jinput", true); + //NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true); + } + if (NativeLibraryLoader.isUsingNativeBullet()) { + NativeLibraryLoader.loadNativeLibrary("bulletjme", true); + } + NativeLibraryLoader.loadNativeLibrary("lwjgl", true); + } + + protected int getNumSamplesToUse() { + int samples = 0; + if (settings.getSamples() > 1) { + samples = settings.getSamples(); + final int supportedSamples = determineMaxSamples(); + if (supportedSamples < samples) { + logger.log(Level.WARNING, + "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() { + final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)); + + if (!capabilities.OpenGL20) { + 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)) { + GL gl = new LwjglGL(); + GLExt glext = new LwjglGLExt(); + GLFbo glfbo; + + if (capabilities.OpenGL30) { + glfbo = new LwjglGLFboGL3(); + } else { + glfbo = new LwjglGLFboEXT(); + } + + 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 = (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); + 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 (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. + } + + renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); + renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); + + // Init input + if (keyInput != null) { + keyInput.initialize(); + } + + if (mouseInput != null) { + mouseInput.initialize(); + } + + if (joyInput != null) { + joyInput.initialize(); + } + + renderable.set(true); + } + + public void internalDestroy() { + renderer = null; + timer = null; + renderable.set(false); + synchronized (createdLock) { + created.set(false); + createdLock.notifyAll(); + } + } + + public void internalCreate() { + synchronized (createdLock) { + created.set(true); + createdLock.notifyAll(); + } + + //if (renderable.get()) { + initContextFirstTime(); + //} else { +// assert getType() == Type.Canvas; +// } + } + + public void create() { + create(false); + } + + public void destroy() { + destroy(false); + } + + protected void waitFor(boolean createdVal) { + synchronized (createdLock) { + while (created.get() != createdVal) { + try { + createdLock.wait(); + } catch (InterruptedException ex) { + } + } + } + } + + public boolean isCreated() { + return created.get(); + } + + public boolean isRenderable() { + return renderable.get(); + } + + public void setSettings(AppSettings settings) { + this.settings.copyFrom(settings); + } + + public AppSettings getSettings() { + return settings; + } + + public Renderer getRenderer() { + return renderer; + } + + public Timer getTimer() { + return timer; + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java new file mode 100644 index 000000000..4a13c30af --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java @@ -0,0 +1,12 @@ +package com.jme3.system.lwjgl; + +/** + * @author Daniel Johansson + * @since 2015-08-11 + */ +public class LwjglDisplay extends LwjglWindow { + + public LwjglDisplay() { + super(Type.Display); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java new file mode 100644 index 000000000..aa9c46511 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglGLDebugOutputHandler.java @@ -0,0 +1,78 @@ +/* + * 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.system.lwjgl; + +import org.lwjgl.opengl.ARBDebugOutput; +import org.lwjgl.opengl.GLDebugMessageARBCallback; + +import java.util.HashMap; + +class LwjglGLDebugOutputHandler extends GLDebugMessageARBCallback { + + private static final HashMap constMap = new HashMap(); + private static final String MESSAGE_FORMAT = + "[JME3] OpenGL debug message\r\n" + + " ID: %d\r\n" + + " Source: %s\r\n" + + " Type: %s\r\n" + + " Severity: %s\r\n" + + " Message: %s"; + + static { + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_API_ARB, "API"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_APPLICATION_ARB, "APPLICATION"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_OTHER_ARB, "OTHER"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, "SHADER_COMPILER"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_THIRD_PARTY_ARB, "THIRD_PARTY"); + constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB, "WINDOW_SYSTEM"); + + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, "DEPRECATED_BEHAVIOR"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_ERROR_ARB, "ERROR"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_OTHER_ARB, "OTHER"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PERFORMANCE_ARB, "PERFORMANCE"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PORTABILITY_ARB, "PORTABILITY"); + constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, "UNDEFINED_BEHAVIOR"); + + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB, "HIGH"); + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB, "MEDIUM"); + constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB, "LOW"); + } + + @Override + public void invoke(int source, int type, int id, int severity, int length, long message, long userParam) { + String sourceStr = constMap.get(source); + String typeStr = constMap.get(type); + String severityStr = constMap.get(severity); + + System.err.println(String.format(MESSAGE_FORMAT, id, sourceStr, typeStr, severityStr, message)); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java new file mode 100644 index 000000000..e374e1841 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java @@ -0,0 +1,14 @@ +package com.jme3.system.lwjgl; + +import com.jme3.system.JmeContext; + +/** + * @author Daniel Johansson + * @since 2015-08-11 + */ +public class LwjglOffscreenBuffer extends LwjglWindow { + + public LwjglOffscreenBuffer() { + super(JmeContext.Type.OffscreenSurface); + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java new file mode 100644 index 000000000..a7960a261 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.math.FastMath; +import com.jme3.system.Timer; +import org.lwjgl.glfw.GLFW; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Timer handles the system's time related functionality. This + * allows the calculation of the framerate. To keep the framerate calculation + * accurate, a call to update each frame is required. Timer is a + * singleton object and must be created via the getTimer method. + * + * @author Mark Powell + * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ + */ +public class LwjglSmoothingTimer extends LwjglTimer { + private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class + .getName()); + + private long lastFrameDiff; + + //frame rate parameters. + private long oldTime; + + private float lastTPF, lastFPS; + + public static int TIMER_SMOOTHNESS = 32; + + private long[] tpf; + + private int smoothIndex; + + private final static long LWJGL_TIMER_RES = 1; + private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); + private static float invTimerRezSmooth; + + public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); + + private long startTime; + + private boolean allSmooth = false; + + /** + * Constructor builds a Timer object. All values will be + * initialized to it's default values. + */ + public LwjglSmoothingTimer() { + reset(); + + //print timer resolution info + logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); + } + + public void reset() { + lastFrameDiff = 0; + lastFPS = 0; + lastTPF = 0; + + // init to -1 to indicate this is a new timer. + oldTime = -1; + //reset time + startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + + tpf = new long[TIMER_SMOOTHNESS]; + smoothIndex = TIMER_SMOOTHNESS - 1; + invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS)); + + // set tpf... -1 values will not be used for calculating the average in update() + for ( int i = tpf.length; --i >= 0; ) { + tpf[i] = -1; + } + } + + /** + * @see Timer#getResolution() + */ + public long getResolution() { + return LWJGL_TIMER_RES; + } + + /** + * getFrameRate returns the current frame rate since the last + * call to update. + * + * @return the current frame rate. + */ + public float getFrameRate() { + return lastFPS; + } + + public float getTimePerFrame() { + return lastTPF; + } + + /** + * update recalulates the frame rate based on the previous + * call to update. It is assumed that update is called each frame. + */ + public void update() { + long newTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + long oldTime = this.oldTime; + this.oldTime = newTime; + if ( oldTime == -1 ) { + // For the first frame use 60 fps. This value will not be counted in further averages. + // This is done so initialization code between creating the timer and the first + // frame is not counted as a single frame on it's own. + lastTPF = 1 / 60f; + lastFPS = 1f / lastTPF; + return; + } + + long frameDiff = newTime - oldTime; + long lastFrameDiff = this.lastFrameDiff; + if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) { + frameDiff = lastFrameDiff *100; + } + this.lastFrameDiff = frameDiff; + tpf[smoothIndex] = frameDiff; + smoothIndex--; + if ( smoothIndex < 0 ) { + smoothIndex = tpf.length - 1; + } + + lastTPF = 0.0f; + if (!allSmooth) { + int smoothCount = 0; + for ( int i = tpf.length; --i >= 0; ) { + if ( tpf[i] != -1 ) { + lastTPF += tpf[i]; + smoothCount++; + } + } + if (smoothCount == tpf.length) + allSmooth = true; + lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount ); + } else { + for ( int i = tpf.length; --i >= 0; ) { + if ( tpf[i] != -1 ) { + lastTPF += tpf[i]; + } + } + lastTPF *= invTimerRezSmooth; + } + if ( lastTPF < FastMath.FLT_EPSILON ) { + lastTPF = FastMath.FLT_EPSILON; + } + + lastFPS = 1f / lastTPF; + } + + /** + * toString returns the string representation of this timer + * in the format:
+ *
+ * jme.utility.Timer@1db699b
+ * Time: {LONG}
+ * FPS: {LONG}
+ * + * @return the string representation of this object. + */ + @Override + public String toString() { + String string = super.toString(); + string += "\nTime: " + oldTime; + string += "\nFPS: " + getFrameRate(); + return string; + } +} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java new file mode 100644 index 000000000..c4a0e5025 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.system.Timer; +import org.lwjgl.glfw.GLFW; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Timer handles the system's time related functionality. This + * allows the calculation of the framerate. To keep the framerate calculation + * accurate, a call to update each frame is required. Timer is a + * singleton object and must be created via the getTimer method. + * + * @author Mark Powell + * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ + */ +public class LwjglTimer extends Timer { + + private static final Logger logger = Logger.getLogger(LwjglTimer.class.getName()); + + //frame rate parameters. + private long oldTime; + private long startTime; + + private float lastTPF, lastFPS; + + private final static long LWJGL_TIMER_RES = 1; + private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); + public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); + + /** + * Constructor builds a Timer object. All values will be + * initialized to it's default values. + */ + public LwjglTimer() { + reset(); + logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); + } + + public void reset() { + startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); + oldTime = getTime(); + } + + @Override + public float getTimeInSeconds() { + return getTime() * INV_LWJGL_TIMER_RES; + } + + /** + * @see Timer#getTime() + */ + public long getTime() { + return ((long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS) - startTime); + } + + /** + * @see Timer#getResolution() + */ + public long getResolution() { + return LWJGL_TIMER_RES; + } + + /** + * getFrameRate returns the current frame rate since the last + * call to update. + * + * @return the current frame rate. + */ + public float getFrameRate() { + return lastFPS; + } + + public float getTimePerFrame() { + return lastTPF; + } + + /** + * update recalulates the frame rate based on the previous + * call to update. It is assumed that update is called each frame. + */ + public void update() { + long curTime = getTime(); + lastTPF = (curTime - oldTime) * (1.0f / LWJGL_TIMER_RES); + lastFPS = 1.0f / lastTPF; + oldTime = curTime; + } + + /** + * toString returns the string representation of this timer + * in the format:
+ *
+ * jme.utility.Timer@1db699b
+ * Time: {LONG}
+ * FPS: {LONG}
+ * + * @return the string representation of this object. + */ + @Override + public String toString() { + String string = super.toString(); + string += "\nTime: " + oldTime; + string += "\nFPS: " + getFrameRate(); + return string; + } +} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java new file mode 100644 index 000000000..c089bf28d --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.system.lwjgl; + +import com.jme3.input.JoyInput; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.TouchInput; +import com.jme3.input.lwjgl.GlfwJoystickInput; +import com.jme3.input.lwjgl.LwjglKeyInput; +import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext; +import com.jme3.system.JmeSystem; +import org.lwjgl.PointerBuffer; +import org.lwjgl.Sys; +import org.lwjgl.glfw.*; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.glfw.GLFW.*; +import static org.lwjgl.opengl.GL11.GL_FALSE; +import static org.lwjgl.opengl.GL11.GL_TRUE; +import static org.lwjgl.system.MemoryUtil.NULL; + +/** + * A wrapper class over the GLFW framework in LWJGL 3. + * + * @author Daniel Johansson (dannyjo) + * @since 3.1 + */ +public abstract class LwjglWindow extends LwjglContext implements Runnable { + + private static final Logger LOGGER = Logger.getLogger(LwjglWindow.class.getName()); + + protected AtomicBoolean needClose = new AtomicBoolean(false); + protected final AtomicBoolean needRestart = new AtomicBoolean(false); + protected boolean wasActive = false; + protected boolean autoFlush = true; + protected boolean allowSwapBuffers = false; + private long window = -1; + private final JmeContext.Type type; + + private GLFWErrorCallback errorCallback; + private GLFWWindowSizeCallback windowSizeCallback; + private GLFWWindowFocusCallback windowFocusCallback; + + public LwjglWindow(final JmeContext.Type type) { + if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) { + throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided"); + } + + this.type = type; + } + + /** + * @return Type.Display or Type.Canvas + */ + public JmeContext.Type getType() { + return type; + } + + /** + * Set the title if its a windowed display + * + * @param title + */ + public void setTitle(final String title) { + if (created.get() && window != -1) { + glfwSetWindowTitle(window, title); + } + } + + /** + * Restart if its a windowed or full-screen display. + */ + public void restart() { + if (created.get()) { + needRestart.set(true); + } else { + LOGGER.warning("Display is not created, cannot restart window."); + } + } + + /** + * Apply the settings, changing resolution, etc. + * + * @param settings + */ + protected void createContext(final AppSettings settings) { + glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { + @Override + public void invoke(int error, long description) { + final String message = Callbacks.errorCallbackDescriptionString(description); + listener.handleError(message, new Exception(message)); + } + }); + + if (glfwInit() != GL_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(); + } + + final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + + if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { + settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode)); + } + + window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); + + if (window == NULL) { + throw new RuntimeException("Failed to create the GLFW window"); + } + + glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE); + 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); + + int frameRateCap = settings.getFrameRate(); + + if (!autoFlush) { + frameRateCap = 20; + } + + if (frameRateCap > 0) { + glfwWindowHint(GLFW_REFRESH_RATE, frameRateCap); + } + + // Not sure how else to support bits per pixel + if (settings.getBitsPerPixel() == 24) { + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + } else if (settings.getBitsPerPixel() == 16) { + glfwWindowHint(GLFW_RED_BITS, 5); + glfwWindowHint(GLFW_GREEN_BITS, 6); + glfwWindowHint(GLFW_BLUE_BITS, 5); + } + + glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits()); + + glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { + @Override + public void invoke(final long window, final int focused) { + final boolean focus = (focused == 1); + + if (wasActive != focus) { + if (!wasActive) { + listener.gainFocus(); + timer.reset(); + } else { + listener.loseFocus(); + } + + wasActive = !wasActive; + } + + } + }); + + // Center the window + if (!settings.isFullscreen() && Type.Display.equals(type)) { + glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2); + } + + // Make the OpenGL context current + glfwMakeContextCurrent(window); + + // Enable vsync + if (settings.isVSync()) { + glfwSwapInterval(1); + } else { + glfwSwapInterval(0); + } + + + // Make the window visible + if (Type.Display.equals(type)) { + 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); + } + }); + + allowSwapBuffers = settings.isSwapBuffers(); + + // TODO: When GLFW 3.2 is released and included in LWJGL 3.x then we should hopefully be able to set the window icon. + } + + /** + * Destroy the context. + */ + protected void destroyContext() { + try { + if (renderer != null) { + renderer.cleanup(); + } + + errorCallback.release(); + windowSizeCallback.release(); + windowFocusCallback.release(); + + if (window != 0) { + glfwDestroyWindow(window); + } + //glfwTerminate(); + } catch (Exception ex) { + listener.handleError("Failed to destroy context", ex); + } + } + + public void create(boolean waitFor) { + if (created.get()) { + LOGGER.warning("create() called when display is already created!"); + return; + } + + new Thread(this, THREAD_NAME).start(); + if (waitFor) + waitFor(true); + } + + /** + * Does LWJGL display initialization in the OpenGL thread + */ + protected boolean initInThread() { + try { + if (!JmeSystem.isLowPermissions()) { + // Enable uncaught exception handler only for current thread + Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread thread, Throwable thrown) { + listener.handleError("Uncaught exception thrown in " + thread.toString(), thrown); + if (needClose.get()) { + // listener.handleError() has requested the + // context to close. Satisfy request. + deinitInThread(); + } + } + }); + } + + timer = new LwjglTimer(); + + // For canvas, this will create a pbuffer, + // allowing us to query information. + // When the canvas context becomes available, it will + // be replaced seamlessly. + createContext(settings); + printContextInitInfo(); + + created.set(true); + super.internalCreate(); + } catch (Exception ex) { + try { + if (window != -1) { + //glfwSetWindowShouldClose(window, GL_TRUE); + glfwDestroyWindow(window); + } + } catch (Exception ex2) { + LOGGER.log(Level.WARNING, null, ex2); + } + + listener.handleError("Failed to create display", ex); + return false; // if we failed to create display, do not continue + } + + listener.initialize(); + return true; + } + + /** + * execute one iteration of the render loop in the OpenGL thread + */ + protected void runLoop() { + // If a restart is required, lets recreate the context. + if (needRestart.getAndSet(false)) { + try { + createContext(settings); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); + } + + LOGGER.fine("Display restarted."); + } + + if (!created.get()) { + throw new IllegalStateException(); + } + + listener.update(); + + // All this does is call swap buffers + // If the canvas is not active, there's no need to waste time + // doing that .. + if (renderable.get()) { + // calls swap buffers, etc. + try { + if (allowSwapBuffers && autoFlush) { + glfwSwapBuffers(window); + } + } catch (Throwable ex) { + listener.handleError("Error while swapping buffers", ex); + } + } + + if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_TRUE) { + glfwPollEvents(); + } + + // Subclasses just call GLObjectManager clean up objects here + // it is safe .. for now. + if (renderer != null) { + renderer.postFrame(); + } + } + + /** + * De-initialize in the OpenGL thread. + */ + protected void deinitInThread() { + destroyContext(); + + listener.destroy(); + LOGGER.fine("Display destroyed."); + super.internalDestroy(); + } + + public void run() { + if (listener == null) { + throw new IllegalStateException("SystemListener is not set on context!" + + "Must set with JmeContext.setSystemListner()."); + } + + registerNatives(); + loadNatives(); + LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); + + if (!initInThread()) { + LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue."); + return; + } + + while (true) { + if (glfwWindowShouldClose(window) == GL_TRUE) { + listener.requestClose(false); + } + + runLoop(); + + if (needClose.get()) { + break; + } + } + + deinitInThread(); + } + + public JoyInput getJoyInput() { + if (joyInput == null) { + joyInput = new GlfwJoystickInput(); + } + return joyInput; + } + + public MouseInput getMouseInput() { + if (mouseInput == null) { + mouseInput = new LwjglMouseInput(this); + } + return mouseInput; + } + + public KeyInput getKeyInput() { + if (keyInput == null) { + keyInput = new LwjglKeyInput(this); + } + + return keyInput; + } + + public TouchInput getTouchInput() { + return null; + } + + public void setAutoFlushFrames(boolean enabled) { + this.autoFlush = enabled; + } + + public void destroy(boolean waitFor) { + needClose.set(true); + + if (waitFor) { + waitFor(false); + } + } + + public long getWindowHandle() { + return window; + } + + private ByteBuffer[] imagesToByteBuffers(Object[] images) { + ByteBuffer[] out = new ByteBuffer[images.length]; + for (int i = 0; i < images.length; i++) { + BufferedImage image = (BufferedImage) images[i]; + out[i] = imageToByteBuffer(image); + } + return out; + } + + private ByteBuffer imageToByteBuffer(BufferedImage image) { + if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { + BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE); + Graphics2D g = convertedImage.createGraphics(); + double width = image.getWidth() * (double) 1; + double height = image.getHeight() * (double) 1; + g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2), + (int) ((convertedImage.getHeight() - height) / 2), + (int) (width), (int) (height), null); + g.dispose(); + image = convertedImage; + } + + byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4]; + int counter = 0; + for (int i = 0; i < image.getHeight(); i++) { + for (int j = 0; j < image.getWidth(); j++) { + int colorSpace = image.getRGB(j, i); + imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24); + imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24); + imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24); + imageBuffer[counter + 3] = (byte) (colorSpace >> 24); + counter += 4; + } + } + return ByteBuffer.wrap(imageBuffer); + } +} diff --git a/settings.gradle b/settings.gradle index 89b8fc075..8b9000340 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,7 @@ include 'jme3-desktop' include 'jme3-blender' include 'jme3-jogl' include 'jme3-lwjgl' +include 'jme3-lwjgl3' // Other external dependencies include 'jme3-jbullet' From 971b9524bd436966f35ee8f284115dd975622c50 Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Wed, 2 Sep 2015 12:47:21 +0100 Subject: [PATCH 05/13] Fixed an issue with the GLFW mouse input coordinates not being mapped correctly. Renamed input classes to GlfwXXX. --- .../{LwjglKeyInput.java => GlfwKeyInput.java} | 6 +-- ...jglMouseInput.java => GlfwMouseInput.java} | 41 +++++++++++++++---- .../com/jme3/system/lwjgl/LwjglContext.java | 21 ++++------ .../com/jme3/system/lwjgl/LwjglWindow.java | 14 +++---- 4 files changed, 52 insertions(+), 30 deletions(-) rename jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/{LwjglKeyInput.java => GlfwKeyInput.java} (95%) rename jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/{LwjglMouseInput.java => GlfwMouseInput.java} (80%) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java similarity index 95% rename from jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java rename to jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index a39010c95..4768290d7 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglKeyInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java @@ -45,9 +45,9 @@ import java.util.logging.Logger; import static org.lwjgl.glfw.GLFW.*; -public class LwjglKeyInput implements KeyInput { +public class GlfwKeyInput implements KeyInput { - private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName()); + private static final Logger logger = Logger.getLogger(GlfwKeyInput.class.getName()); private LwjglWindow context; private RawInputListener listener; @@ -55,7 +55,7 @@ public class LwjglKeyInput implements KeyInput { private GLFWKeyCallback keyCallback; private Queue keyInputEvents = new LinkedList(); - public LwjglKeyInput(LwjglWindow context) { + public GlfwKeyInput(LwjglWindow context) { this.context = context; } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java similarity index 80% rename from jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java rename to jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java index 45262ffbc..41e76a29d 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/LwjglMouseInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java @@ -50,9 +50,17 @@ import java.util.logging.Logger; import static org.lwjgl.glfw.GLFW.*; -public class LwjglMouseInput implements MouseInput { +/** + * Captures mouse input using GLFW callbacks. It then temporarily stores these in event queues which are processed in the + * {@link #update()} method. Due to some of the GLFW button id's there is a conversion method in this class which will + * convert the GLFW left, middle and right mouse button to JME3 left, middle and right button codes. + * + * @author Daniel Johansson (dannyjo) + * @since 3.1 + */ +public class GlfwMouseInput implements MouseInput { - private static final Logger logger = Logger.getLogger(LwjglMouseInput.class.getName()); + private static final Logger logger = Logger.getLogger(GlfwMouseInput.class.getName()); private LwjglWindow context; private RawInputListener listener; @@ -67,7 +75,7 @@ public class LwjglMouseInput implements MouseInput { private Queue mouseMotionEvents = new LinkedList(); private Queue mouseButtonEvents = new LinkedList(); - public LwjglMouseInput(LwjglWindow context) { + public GlfwMouseInput(final LwjglWindow context) { this.context = context; } @@ -78,7 +86,7 @@ public class LwjglMouseInput implements MouseInput { int xDelta; int yDelta; int x = (int) Math.round(xpos); - int y = (int) Math.round(ypos); + int y = context.getSettings().getHeight() - (int) Math.round(ypos); if (mouseX == 0) { mouseX = x; @@ -94,7 +102,7 @@ public class LwjglMouseInput implements MouseInput { mouseY = y; if (xDelta != 0 || yDelta != 0) { - final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y * -1, xDelta, yDelta * -1, mouseWheel, 0); + final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y, xDelta, yDelta, mouseWheel, 0); mouseMotionEvent.setTime(getInputTimeNanos()); mouseMotionEvents.add(mouseMotionEvent); } @@ -115,7 +123,7 @@ public class LwjglMouseInput implements MouseInput { 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(button, action == GLFW_PRESS, mouseX, mouseY); + final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY); mouseButtonEvent.setTime(getInputTimeNanos()); mouseButtonEvents.add(mouseButtonEvent); } @@ -131,7 +139,7 @@ public class LwjglMouseInput implements MouseInput { } public int getButtonCount() { - return 2; // TODO: How to determine this? + return GLFW_MOUSE_BUTTON_LAST + 1; } public void update() { @@ -186,4 +194,23 @@ public class LwjglMouseInput implements MouseInput { glfwSetCursor(context.getWindowHandle(), cursor); } } + + /** + * 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. + * + * @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; + } + + return glfwButton; + } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 3f6491e5f..86b6a294a 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -33,8 +33,8 @@ package com.jme3.system.lwjgl; import com.jme3.input.lwjgl.GlfwJoystickInput; -import com.jme3.input.lwjgl.LwjglKeyInput; -import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.input.lwjgl.GlfwKeyInput; +import com.jme3.input.lwjgl.GlfwMouseInput; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; import com.jme3.renderer.lwjgl.LwjglGL; @@ -71,8 +71,8 @@ public abstract class LwjglContext implements JmeContext { protected AppSettings settings = new AppSettings(true); protected Renderer renderer; - protected LwjglKeyInput keyInput; - protected LwjglMouseInput mouseInput; + protected GlfwKeyInput keyInput; + protected GlfwMouseInput mouseInput; protected GlfwJoystickInput joyInput; protected Timer timer; protected SystemListener listener; @@ -123,16 +123,15 @@ public abstract class LwjglContext implements JmeContext { if (JmeSystem.isLowPermissions()) { return; } + if ("LWJGL".equals(settings.getAudioRenderer())) { NativeLibraryLoader.loadNativeLibrary("openal", true); } - if (settings.useJoysticks()) { - //NativeLibraryLoader.loadNativeLibrary("jinput", true); - //NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true); - } + if (NativeLibraryLoader.isUsingNativeBullet()) { NativeLibraryLoader.loadNativeLibrary("bulletjme", true); } + NativeLibraryLoader.loadNativeLibrary("lwjgl", true); } @@ -236,11 +235,7 @@ public abstract class LwjglContext implements JmeContext { createdLock.notifyAll(); } - //if (renderable.get()) { - initContextFirstTime(); - //} else { -// assert getType() == Type.Canvas; -// } + initContextFirstTime(); } public void create() { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index c089bf28d..4315618b1 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -37,12 +37,11 @@ import com.jme3.input.KeyInput; import com.jme3.input.MouseInput; import com.jme3.input.TouchInput; import com.jme3.input.lwjgl.GlfwJoystickInput; -import com.jme3.input.lwjgl.LwjglKeyInput; -import com.jme3.input.lwjgl.LwjglMouseInput; +import com.jme3.input.lwjgl.GlfwKeyInput; +import com.jme3.input.lwjgl.GlfwMouseInput; import com.jme3.system.AppSettings; import com.jme3.system.JmeContext; import com.jme3.system.JmeSystem; -import org.lwjgl.PointerBuffer; import org.lwjgl.Sys; import org.lwjgl.glfw.*; @@ -256,7 +255,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { if (window != 0) { glfwDestroyWindow(window); } - //glfwTerminate(); } catch (Exception ex) { listener.handleError("Failed to destroy context", ex); } @@ -269,8 +267,10 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } new Thread(this, THREAD_NAME).start(); - if (waitFor) + + if (waitFor) { waitFor(true); + } } /** @@ -417,14 +417,14 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { public MouseInput getMouseInput() { if (mouseInput == null) { - mouseInput = new LwjglMouseInput(this); + mouseInput = new GlfwMouseInput(this); } return mouseInput; } public KeyInput getKeyInput() { if (keyInput == null) { - keyInput = new LwjglKeyInput(this); + keyInput = new GlfwKeyInput(this); } return keyInput; From 66e0e7053c9ddd947ab63e2bd9c4ae572aedc4db Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Thu, 3 Sep 2015 13:31:25 +0100 Subject: [PATCH 06/13] Fixed an issue where GLFW would not accept window focus again due to event polling not running. --- .../main/java/com/jme3/system/lwjgl/LwjglWindow.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 4315618b1..6eac34cdc 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -188,7 +188,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { @Override public void invoke(final long window, final int focused) { - final boolean focus = (focused == 1); + final boolean focus = (focused == GL_TRUE); if (wasActive != focus) { if (!wasActive) { @@ -200,7 +200,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { wasActive = !wasActive; } - } }); @@ -219,7 +218,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { glfwSwapInterval(0); } - // Make the window visible if (Type.Display.equals(type)) { glfwShowWindow(window); @@ -356,9 +354,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } } - if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_TRUE) { - glfwPollEvents(); - } + glfwPollEvents(); // Subclasses just call GLObjectManager clean up objects here // it is safe .. for now. @@ -381,7 +377,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { public void run() { if (listener == null) { throw new IllegalStateException("SystemListener is not set on context!" - + "Must set with JmeContext.setSystemListner()."); + + "Must set with JmeContext.setSystemListener()."); } registerNatives(); From e9e4b4a1224e18aefee8793070d9872e8e2145fe Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Thu, 3 Sep 2015 13:32:06 +0100 Subject: [PATCH 07/13] Improved audio renderer information log message to include more information and to print out in a format consistent with the GL renderer information. --- .../jme3/audio/openal/ALAudioRenderer.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java index 62f04018a..0878e23fa 100644 --- a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java +++ b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java @@ -31,22 +31,20 @@ */ package com.jme3.audio.openal; -import com.jme3.audio.AudioSource.Status; import com.jme3.audio.*; +import com.jme3.audio.AudioSource.Status; import com.jme3.math.Vector3f; import com.jme3.util.BufferUtils; import com.jme3.util.NativeObjectManager; + import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import static com.jme3.audio.openal.AL.*; -import static com.jme3.audio.openal.ALC.*; -import static com.jme3.audio.openal.EFX.*; public class ALAudioRenderer implements AudioRenderer, Runnable { @@ -102,16 +100,6 @@ public class ALAudioRenderer implements AudioRenderer, Runnable { return; } - String deviceName = alc.alcGetString(ALC.ALC_DEVICE_SPECIFIER); - - logger.log(Level.INFO, "Audio Device: {0}", deviceName); - logger.log(Level.INFO, "Audio Vendor: {0}", al.alGetString(AL_VENDOR)); - logger.log(Level.INFO, "Audio Renderer: {0}", al.alGetString(AL_RENDERER)); - logger.log(Level.INFO, "Audio Version: {0}", al.alGetString(AL_VERSION)); - - logger.log(Level.INFO, "ALC extensions: {0}", alc.alcGetString(ALC.ALC_EXTENSIONS)); - logger.log(Level.INFO, "AL extensions: {0}", al.alGetString(AL_EXTENSIONS)); - // Find maximum # of sources supported by this implementation ArrayList channelList = new ArrayList(); for (int i = 0; i < MAX_NUM_CHANNELS; i++) { @@ -131,7 +119,25 @@ public class ALAudioRenderer implements AudioRenderer, Runnable { ib = BufferUtils.createIntBuffer(channels.length); chanSrcs = new AudioSource[channels.length]; - logger.log(Level.INFO, "AudioRenderer supports {0} channels", channels.length); + final String deviceName = alc.alcGetString(ALC.ALC_DEVICE_SPECIFIER); + + logger.log(Level.INFO, "Audio Renderer Information\n" + + " * Device: {0}\n" + + " * Vendor: {1}\n" + + " * Renderer: {2}\n" + + " * Version: {3}\n" + + " * Supported channels: {4}\n" + + " * ALC extensions: {5}\n" + + " * AL extensions: {6}", + new Object[]{ + deviceName, + al.alGetString(AL_VENDOR), + al.alGetString(AL_RENDERER), + al.alGetString(AL_VERSION), + channels.length, + alc.alcGetString(ALC.ALC_EXTENSIONS), + al.alGetString(AL_EXTENSIONS) + }); // Pause device is a feature used specifically on Android // where the application could be closed but still running, @@ -153,7 +159,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable { alc.alcGetInteger(EFX.ALC_MAX_AUXILIARY_SENDS, ib, 1); auxSends = ib.get(0); - logger.log(Level.INFO, "Audio max auxilary sends: {0}", auxSends); + logger.log(Level.INFO, "Audio max auxiliary sends: {0}", auxSends); // create slot ib.position(0).limit(1); From 88bf9d458014427cb15ceb80cbd75850845ab11b Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Sun, 13 Sep 2015 20:23:07 +0100 Subject: [PATCH 08/13] Reverted some changes to light classes which was not meant to be committed as part of #314. --- .../src/main/java/com/jme3/light/Light.java | 16 ----------- .../main/java/com/jme3/light/PointLight.java | 28 +++++++++---------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/light/Light.java b/jme3-core/src/main/java/com/jme3/light/Light.java index f050729c2..b1c48be7a 100644 --- a/jme3-core/src/main/java/com/jme3/light/Light.java +++ b/jme3-core/src/main/java/com/jme3/light/Light.java @@ -122,22 +122,6 @@ public abstract class Light implements Savable, Cloneable { setColor(color); } - /** - * Default constructor for Light. - */ - public Light() { - - } - - /** - * Constructor which allows setting of the color. - * - * @param color the color to apply to this light. - */ - public Light(final ColorRGBA color) { - this.color = color; - } - /** * Returns the color of the light. * diff --git a/jme3-core/src/main/java/com/jme3/light/PointLight.java b/jme3-core/src/main/java/com/jme3/light/PointLight.java index 2505a2a50..ff3b3295f 100644 --- a/jme3-core/src/main/java/com/jme3/light/PointLight.java +++ b/jme3-core/src/main/java/com/jme3/light/PointLight.java @@ -53,7 +53,7 @@ import java.io.IOException; * In addition to a position, point lights also have a radius which * can be used to attenuate the influence of the light depending on the * distance between the light and the effected object. - * + * */ public class PointLight extends Light { @@ -84,7 +84,7 @@ public class PointLight extends Light { super(color); setPosition(position); } - + /** * Creates a PointLight at the given position, with the given color and the * given radius @@ -96,7 +96,7 @@ public class PointLight extends Light { this(position, color); setRadius(radius); } - + /** * Creates a PointLight at the given position, with the given radius * @param position the position in world space @@ -119,10 +119,10 @@ public class PointLight extends Light { /** * Returns the world space position of the light. - * + * * @return the world space position of the light. - * - * @see PointLight#setPosition(com.jme3.math.Vector3f) + * + * @see PointLight#setPosition(com.jme3.math.Vector3f) */ public Vector3f getPosition() { return position; @@ -130,7 +130,7 @@ public class PointLight extends Light { /** * Set the world space position of the light. - * + * * @param position the world space position of the light. */ public final void setPosition(Vector3f position) { @@ -140,7 +140,7 @@ public class PointLight extends Light { /** * Returns the radius of the light influence. A radius of 0 means * the light has no attenuation. - * + * * @return the radius of the light */ public float getRadius() { @@ -155,9 +155,9 @@ public class PointLight extends Light { * is greater than the light's radius, then the pixel will not be * effected by this light, if the distance is less than the radius, then * the magnitude of the influence is equal to distance / radius. - * + * * @param radius the radius of the light influence. - * + * * @throws IllegalArgumentException If radius is negative */ public final void setRadius(float radius) { @@ -192,11 +192,11 @@ public class PointLight extends Light { } else { // Sphere v. box collision return FastMath.abs(box.getCenter().x - position.x) < radius + box.getXExtent() - && FastMath.abs(box.getCenter().y - position.y) < radius + box.getYExtent() - && FastMath.abs(box.getCenter().z - position.z) < radius + box.getZExtent(); + && FastMath.abs(box.getCenter().y - position.y) < radius + box.getYExtent() + && FastMath.abs(box.getCenter().z - position.z) < radius + box.getZExtent(); } } - + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { if (this.radius == 0) { @@ -210,7 +210,7 @@ public class PointLight extends Light { return true; } } - + @Override public void write(JmeExporter ex) throws IOException { super.write(ex); From b68035570d4f04cc9b070ef45376310a5ee29ddc Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Sun, 13 Sep 2015 20:26:18 +0100 Subject: [PATCH 09/13] Removed a TODO note and added key count implementation (rough for now). --- .../src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java | 2 -- .../src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java index f17c08534..b1063d6b9 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java @@ -64,8 +64,6 @@ public class GlfwJoystickInput implements JoyInput { @Override public Joystick[] loadJoysticks(final InputManager inputManager) { - // TODO: Implement - for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) { if (glfwJoystickPresent(i) == GL11.GL_TRUE) { final String name = glfwGetJoystickName(i); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index 4768290d7..5b7d8e267 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java @@ -80,7 +80,8 @@ public class GlfwKeyInput implements KeyInput { } public int getKeyCount() { - return 0; // TODO: How do we figure this out? + // This might not be correct + return GLFW_KEY_LAST - GLFW_KEY_SPACE; } public void update() { From dd6356eff1d9ea747c9f6c4d1628950d7c39e710 Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Sun, 13 Sep 2015 20:30:36 +0100 Subject: [PATCH 10/13] Reverted some more light code which should not be in this branch. --- .../src/main/java/com/jme3/light/AmbientLight.java | 6 +++--- .../main/java/com/jme3/light/DirectionalLight.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java index 101a4efc7..8dd5f9266 100644 --- a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java +++ b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java @@ -45,7 +45,7 @@ import com.jme3.util.TempVars; * regardless of the model's location. The material's ambient color is * multiplied by the ambient light color to get the final ambient color of * an object. - * + * * @author Kirill Vainer */ public class AmbientLight extends Light { @@ -61,12 +61,12 @@ public class AmbientLight extends Light { public boolean intersectsBox(BoundingBox box, TempVars vars) { return true; } - + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { return true; } - + @Override public void computeLastDistance(Spatial owner) { } diff --git a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java index 333154b2d..87fbf695a 100644 --- a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java +++ b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java @@ -85,10 +85,10 @@ public class DirectionalLight extends Light { /** * Returns the direction vector of the light. - * + * * @return The direction vector of the light. - * - * @see DirectionalLight#setDirection(com.jme3.math.Vector3f) + * + * @see DirectionalLight#setDirection(com.jme3.math.Vector3f) */ public Vector3f getDirection() { return direction; @@ -99,7 +99,7 @@ public class DirectionalLight extends Light { *

* Represents the direction the light is shining. * (1, 0, 0) would represent light shining in the +X direction. - * + * * @param dir the direction of the light. */ public final void setDirection(Vector3f dir){ @@ -113,12 +113,12 @@ public class DirectionalLight extends Light { public boolean intersectsBox(BoundingBox box, TempVars vars) { return true; } - + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { return true; } - + @Override public Type getType() { return Type.Directional; From d8e964b2f0f7b1c7e729fcd748cbc9c6ea062596 Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Sun, 13 Sep 2015 20:43:41 +0100 Subject: [PATCH 11/13] Added copyright headers to some files. --- .../java/com/jme3/audio/lwjgl/LwjglALC.java | 31 ++++++++++++++++++ .../java/com/jme3/audio/lwjgl/LwjglEFX.java | 31 ++++++++++++++++++ .../java/com/jme3/renderer/lwjgl/LwjglGL.java | 31 ++++++++++++++++++ .../com/jme3/renderer/lwjgl/LwjglGLExt.java | 31 ++++++++++++++++++ .../jme3/renderer/lwjgl/LwjglGLFboEXT.java | 31 ++++++++++++++++++ .../jme3/renderer/lwjgl/LwjglGLFboGL3.java | 31 ++++++++++++++++++ .../com/jme3/system/lwjgl/LwjglDisplay.java | 32 ++++++++++++++++++- .../system/lwjgl/LwjglOffscreenBuffer.java | 32 ++++++++++++++++++- .../com/jme3/system/lwjgl/LwjglWindow.java | 3 +- 9 files changed, 249 insertions(+), 4 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java index e0aed80ee..b0b1bc1e3 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.audio.lwjgl; import com.jme3.audio.openal.ALC; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java index 2ddd09ed8..ecd67211f 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglEFX.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.audio.lwjgl; import com.jme3.audio.openal.EFX; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 80e7f3513..187b232f2 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.renderer.lwjgl; import com.jme3.renderer.RendererException; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java index 00b3f688c..2ed2ec215 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLExt.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.renderer.lwjgl; import com.jme3.renderer.RendererException; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java index 969d7ae1d..5d9fe8dc1 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboEXT.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.renderer.lwjgl; import com.jme3.renderer.RendererException; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java index aa15aeb09..5a7a9825e 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/renderer/lwjgl/LwjglGLFboGL3.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.renderer.lwjgl; import com.jme3.renderer.RendererException; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java index 4a13c30af..3eb749adc 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java @@ -1,8 +1,38 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.system.lwjgl; /** * @author Daniel Johansson - * @since 2015-08-11 */ public class LwjglDisplay extends LwjglWindow { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java index e374e1841..8fdde51af 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java @@ -1,10 +1,40 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.system.lwjgl; import com.jme3.system.JmeContext; /** * @author Daniel Johansson - * @since 2015-08-11 */ public class LwjglOffscreenBuffer extends LwjglWindow { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 6eac34cdc..c5cb35e03 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -60,8 +60,7 @@ import static org.lwjgl.system.MemoryUtil.NULL; /** * A wrapper class over the GLFW framework in LWJGL 3. * - * @author Daniel Johansson (dannyjo) - * @since 3.1 + * @author Daniel Johansson */ public abstract class LwjglWindow extends LwjglContext implements Runnable { From 30cdca7ad727bc79fe1946fb80ee8375d3938350 Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Thu, 17 Sep 2015 11:59:44 +0100 Subject: [PATCH 12/13] Native library loading is back to the way it used to be with the addition of LWJGL 3.x libraries added with a different key. Moved LWJGL 3.x repository definition to build.grade in that module. Fixed an issue where frame rate limit would cause GLFW frequency window hint to be set rather than use a software limiter. Removed LWJGLTimer for lwjgl3 module, no need for it any more, we'll just use the NanoTimer. Removed LWJGLCanvas for lwjgl3 module, can't implement this so we'll leave it for now. --- common.gradle | 3 - .../com/jme3/system/NativeLibraryLoader.java | 36 ++ .../system/lwjgl/LwjglAbstractDisplay.java | 1 - .../com/jme3/system/lwjgl/LwjglContext.java | 21 +- jme3-lwjgl3/build.gradle | 6 + .../com/jme3/system/lwjgl/LwjglCanvas.java | 369 ------------------ .../com/jme3/system/lwjgl/LwjglContext.java | 25 +- .../system/lwjgl/LwjglSmoothingTimer.java | 203 ---------- .../com/jme3/system/lwjgl/LwjglTimer.java | 139 ------- .../com/jme3/system/lwjgl/LwjglWindow.java | 51 ++- 10 files changed, 83 insertions(+), 771 deletions(-) delete mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java delete mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java delete mode 100644 jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java diff --git a/common.gradle b/common.gradle index c225588c4..237ee5e7f 100644 --- a/common.gradle +++ b/common.gradle @@ -16,9 +16,6 @@ repositories { maven { url "http://nifty-gui.sourceforge.net/nifty-maven-repo" } - maven { - url "https://oss.sonatype.org/content/repositories/snapshots" - } } configurations { diff --git a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java index 6e83e0e6b..53898883c 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java +++ b/jme3-desktop/src/main/java/com/jme3/system/NativeLibraryLoader.java @@ -124,6 +124,42 @@ public final class NativeLibraryLoader { } static { + // LWJGL + registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); + registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); + registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); + registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); + registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + + // OpenAL + // For OSX: Need to add lib prefix when extracting + registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); + registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); + registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); + registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); + registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + + // LWJGL 3.x + registerNativeLibrary("lwjgl3", Platform.Windows32, "native/windows/lwjgl32.dll"); + registerNativeLibrary("lwjgl3", Platform.Windows64, "native/windows/lwjgl.dll"); + registerNativeLibrary("lwjgl3", Platform.Linux32, "native/linux/liblwjgl32.so"); + registerNativeLibrary("lwjgl3", Platform.Linux64, "native/linux/liblwjgl.so"); + registerNativeLibrary("lwjgl3", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); + registerNativeLibrary("lwjgl3", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); + registerNativeLibrary("lwjgl3", Platform.Windows32, "native/windows/jemalloc32.dll"); + registerNativeLibrary("lwjgl3", Platform.Windows64, "native/windows/jemalloc.dll"); + + // OpenAL for LWJGL 3.x + // For OSX: Need to add lib prefix when extracting + registerNativeLibrary("openal-lwjgl3", Platform.Windows32, "native/windows/OpenAL32.dll"); + registerNativeLibrary("openal-lwjgl3", Platform.Windows64, "native/windows/OpenAL.dll"); + registerNativeLibrary("openal-lwjgl3", Platform.Linux32, "native/linux/libopenal32.so"); + registerNativeLibrary("openal-lwjgl3", Platform.Linux64, "native/linux/libopenal.so"); + registerNativeLibrary("openal-lwjgl3", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); + registerNativeLibrary("openal-lwjgl3", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); + // BulletJme registerNativeLibrary("bulletjme", Platform.Windows32, "native/windows/x86/bulletjme.dll"); registerNativeLibrary("bulletjme", Platform.Windows64, "native/windows/x86_64/bulletjme.dll"); diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index 415084788..802b12a0f 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -206,7 +206,6 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna + "Must set with JmeContext.setSystemListner()."); } - registerNatives(); loadNatives(); logger.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); if (!initInThread()) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 70885c39b..ee12d1fea 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -162,26 +162,7 @@ public abstract class LwjglContext implements JmeContext { } } } - - protected void registerNatives() { - // LWJGL - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl.dll"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl64.dll"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl.so"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl64.so"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); - - // For OSX: Need to add lib prefix when extracting - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL64.dll"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal.so"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal64.so"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); - } - - protected void loadNatives() { + protected void loadNatives() { if (JmeSystem.isLowPermissions()) { return; } diff --git a/jme3-lwjgl3/build.gradle b/jme3-lwjgl3/build.gradle index c9b43e0de..3c7e4e646 100644 --- a/jme3-lwjgl3/build.gradle +++ b/jme3-lwjgl3/build.gradle @@ -2,6 +2,12 @@ if (!hasProperty('mainClass')) { ext.mainClass = '' } +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/snapshots" + } +} + dependencies { compile project(':jme3-core') compile project(':jme3-desktop') diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java deleted file mode 100644 index 1f1ef2ab5..000000000 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.jme3.system.lwjgl; - -import com.jme3.system.AppSettings; -import com.jme3.system.JmeCanvasContext; - -import javax.swing.*; -import java.awt.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; - -public class LwjglCanvas extends LwjglWindow implements JmeCanvasContext { - - protected static final int TASK_NOTHING = 0, - TASK_DESTROY_DISPLAY = 1, - TASK_CREATE_DISPLAY = 2, - TASK_COMPLETE = 3; - -// protected static final boolean USE_SHARED_CONTEXT = -// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true")); - - protected static final boolean USE_SHARED_CONTEXT = false; - - private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName()); - private Canvas canvas; - private int width; - private int height; - - private final Object taskLock = new Object(); - private int desiredTask = TASK_NOTHING; - - private Thread renderThread; - private boolean runningFirstTime = true; - private boolean mouseWasGrabbed = false; - - private boolean mouseWasCreated = false; - private boolean keyboardWasCreated = false; - - private long window; - - private class GLCanvas extends Canvas { - @Override - public void addNotify(){ - super.addNotify(); - - if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED) { - return; // already destroyed. - } - - if (renderThread == null){ - logger.log(Level.FINE, "EDT: Creating OGL thread."); - - // Also set some settings on the canvas here. - // So we don't do it outside the AWT thread. - canvas.setFocusable(true); - canvas.setIgnoreRepaint(true); - - renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); - renderThread.start(); - }else if (needClose.get()){ - return; - } - - logger.log(Level.FINE, "EDT: Telling OGL to create display .."); - synchronized (taskLock){ - desiredTask = TASK_CREATE_DISPLAY; -// while (desiredTask != TASK_COMPLETE){ -// try { -// taskLock.wait(); -// } catch (InterruptedException ex) { -// return; -// } -// } -// desiredTask = TASK_NOTHING; - } -// logger.log(Level.FINE, "EDT: OGL has created the display"); - } - - @Override - public void removeNotify(){ - if (needClose.get()){ - logger.log(Level.FINE, "EDT: Application is stopped. Not restoring canvas."); - super.removeNotify(); - return; - } - - // We must tell GL context to shutdown and wait for it to - // shutdown, otherwise, issues will occur. - logger.log(Level.FINE, "EDT: Telling OGL to destroy display .."); - synchronized (taskLock){ - desiredTask = TASK_DESTROY_DISPLAY; - while (desiredTask != TASK_COMPLETE){ - try { - taskLock.wait(); - } catch (InterruptedException ex){ - super.removeNotify(); - return; - } - } - desiredTask = TASK_NOTHING; - } - - logger.log(Level.FINE, "EDT: Acknowledged receipt of canvas death"); - // GL context is dead at this point - - super.removeNotify(); - } - } - - public LwjglCanvas(){ - super(Type.Canvas); - canvas = new GLCanvas(); - } - - public void create(boolean waitFor){ - if (renderThread == null){ - logger.log(Level.FINE, "MAIN: Creating OGL thread."); - - renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); - renderThread.start(); - } - // do not do anything. - // superclass's create() will be called at initInThread() - if (waitFor) { - waitFor(true); - } - } - - public Canvas getCanvas(){ - return canvas; - } - - @Override - protected void runLoop(){ - if (desiredTask != TASK_NOTHING){ - synchronized (taskLock){ - switch (desiredTask){ - case TASK_CREATE_DISPLAY: - logger.log(Level.FINE, "OGL: Creating display .."); - restoreCanvas(); - listener.gainFocus(); - desiredTask = TASK_NOTHING; - break; - case TASK_DESTROY_DISPLAY: - logger.log(Level.FINE, "OGL: Destroying display .."); - listener.loseFocus(); - pauseCanvas(); - break; - } - desiredTask = TASK_COMPLETE; - taskLock.notifyAll(); - } - } - - if (renderable.get()){ - int newWidth = Math.max(canvas.getWidth(), 1); - int newHeight = Math.max(canvas.getHeight(), 1); - - if (width != newWidth || height != newHeight){ - width = newWidth; - height = newHeight; - if (listener != null){ - listener.reshape(width, height); - } - } - } - - super.runLoop(); - } - - private void pauseCanvas(){ - if (mouseInput != null) { - mouseInput.setCursorVisible(true); - mouseWasCreated = true; - } - -/* - if (Mouse.isCreated()){ - if (Mouse.isGrabbed()){ - Mouse.setGrabbed(false); - mouseWasGrabbed = true; - } - mouseWasCreated = true; - Mouse.destroy(); - } - if (Keyboard.isCreated()){ - keyboardWasCreated = true; - Keyboard.destroy(); - } -*/ - - renderable.set(false); - destroyContext(); - } - - /** - * Called to restore the canvas. - */ - private void restoreCanvas(){ - logger.log(Level.FINE, "OGL: Waiting for canvas to become displayable.."); - while (!canvas.isDisplayable()){ - try { - Thread.sleep(10); - } catch (InterruptedException ex) { - logger.log(Level.SEVERE, "OGL: Interrupted! ", ex); - } - } - - logger.log(Level.FINE, "OGL: Creating display context .."); - - // Set renderable to true, since canvas is now displayable. - renderable.set(true); - createContext(settings); - - logger.log(Level.FINE, "OGL: Display is active!"); - - try { - if (mouseWasCreated){ -// Mouse.create(); -// if (mouseWasGrabbed){ -// Mouse.setGrabbed(true); -// mouseWasGrabbed = false; -// } - } - if (keyboardWasCreated){ -// Keyboard.create(); -// keyboardWasCreated = false; - } - } catch (Exception ex){ - logger.log(Level.SEVERE, "Encountered exception when restoring input", ex); - } - - SwingUtilities.invokeLater(new Runnable(){ - public void run(){ - canvas.requestFocus(); - } - }); - } - -/* - */ -/** - * Makes sure the pbuffer is available and ready for use - *//* - - protected void makePbufferAvailable() throws LWJGLException{ - if (pbuffer != null && pbuffer.isBufferLost()){ - logger.log(Level.WARNING, "PBuffer was lost!"); - pbuffer.destroy(); - pbuffer = null; - } - - if (pbuffer == null) { - pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); - pbuffer.makeCurrent(); - logger.log(Level.FINE, "OGL: Pbuffer has been created"); - - // Any created objects are no longer valid - if (!runningFirstTime){ - renderer.resetGLObjects(); - } - } - - pbuffer.makeCurrent(); - if (!pbuffer.isCurrent()){ - throw new LWJGLException("Pbuffer cannot be made current"); - } - } - - protected void destroyPbuffer(){ - if (pbuffer != null){ - if (!pbuffer.isBufferLost()){ - pbuffer.destroy(); - } - pbuffer = null; - } - } -*/ - - /** - * This is called: - * 1) When the context thread ends - * 2) Any time the canvas becomes non-displayable - */ - protected void destroyContext(){ - // invalidate the state so renderer can resume operation - if (!USE_SHARED_CONTEXT){ - renderer.cleanup(); - } - - if (window != 0) { - glfwDestroyWindow(window); - } - - // TODO: Destroy input - - - // The canvas is no longer visible, - // but the context thread is still running. - if (!needClose.get()){ - renderer.invalidateState(); - } - } - - /** - * This is called: - * 1) When the context thread starts - * 2) Any time the canvas becomes displayable again. - */ - @Override - protected void createContext(final AppSettings settings) { - // In case canvas is not visible, we still take framerate - // from settings to prevent "100% CPU usage" - allowSwapBuffers = settings.isSwapBuffers(); - - if (renderable.get()){ - if (!runningFirstTime){ - // because the display is a different opengl context - // must reset the context state. - if (!USE_SHARED_CONTEXT){ - renderer.cleanup(); - } - } - - super.createContext(settings); - } - - // At this point, the OpenGL context is active. - if (runningFirstTime) { - // THIS is the part that creates the renderer. - // It must always be called, now that we have the pbuffer workaround. - initContextFirstTime(); - runningFirstTime = false; - } - } -} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 86b6a294a..7f62a447e 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -98,41 +98,20 @@ public abstract class LwjglContext implements JmeContext { return Integer.MAX_VALUE; } - protected void registerNatives() { - // LWJGL - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl32.dll"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl.dll"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl32.so"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl.so"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/jemalloc32.dll"); - NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/jemalloc.dll"); - - // OpenAL - // For OSX: Need to add lib prefix when extracting - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL.dll"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal32.so"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal.so"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); - NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); - } - protected void loadNatives() { if (JmeSystem.isLowPermissions()) { return; } if ("LWJGL".equals(settings.getAudioRenderer())) { - NativeLibraryLoader.loadNativeLibrary("openal", true); + NativeLibraryLoader.loadNativeLibrary("openal-lwjgl3", true); } if (NativeLibraryLoader.isUsingNativeBullet()) { NativeLibraryLoader.loadNativeLibrary("bulletjme", true); } - NativeLibraryLoader.loadNativeLibrary("lwjgl", true); + NativeLibraryLoader.loadNativeLibrary("lwjgl3", true); } protected int getNumSamplesToUse() { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java deleted file mode 100644 index a7960a261..000000000 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglSmoothingTimer.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.jme3.system.lwjgl; - -import com.jme3.math.FastMath; -import com.jme3.system.Timer; -import org.lwjgl.glfw.GLFW; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Timer handles the system's time related functionality. This - * allows the calculation of the framerate. To keep the framerate calculation - * accurate, a call to update each frame is required. Timer is a - * singleton object and must be created via the getTimer method. - * - * @author Mark Powell - * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ - */ -public class LwjglSmoothingTimer extends LwjglTimer { - private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class - .getName()); - - private long lastFrameDiff; - - //frame rate parameters. - private long oldTime; - - private float lastTPF, lastFPS; - - public static int TIMER_SMOOTHNESS = 32; - - private long[] tpf; - - private int smoothIndex; - - private final static long LWJGL_TIMER_RES = 1; - private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); - private static float invTimerRezSmooth; - - public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); - - private long startTime; - - private boolean allSmooth = false; - - /** - * Constructor builds a Timer object. All values will be - * initialized to it's default values. - */ - public LwjglSmoothingTimer() { - reset(); - - //print timer resolution info - logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); - } - - public void reset() { - lastFrameDiff = 0; - lastFPS = 0; - lastTPF = 0; - - // init to -1 to indicate this is a new timer. - oldTime = -1; - //reset time - startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); - - tpf = new long[TIMER_SMOOTHNESS]; - smoothIndex = TIMER_SMOOTHNESS - 1; - invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS)); - - // set tpf... -1 values will not be used for calculating the average in update() - for ( int i = tpf.length; --i >= 0; ) { - tpf[i] = -1; - } - } - - /** - * @see Timer#getResolution() - */ - public long getResolution() { - return LWJGL_TIMER_RES; - } - - /** - * getFrameRate returns the current frame rate since the last - * call to update. - * - * @return the current frame rate. - */ - public float getFrameRate() { - return lastFPS; - } - - public float getTimePerFrame() { - return lastTPF; - } - - /** - * update recalulates the frame rate based on the previous - * call to update. It is assumed that update is called each frame. - */ - public void update() { - long newTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); - long oldTime = this.oldTime; - this.oldTime = newTime; - if ( oldTime == -1 ) { - // For the first frame use 60 fps. This value will not be counted in further averages. - // This is done so initialization code between creating the timer and the first - // frame is not counted as a single frame on it's own. - lastTPF = 1 / 60f; - lastFPS = 1f / lastTPF; - return; - } - - long frameDiff = newTime - oldTime; - long lastFrameDiff = this.lastFrameDiff; - if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) { - frameDiff = lastFrameDiff *100; - } - this.lastFrameDiff = frameDiff; - tpf[smoothIndex] = frameDiff; - smoothIndex--; - if ( smoothIndex < 0 ) { - smoothIndex = tpf.length - 1; - } - - lastTPF = 0.0f; - if (!allSmooth) { - int smoothCount = 0; - for ( int i = tpf.length; --i >= 0; ) { - if ( tpf[i] != -1 ) { - lastTPF += tpf[i]; - smoothCount++; - } - } - if (smoothCount == tpf.length) - allSmooth = true; - lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount ); - } else { - for ( int i = tpf.length; --i >= 0; ) { - if ( tpf[i] != -1 ) { - lastTPF += tpf[i]; - } - } - lastTPF *= invTimerRezSmooth; - } - if ( lastTPF < FastMath.FLT_EPSILON ) { - lastTPF = FastMath.FLT_EPSILON; - } - - lastFPS = 1f / lastTPF; - } - - /** - * toString returns the string representation of this timer - * in the format:
- *
- * jme.utility.Timer@1db699b
- * Time: {LONG}
- * FPS: {LONG}
- * - * @return the string representation of this object. - */ - @Override - public String toString() { - String string = super.toString(); - string += "\nTime: " + oldTime; - string += "\nFPS: " + getFrameRate(); - return string; - } -} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java deleted file mode 100644 index c4a0e5025..000000000 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglTimer.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.jme3.system.lwjgl; - -import com.jme3.system.Timer; -import org.lwjgl.glfw.GLFW; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Timer handles the system's time related functionality. This - * allows the calculation of the framerate. To keep the framerate calculation - * accurate, a call to update each frame is required. Timer is a - * singleton object and must be created via the getTimer method. - * - * @author Mark Powell - * @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ - */ -public class LwjglTimer extends Timer { - - private static final Logger logger = Logger.getLogger(LwjglTimer.class.getName()); - - //frame rate parameters. - private long oldTime; - private long startTime; - - private float lastTPF, lastFPS; - - private final static long LWJGL_TIMER_RES = 1; - private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); - public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); - - /** - * Constructor builds a Timer object. All values will be - * initialized to it's default values. - */ - public LwjglTimer() { - reset(); - logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); - } - - public void reset() { - startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); - oldTime = getTime(); - } - - @Override - public float getTimeInSeconds() { - return getTime() * INV_LWJGL_TIMER_RES; - } - - /** - * @see Timer#getTime() - */ - public long getTime() { - return ((long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS) - startTime); - } - - /** - * @see Timer#getResolution() - */ - public long getResolution() { - return LWJGL_TIMER_RES; - } - - /** - * getFrameRate returns the current frame rate since the last - * call to update. - * - * @return the current frame rate. - */ - public float getFrameRate() { - return lastFPS; - } - - public float getTimePerFrame() { - return lastTPF; - } - - /** - * update recalulates the frame rate based on the previous - * call to update. It is assumed that update is called each frame. - */ - public void update() { - long curTime = getTime(); - lastTPF = (curTime - oldTime) * (1.0f / LWJGL_TIMER_RES); - lastFPS = 1.0f / lastTPF; - oldTime = curTime; - } - - /** - * toString returns the string representation of this timer - * in the format:
- *
- * jme.utility.Timer@1db699b
- * Time: {LONG}
- * FPS: {LONG}
- * - * @return the string representation of this object. - */ - @Override - public String toString() { - String string = super.toString(); - string += "\nTime: " + oldTime; - string += "\nFPS: " + getFrameRate(); - return string; - } -} \ No newline at end of file diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index c5cb35e03..2f00eb700 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -42,6 +42,7 @@ import com.jme3.input.lwjgl.GlfwMouseInput; 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.*; @@ -73,6 +74,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { protected boolean allowSwapBuffers = false; private long window = -1; private final JmeContext.Type type; + private int frameRateLimit = -1; + private double frameSleepTime; private GLFWErrorCallback errorCallback; private GLFWWindowSizeCallback windowSizeCallback; @@ -160,16 +163,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits()); glfwWindowHint(GLFW_SAMPLES, settings.getSamples()); glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE); - - int frameRateCap = settings.getFrameRate(); - - if (!autoFlush) { - frameRateCap = 20; - } - - if (frameRateCap > 0) { - glfwWindowHint(GLFW_REFRESH_RATE, frameRateCap); - } + glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency()); // Not sure how else to support bits per pixel if (settings.getBitsPerPixel() == 24) { @@ -289,7 +283,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { }); } - timer = new LwjglTimer(); + timer = new NanoTimer(); // For canvas, this will create a pbuffer, // allowing us to query information. @@ -303,7 +297,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } catch (Exception ex) { try { if (window != -1) { - //glfwSetWindowShouldClose(window, GL_TRUE); glfwDestroyWindow(window); } } catch (Exception ex2) { @@ -360,11 +353,41 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { if (renderer != null) { renderer.postFrame(); } + + if (autoFlush) { + if (frameRateLimit != getSettings().getFrameRate()) { + setFrameRateLimit(getSettings().getFrameRate()); + } + } else if (frameRateLimit != 20) { + setFrameRateLimit(20); + } + + // If software frame rate limiting has been asked for, lets calculate sleep time based on a base value calculated + // from 1000 / frameRateLimit in milliseconds subtracting the time it has taken to render last frame. + // This gives an approximate limit within 3 fps of the given frame rate limit. + if (frameRateLimit > 0) { + final double sleep = frameSleepTime - (timer.getTimePerFrame() / 1000.0); + final long sleepMillis = (long) sleep; + final int additionalNanos = (int) ((sleep - sleepMillis) * 1000000.0); + + if (sleepMillis >= 0 && additionalNanos >= 0) { + try { + Thread.sleep(sleepMillis, additionalNanos); + } catch (InterruptedException ignored) { + } + } + } + } + + private void setFrameRateLimit(int frameRateLimit) { + this.frameRateLimit = frameRateLimit; + frameSleepTime = 1000.0 / this.frameRateLimit; } /** * De-initialize in the OpenGL thread. */ + protected void deinitInThread() { destroyContext(); @@ -379,7 +402,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { + "Must set with JmeContext.setSystemListener()."); } - registerNatives(); loadNatives(); LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); @@ -445,6 +467,9 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { return window; } + + // TODO: Implement support for window icon when GLFW supports it. + private ByteBuffer[] imagesToByteBuffers(Object[] images) { ByteBuffer[] out = new ByteBuffer[images.length]; for (int i = 0; i < images.length; i++) { From c375974a9a88d9484122e358c89b7ea2db5fd98b Mon Sep 17 00:00:00 2001 From: Daniel Johansson Date: Thu, 17 Sep 2015 14:48:02 +0100 Subject: [PATCH 13/13] Fixed a compiler error where glfw input classes wanted to use the old LwjglTimer class. --- .../src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java | 3 +-- .../src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index 5b7d8e267..20cd07672 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java @@ -35,7 +35,6 @@ package com.jme3.input.lwjgl; import com.jme3.input.KeyInput; import com.jme3.input.RawInputListener; import com.jme3.input.event.KeyInputEvent; -import com.jme3.system.lwjgl.LwjglTimer; import com.jme3.system.lwjgl.LwjglWindow; import org.lwjgl.glfw.GLFWKeyCallback; @@ -112,6 +111,6 @@ public class GlfwKeyInput implements KeyInput { } public long getInputTimeNanos() { - return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + return (long) (glfwGetTime() * 1000000000); } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java index 41e76a29d..05a2df5db 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java @@ -37,7 +37,6 @@ import com.jme3.input.MouseInput; import com.jme3.input.RawInputListener; import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseMotionEvent; -import com.jme3.system.lwjgl.LwjglTimer; import com.jme3.system.lwjgl.LwjglWindow; import org.lwjgl.glfw.GLFWCursorPosCallback; import org.lwjgl.glfw.GLFWMouseButtonCallback; @@ -183,7 +182,7 @@ public class GlfwMouseInput implements MouseInput { } public long getInputTimeNanos() { - return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); + return (long) (glfwGetTime() * 1000000000); } public void setNativeCursor(final JmeCursor jmeCursor) {