Why jme3-lwjgl3 works only with jme3-lwjgl

I try to start SimpleApplication “JMEApp”:

private void attachJmeCanvasToFrame(AppSettings settings) {
        JMEApp app = new JMEApp(gameControllerService, settings, props);
        app.createCanvas();
        app.startCanvas();

        // ждём пока JME-окно не прогрузится:
        log.info("Ожидание готовности SimpleApplication...");
        while (!app.isReady() || app.getAssetManager() == null) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException _) {
            }
        }
...

and app.createCanvas(); got error “ctx is null”.

Then I do this:

private void attachJmeCanvasToFrame(AppSettings settings) {
        JMEApp app = new JMEApp(gameControllerService, settings, props);

        // ждём пока JME-окно не прогрузится:
        log.info("Ожидание готовности SimpleApplication...");
        while (!app.isReady() || app.getAssetManager() == null) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException _) {
            }
        }

        app.createCanvas();
        app.startCanvas();
...

and stop into while-cycle forever.

Than, I back all to first variant. And add in my maven pom a library jme3-lwjgl

<!-- jmonkey -->
        <dependency> // <<< THIS
            <groupId>org.jmonkeyengine</groupId> // <<< THIS
            <artifactId>jme3-lwjgl</artifactId> // <<< THIS
            <version>3.6.1-stable</version> // <<< THIS
        </dependency> // <<< THIS
        <dependency>
            <groupId>org.jmonkeyengine</groupId>
            <artifactId>jme3-core</artifactId>
            <version>3.6.1-stable</version>
        </dependency>
        <dependency>
            <groupId>org.jmonkeyengine</groupId>
            <artifactId>jme3-lwjgl3</artifactId>
            <version>3.6.1-stable</version>
        </dependency>
...

And all works! Application starts correctly. I see the game window… but why?
With library jme3-lwjgl I can not to use io.github.jmecn.font.plugins.FtFontLoader.class for loding my fonts (.fnt + .png):

[ERROR] th:jME3 Main c.j.a.LegacyApplication.handleError():666   Uncaught exception thrown in Thread[#68,jME3 Main,6,main]
java.lang.UnsatisfiedLinkError: Failed to locate library: lwjgl.dll
	at org.lwjgl.system.Library.loadSystem(Library.java:174)
	at org.lwjgl.system.Library.loadSystem(Library.java:64)
	at org.lwjgl.system.Library.<clinit>(Library.java:52)
	at org.lwjgl.system.MemoryUtil.<clinit>(MemoryUtil.java:100)
	at org.lwjgl.system.Pointer$Default.<clinit>(Pointer.java:67)
	at io.github.jmecn.font.freetype.FtLibrary.<init>(FtLibrary.java:35)

But without jme3-lwjgl my App is not starts and gamma correction always broken…
(I set settings.setGammaCorrection(true); on application start, as hardcode)

P.S.: isReady() is a boolean, I set it to true in the end of simpleInitApp() of the JMEApp.

The startup for lwjgl3 is significantly different as I recall. (I half remember that it even must use the same thread you start on… but maybe that’s only on Macs.)

But you will have problems even if you could startup because glfw (that lwjgl3 uses) is apparently completely incompatible with Swing/AWT.

Someone else may have more details. (I still use lwjgl2 because I’m slow to upgrade and don’t want to deal with random issues like this yet.)

Yep, I love updates and want to be ready to future )
That’s why I started with lwjgl3…

