However, that only tests LWJGL v2. To test LWJGL v3 (or run some of the more sophisticated example apps), clone the repo and build the Engine from source:
$ git clone https://github.com/jmonkeyengine/jmonkeyengine.git
$ cd jmonkeyengine
$ git checkout -b latest v3.5.0-beta4
$ ./gradlew run
To switch between LWJGL v2 and v3, edit lines 22-23 of the file “jme3-examples/build.gradle” and rebuild.
Any issues or difficulties with v3.5.0-beta4 may be discussed here. If you believe you’ve discovered a new bug, you may also open an issue at GitHub.
One thing I find annoying about v3.5: ALSOFT warning messages during app startup, like these:
[ALSOFT] (EE) Failed to set real-time priority for thread: Operation not permitted (1)
[ALSOFT] (EE) Failed to set real-time priority for thread: Operation not permitted (1)
I don’t think they indicate a serious problem, but short of reverting to LWJGL v3.2.3, I don’t see how to disable them.
I think I’ve found a bug in 3.5 beta. A call to SimpleApplication.stop(boolean waitFor) with waitFor=true causes the application to freeze. This doesn’t happen on 3.4.1-stable, where the app stops as expected.
The following code shows the issue:
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
public class StopAppTest extends SimpleApplication {
private float time = 0.0f;
public static void main(String... args) {
final Application app = new StopAppTest();
app.start();
}
@Override
public void simpleInitApp() {
final DirectionalLight light = new DirectionalLight(new Vector3f(-.5f, -.5f, -.5f), ColorRGBA.White);
rootNode.addLight(light);
final Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mat.setColor("Diffuse", ColorRGBA.Blue);
mat.setBoolean("UseMaterialColors", true);
final Spatial cube = new Geometry("Cube", new Box(1, 1, 1));
cube.setMaterial(mat);
rootNode.attachChild(cube);
}
@Override
public void simpleUpdate(float tpf) {
rootNode.getChild("Cube").rotate(tpf, tpf, tpf);
time += tpf;
System.out.println(time);
// stops after 10 seconds
if (time >= 10) {
this.stop(true); // THIS LINE HANGS THE APP
}
}
}
Edit: running on openSUSE Tumbleweed and openjdk 17.0.1.
@fba can you open up an issue on the JME Github page?
Also, are you using LWJGL3? If so, maybe this can be related to
Edit:
I could reproduce this issue as well in Linux Mint with LWJGL3.
Edit2:
I noticed in the above PR (submitted by @kevinba99 ?) the newly created thread is never set to mainThread field at the below line, so mainThread field value will be null.
thus will be evaluated to null here:
Setting the mainThread at line 513 fixed it for me.
When I update my projects to 3.5.0-beta4, they fail to locate the native LWJGL(3) libraries during startup.
I tried to run them from the IDE (IntelliJ) on both, Windows 10 and Linux Kubuntu,
AdoptOpenJDK 11 and GraalVM 17.
Dec 28, 2021 4:37:32 PM com.jme3.system.JmeDesktopSystem initialize
INFO: Running on jMonkeyEngine 3.5.0-beta4
* Branch: HEAD
* Git Hash: b10d6d4
* Build Date: 2021-12-17
[LWJGL] Version: 3.3.0 build 21
[LWJGL] OS: Linux v5.11.0-41-generic
[LWJGL] JRE: Linux amd64 17.0.1
[LWJGL] JVM: OpenJDK 64-Bit Server VM v17.0.1+12-jvmci-21.3-b05 by GraalVM Community
[LWJGL] Loading JNI library: lwjgl
[LWJGL] Module: org.lwjgl
[LWJGL] linux/x64/org/lwjgl/liblwjgl.so not found in java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
[LWJGL] liblwjgl.so not found in java.library.path
[LWJGL] Failed to load a library. Possible solutions:
a) Add the directory that contains the shared library to -Djava.library.path or -Dorg.lwjgl.librarypath.
b) Add the JAR that contains the shared library to the classpath.
Dec 28, 2021 4:37:32 PM com.jme3.app.LegacyApplication handleError
SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.UnsatisfiedLinkError: Failed to locate library: liblwjgl.so
at org.lwjgl.system.Library.loadSystem(Library.java:164)
at org.lwjgl.system.Library.loadSystem(Library.java:63)
at org.lwjgl.system.Library.<clinit>(Library.java:51)
at org.lwjgl.system.MemoryUtil.<clinit>(MemoryUtil.java:100)
at org.lwjgl.system.Pointer$Default.<clinit>(Pointer.java:67)
at org.lwjgl.system.Callback.<clinit>(Callback.java:40)
at com.jme3.system.lwjgl.LwjglWindow.createContext(LwjglWindow.java:191)
at com.jme3.system.lwjgl.LwjglWindow.initInThread(LwjglWindow.java:524)
at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:659)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception: java.lang.NoClassDefFoundError thrown from the UncaughtExceptionHandler in thread "jME3 Main"
I’m using Gradle and the build scripts are all similar to this one:
After the update, I couldn’t find any lwjgl-xxxx-3.3.0-natives-xxxx.jar files inside ~/.gradle.
These do exist for previous LWJGL versions (3.2.3).
The 3.3.0 files are downloaded when I add the dependencies manually, e.g.:
I see the actual *.so files are extracted to some directory in /tmp.
This works for Linux and Windows and the program runs without issues so far.
Updating to previous versions was a breeze and only included changing the jme-version string defined in the Gradle script. But since the error seems obvious and you don’t seem to encounter the same, I assume the issue lies in my Gradle script or maybe the Gradle version (6.1).
Any hints?
When I run applications containing “jme3-lwjgl3-3.5.0-beta4.jar” on 64-bit OpenJDK version 11 on Linux, 5 native libraries get written to the “/tmp/lwjglsgold/3.3.0-build-21” directory, and that same directory gets added to the “org.lwjgl.librarypath” system property. I’m unsure why your apps are behaving differently.
The extracted files have the following names and properties:
sgold:~/Git/BasicGame-on-Gradle$ ls -l /tmp/lwjglsgold/*
total 2436
-rw-rw-r-- 1 sgold sgold 373744 Dec 28 08:07 libglfw.so
-rw-rw-r-- 1 sgold sgold 371600 Dec 28 08:07 libjemalloc.so
-rw-rw-r-- 1 sgold sgold 354072 Dec 28 08:07 liblwjgl_opengl.so
-rw-rw-r-- 1 sgold sgold 391728 Dec 28 08:07 liblwjgl.so
-rw-rw-r-- 1 sgold sgold 991320 Dec 28 08:07 libopenal.so
JME uses NativeLibraryLoader.loadNativeLibrary() to extract native libraries:
The “org.lwjgl.librarypath” property gets set in line 667. I wonder whether that code gets executed on your system. Could you step through the method in a debugger or add some System.out.println() calls?
Edit: Looking at your “build.gradle”, I don’t see where the repositories get set, nor where the jmonkeyengineVersion variable gets set.
Thanks for your suggestions. I updated Gradle (through the Gradle wrapper) from 6.1.1 to 6.9.1 and now it seems to work as it should.
And I can confirm that it also works with runtimeOnly for jme3-lwjgl3.
It seems to me that Gradle somehow didn’t retrieve all transitive dependencies, even though ./gradlew dependencies listed them all… I think. It didn’t say anything about the native libraries specifically.
The JARs containing the .so/.dll were missing, so there was also nothing to extract.
With Gradle v6.1.1, I was able to reproduce the UnsatisfiedLinkError. I’ll investigate further.
Edit: Whatever the Gradle bug was, it was fixed between v6.3-rc-2 and v6.3-rc-3. I looked at the release notes for both releases, but nothing jumped out at me. Very interesting!
Edit^2: I haven’t found a better workaround than simply upgrading Gradle, so I added an item to the 3.5.0-beta4 release notes:
to use the “jme3-lwjgl3” library in a Gradle build, you’ll need Gradle v6.3 or later
java.lang.NullPointerException: Cannot invoke "com.jme3.anim.tween.action.Action.setMask(com.jme3.anim.AnimationMask)" because "this.currentAction" is null
at com.jme3.anim.AnimLayer.update(AnimLayer.java:209)
at com.jme3.anim.AnimComposer.controlUpdate(AnimComposer.java:391)
at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:118)
at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:743)
at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:890)
at com.jme3.scene.Node.updateLogicalState(Node.java:228)
at com.jme3.scene.Node.updateLogicalState(Node.java:239)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:262)
at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:578)
at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:667)
at java.base/java.lang.Thread.run(Thread.java:833)
I took a test myself and encountered the same exception. I confirm @Ali_RS’s analysis.
If it helps, this is the previous controlUpdate method of the AnimComposer class from jme-3.4.0
public class AnimComposer {
...
@Override
protected void controlUpdate(float tpf) {
for (Layer layer : layers.values()) {
Action currentAction = layer.currentAction;
if (currentAction == null) {
continue;
}
layer.advance(tpf);
currentAction.setMask(layer.mask);
boolean running = currentAction.interpolate(layer.time);
currentAction.setMask(null);
if (!running) {
layer.time = 0;
}
}
}
}
Here the possible solution in the AnimLayer class:
public class AnimLayer {
...
void update(float appDeltaTimeInSeconds) {
Action runningAction = currentAction;
if (runningAction == null) {
return;
}
double speedup = runningAction.getSpeed() * composer.getGlobalSpeed();
double scaledDeltaTime = speedup * appDeltaTimeInSeconds;
time += scaledDeltaTime;
// wrap negative times to the [0, length] range:
if (time < 0.0) {
double length = runningAction.getLength();
time = (time % length + length) % length;
}
// update the current Action, filtered by this layer's mask:
runningAction.setMask(mask);
boolean running = runningAction.interpolate(time);
runningAction.setMask(null);
if (!running) { // went past the end of the current Action
time = 0.0;
}
}
}