Update of my project to 3 part later, after some years, may be harder. I think so.
All right, I can`t use jme3-freetype anymore, but stil can create simple ttf+png fonts… Its ugly, but works. -_-"

Will see.

I like freetype besause It have many beautifull things as that:


and my texts was perfect -_-"

Or you port the fnt loader to lwjgl2.

Or just by taking a quick look at the build.gradle, what is the actual error when you use jme-lwjgl and the fnt loader?

I am not sure about it, thats why i ask, but no opengl/glfw is used in the fnt loader. There might be other thing that wont allow using any lwjgl3 lib in combination with a lwjgl2 one

Hi @Kira_39

The current version of jme3 (3.6.1-stable - at least with lwjgl3) does not support creating canvases (AWT/Swing), so an exception is thrown.

Than, I back all to first variant. And add in my maven pom a library jme3-lwjgl

And all works! Application starts correctly. I see the game window… but why?

That works since lwjgl supports Swing/AWT, that is; that your application uses lwjgl and not lwjgl3

In the new version of JME (3.7), an effort is being made to allow creating canvases using lwjgl3 again (you can try it in the beta version).

With library jme3-lwjgl I can not to use io.github.jmecn.font.plugins.FtFontLoader.class for loding my fonts (.fnt + .png):

This is because lwjgl and lwjgl3 are different (at the API level), specifically it uses the ‘lwjgl-freetype’ module which is native to lwjgl3 and depends on this version so you can’t mix them (it is possible to make it work with some tricks ),

Yes, I remove jme3-lwjgl and got exception in methode private JmeContext newContextLwjgl(AppSettings settings, JmeContext.Type type)

09.10.24 05:16:00.607 [ERROR] th:AWT-EventQueue-0 c.jme3.system.JmeSystem.newContextLwjgl():152   CRITICAL ERROR: Context class is missing!
Make sure jme3_lwjgl-ogl is on the classpath.
java.lang.ClassNotFoundException: com.jme3.system.lwjgl.LwjglCanvas
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:413)
	at java.base/java.lang.Class.forName(Class.java:404)

Its a good idea to try to use newer version. Ok…

Its strange, early I use AppSettings.LWJGL_OPENGL45, but with a new version Its not supported, I switch render to AppSettings.LWJGL_OPENGL32


warn here, Its my check-method after app starts…

Finally, app is works. Yes, updating lib to beta was helpful. But gammaCorrection broken (all is dark) and components not in their places. Refactoring and research are needed…

This behavior is strange, if possible I would like to ask you a few things:

  1. Are you using the beta version of JME?
  2. What OS are you using?
  3. Can you share a screenshot with this problem?

I was able to run the application with a new version jme3 (3.7.0-beta1.2.2) as swing canvas. And gammaCorrection was fixed with

@Override
    public void gainFocus() {
        log.info("Focus gained...");
        if (renderer != null) {
            log.info("Коррекция гаммы при получении фокуса окном игры...");
            renderer.setMainFrameBufferSrgb(true);
            renderer.setLinearizeSrgbImages(true);
        }
...

OS: Windows 10 x64 LTSC (21H2)

Now gamma works correctly, but when I toggle frame to fullscreen than got Error

on last line restart() all crashed:

public void toggleFullscreen() {
        AppSettings settings = Constants.getGameCanvas().getContext().getSettings();
        DisplayMode vMode = FoxVideoMonitorUtil.getDisplayMode();
        Dimension dDim = FoxVideoMonitorUtil.getConfiguration().getBounds().getSize();

        if (Constants.getUserConfig().isUseVSync()) {
            settings.setFrequency(vMode.getRefreshRate()); // use VSync
        } else if (Constants.getUserConfig().getFpsLimit() > 0) {
            settings.setFrequency(Constants.getUserConfig().getFpsLimit()); // use fps limit
        } else {
            settings.setFrequency(-1); // unlimited
        }

        if (Constants.getUserConfig().isFullscreen()) {
            restoreToWindow(settings);
            Constants.getUserConfig().setFullscreen(false);
        } else if (FoxVideoMonitorUtil.isFullScreenSupported()) {
            switch (Constants.getUserConfig().getFullscreenType()) {
                case EXCLUSIVE -> doExclusive(settings, vMode, dDim);
                case MAXIMIZE_WINDOW -> doMaximize(settings, vMode, dDim);
                case null, default ->
                        log.error("Некорректное указание режима окна '{}'", Constants.getUserConfig().getFullscreenType());
            }
            Constants.getUserConfig().setFullscreen(true);
        }

        settings.setFullscreen(Constants.getUserConfig().isFullscreen());
        log.info("Fullscreen mode now: {} ({})", Constants.getUserConfig().isFullscreen(), settings.isFullscreen());

        Constants.getGameFrame().reloadCanvasDim();
        restart(); // Это не перезапускает и не переинициализирует всю игру, перезапускает контекст и применяет обновленный объект настроек
    }

Exclusive or pseudo maximized window - I got these errors…

I remove the restart() method.

Now EXCLUSIVE fullscreen mode works correctly.
But MAXIMIZE_WINDOW makes the canvas black, even after returning to windowed mode

private void doExclusive(AppSettings settings, DisplayMode vMode) {
        log.info("Do exclusive window fullscreen...");
        // frame:
        FoxVideoMonitorUtil.setFullscreen(Constants.getGameFrame());

        // canvas:
        settings.setResolution(vMode.getWidth(), vMode.getHeight());
        settings.setBitsPerPixel(vMode.getBitDepth());
        settings.setFullscreen(true);
    }

    private void doMaximize(AppSettings settings, DisplayMode vMode) {
        log.info("Do pseudo maximize window fullscreen...");
        // frame:
        Constants.getGameFrame().dispose();
        Constants.getGameFrame().setUndecorated(true);
        Constants.getGameFrame().setSize(vMode.getWidth(), vMode.getHeight());
        Constants.getGameFrame().setState(Frame.MAXIMIZED_BOTH);
        Constants.getGameFrame().setLocationRelativeTo(null);
        Constants.getGameFrame().setVisible(true);

        // canvas:
        settings.setResolution(vMode.getWidth(), vMode.getHeight());
        settings.setFullscreen(true);
    }

    private void restoreToWindow(AppSettings settings) {
        log.info("Restore from fullscreen mode...");
        // frame:
        FoxVideoMonitorUtil.setFullscreen(null);
        Constants.getGameFrame().setState(Frame.NORMAL);
        Constants.getGameFrame().setLocationRelativeTo(null);
        Constants.getGameFrame().setPreferredSize(new Dimension(Constants.getUserConfig().getWindowWidth(), Constants.getUserConfig().getWindowHeight()));
        Constants.getGameFrame().setSize(new Dimension(Constants.getUserConfig().getWindowWidth(), Constants.getUserConfig().getWindowHeight()));
        Constants.getGameFrame().setSize(Constants.getUserConfig().getWindowWidth(), Constants.getUserConfig().getWindowHeight());
        Constants.getGameFrame().setLocationRelativeTo(null);

        if (Constants.getUserConfig().getFullscreenType().equals(FullscreenType.MAXIMIZE_WINDOW)) {
            Constants.getGameFrame().dispose();
            Constants.getGameFrame().setUndecorated(false);
            Constants.getGameFrame().setVisible(true);
        }

        // canvas:
        settings.setFullscreen(false);
        settings.setBitsPerPixel(settings.getDepthBits());
        settings.setResolution(Constants.getUserConfig().getWindowWidth(), Constants.getUserConfig().getWindowHeight());
    }

P.S.: my method FoxVideoMonitorUtil.setFullscreen(Constants.getGameFrame()):

@UtilityClass
public class FoxVideoMonitorUtil {
    @Getter
    private final static GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
    @Getter
    private final static GraphicsDevice device = environment.getDefaultScreenDevice();
    @Getter
    private final static GraphicsConfiguration configuration = device.getDefaultConfiguration();

    public static DisplayMode getDisplayMode() {
        return device.getDisplayMode();
    }

    public static void setDisplayMode(DisplayMode mode) {
        device.setDisplayMode(mode);
    }

    public static void setFullscreen(Window win) {
        device.setFullScreenWindow(win);
    }
...

And Constants.getGameFrame() = my GameWindowSwing, the JFrame with JMECanvas onboard.

Well, if I remove jFrame undecorating - all is good.
I need to find way to fix restore jmeCanvas content after jFrame dispose…
And all problems will gone.

On Windows, this error is present; That is to say: if you delete a component (Swing/AWT - Canvas) in its context, the canvas where it is rendering will be broken… a possible solution is that the jme canvas must be created again, leaving the scene in memory.

It is possible that at some point the canvas context is being removed from awt, which is why the canvas breaks. While lwjg3-awt makes swing work, it is far from 100% compatible with GLFW