Can we expect JOGL as an "official" render option in JME?

I’m evaluating JME for production use and require multi-windowed support. At the moment, AwtPanel does not provide adequate performance to be considered as an option. I’ve been monitoring the forums for a few months and have not seen much discussion with regards to JOGL use in JME. It was mentioned that JOGL may replace LWJGL in 3.1. Is this still the case? I can get the current 3.0 to work with JOGL but it appears that this practice is discouraged. What is the future of JOGL in JME?

Are there any other options in JME for gaining multi-context support?

The official maintainer for jME3’s JOGL backend, @gouessej is no longer here.
Given that JOGL support is almost broken in the current jME3.1, it is very likely to be removed (especially since it is taking a lot of space in each installer package).

Does multi-windowed mean using AWT / Swing and having an embedded jME panel or just sepearate standalone jME3 windows?

Having jME embedded into a Swing application, either as a Canvas or Panel (any AWT component really). I need to have a main JFrame that displays a jME scene (main app) and then a floating dialog spawned from the main app that shows a different scene. At the moment JOGL is the only working renderer in jME that allows multiple contexts (the AwtPanel’s off-screen rendering solution has poor fps in my tests).

Another problem with the AWTPanel is that the FilterPostProcessor with a Bloom filter throughs an exception and is broken if it is used. I am also looking to a multi-windows solution.

Maybe it’s time to have a look at LWJGL3? It supports multiple windows using GLFW (including hidden off-screen windows). Although it doesn’t have any official AWT/JavaFX support components yet, people have already been able to create AWT and JavaFX applications by simply draw everything to an hidden GFLW window and copying its contents over to a AWT or JavaFX image.

Drawing to a hidden window / pbuffer is what is currently used for AWT / Swing integration, and it is the same between LWJGL 2 and 3. There’s two issues with that approach:

  1. its much slower than drawing directly to a canvas or window.
  2. There’s no API to manage multiple windows within jME, instead there are AWT panels, which is more of a hack / workaround on top of the current system, which causes problems with things like post-processing filters not working when applied to more than one window.

Also, LWJGL3 support is already being implemented here:

1 Like

Yeh the extra copy does make it slower but overall is probably the best and most reliable method. This is because AWT/Swing/JavaFX do not support or expose API’s to integrate with OpenGL, so any method to draw directly is nothing but a hack and usually results in all sorts of bugs and problems.

In retrospect adding AWT support directly into LWJGL 2’s API was a probably the wrong thing to do. It was a source of a major problems/bugs, increased the complexity of the library and required massive amounts of development time as implementations on various platforms occassionally changed therefore breaking the code. It’s something which hopefully won’t be repeated in LWJGL3 and if implemented be done in a way which doesn’t effect the core API.

Also I’d recommend for LWJGL3 that pbuffer’s be completely dropped in JME and the switch be made to using FBO’s + hidden window instead.

1 Like

No worries, the pbuffer API’s are all gone in LWJGL 3 so that will all be going. The plan is to make the lwjgl3 renderer into a separate module (jme3-lwjgl3) which can be easily swapped into place of the jme3-lwjgl module to enable the use of LWJGL 3.

This may be the root cause of why there is no multi-context support. I have used Ardor3d in the past and they overcome the single LWJGL instance by managing and switching the local contexts of each scene/canvas to be rendered.

I’m still there, sorry. I can make the few adjustments soon. I’m just extremely busy, trying to maintain several engines at the same time is very time consuming. I have to implement the unified renderer and switch to JOGL 2.3.2 RC.

@Mr_Marbles The JOGL renderer will go on being maintained whatever happens in the future even though it won’t become something official.

Sorry for the off topic but JogAmp’s Ardor3D Continuation is actively maintained, it’s the same for the JOGL backend of LibGDX and Java 3D 1.6.0. Feel free to use the scenegraph API that fits your needs.

1 Like

Do you have any guarantees that the jME renderer API will remain extendable so the the JOGL port will continue to work in the future? I am somewhat hesitant to rely on external engine extensions that may fail at any time due to API changes. Any thoughts on this?

From the recent talks on the forum I got an impression that JME3 is moving toward LWJGL3 which supports multiwindow applications and this feature will be added to JME3. Somebody correct me if I’m wrong…

@Mr_Marbles Actually, the JogAmp community is reliable, relying on our backends on the long term has proven to be a viable option, it is even sometimes safer (or at least something complementary) than relying only on the “official” maintainers, for example with Java 3D as we still maintain it (big kudos to Harvey, August, Emmanuel and the others) whereas Sun Microsystems abandoned it in 2009, with Ardor3D as Renanse decided to stop maintaining it in March 2014 as we still maintain it (but it’s called JogAmp’s Ardor3D Continuation now), with LibGDX as we are still almost daily synced with the “official” version (big kudos to Xerxes). The core maintainers won’t do anything that would intentionally prevent the JogAmp community from maintaining a separate renderer. Just look at my reactivity on our official forum, the bugs are fixed within days or in the worst case within a few weeks. Oracle abandoned JOGL in 2010 and we’re still here (thanks to Sven and others). Do you really need the pretty label “OFFICIAL” to feel reassured?

JOGL has supported multiple windows in an application for about ten years. All major scenegraph APIs written in Java has a JOGL backend, official or not.

Back to the topic, the answer to the question is: yes or no, it doesn’t matter as the JOGL backend will remain maintained in the official repository or in the JogAmp repository. As long as JMonkeyEngine will remain a major 3D engine written in Java, it will have a JOGL backend.

Wow, that’s really cool to know! I have heard of a JOGL backend several times, but never used it. So I’d explore it if it is available. Hence I have some questions:

  1. What differences will I notice if I move from LWJGL to JOGL? I have some well-established JMonkeyEngine apps, using various features of it. I assume there will be no changes to my code?
  2. Will there be any visual changes to the picture? Or some other changes to the basic game behavior?
  3. Is there a tutorial on switching to the JOGL backend?
  4. Is there a tutorial/example on using many windows with JME+JOGL ?
  1. I don’t know, I don’t use the other library you talk about but I try to do nothing fancy that would annoy the JMonkeyEngine users. You just have to add one line of code to use JOGL and another one to use JOAL into your application at the very beginning. If you don’t use Maven or Gradle, it’s possible to use JogAmp thanks to only one JAR for everything (Java libraries + native libraries) since JOGL 2.3.2, which is named jogamp-fat.jar. Otherwise, JogAmp is on Maven Central :smile: You don’t have to set the Java library path, you don’t risk to pick the wrong libraries, typically when using a 32-bit JVM on a 64-bit OS.

  2. There shouldn’t be any change but I wasn’t here since April. You’ll have to wait for September to use the unified renderer.

  3. There is no such tutorial yet (I might write one if the JogAmp community asks me to do so) but I can prove that I provide some very complete tutorials for the engines we maintain, just look at those ones:
    JogAmp’s Java 3D Continuation http://gouessej.wordpress.com/2012/08/01/java-3d-est-de-retour-java-3d-is-back/
    JogAmp’s Ardor3D Continuation http://gouessej.wordpress.com/2014/11/22/ardor3d-est-mort-vive-jogamps-ardor3d-continuation-ardor3d-is-dead-long-life-to-jogamps-ardor3d-continuation/

  4. It’s not very difficult, I would rather explain it in the same tutorial rather than creating a separate tutorial just for this feature. It becomes a bit tricky when you want to share some data between several contexts.

If you need any assistance, please favour our official IRC channel and our official forum, these are more peaceful places to talk about the JOGL backends. This forum is still excellent for general JMonkeyEngine questions.

2 Likes

Thank you for your answers!

  1. Okay, I’m using maven, so I guess this one will be easy.
  2. Okay, I can wait till September, good to know it is coming rather soon.
  3. Gonna read those! The articles look very interesting by the pictures. Still wondering what couple of lines I have to add that you mentioned in answer to question 1)…
  4. Okay, but there is no tutorial yet… I wonder, how do I create the contexts from within my Java JMonkeyEngine app, what code exactly do I write and what are the implications of sharing the data between contexts…

Alright, I guess that when the unified renderer is released and I can work with it directly, in the upcoming September, I will come to the JOGL community to ask more about the particularities… probably some sort of a simple tutorial can be written for this as a result…

  1. http://search.maven.org/#search|ga|1|jogamp
  2. I try to avoid putting too much text without pictures :wink: @jmaasing knows which lines to add. I’m going to post them soon, sorry.
  3. You’re a client of the JMonkeyEngine API, we’ll have to do the necessary changes so that you don’t have to code directly against JogAmp so that you remain free to use another backend to compare.
1 Like

@noncom here is a sample test app that I’ve been using to run jME using JOGL with multiple JFrames:

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.util.JmeFormatter;
import jme3test.model.TestMonkeyHead;
import jme3test.model.anim.TestBlenderObjectAnim;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;

public class TestMultipleCanvas {

    public static Component createCanvas(AppSettings settings, Application app) {
        JmeCanvasContext context = (JmeCanvasContext) app.getContext();
        Component comp = context.getCanvas();
        comp.setSize(settings.getWidth(), settings.getHeight());
        return comp;
    }

    private static AppSettings createSettings() {
        AppSettings settings = new AppSettings(true);
        // settings.setVSync(true);
        settings.setFrameRate(60);
        settings.setAudioRenderer(null);
        settings.setWidth(800);
        settings.setHeight(600);
        settings.setRenderer("JOGL");
        return settings;
    }

    private static Application createApp(Class<? extends Application> appClass, AppSettings settings) {
        Application app = null;
        try {
            app = appClass.newInstance();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        }

        app.setPauseOnLostFocus(false);
        app.setSettings(settings);
        app.createCanvas();
        app.startCanvas();
        return app;
    }

    public static void startApp(Application... apps) {
        for (final Application app : apps) {
            app.startCanvas();
            app.enqueue(new Callable<Void>() {
                public Void call() {
                    if (app instanceof SimpleApplication) {
                        SimpleApplication simpleApp = (SimpleApplication) app;
                        simpleApp.getFlyByCamera().setDragToRotate(true);
                    }
                    return null;
                }
            });
        }

    }

    public static void main(String[] args) {
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);

        JmeFormatter formatter = new JmeFormatter();

        Handler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(formatter);

        Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
        Logger.getLogger("").addHandler(consoleHandler);

        AppSettings settings = createSettings();
        List<Class<? extends Application>> appClasses = getAppClasses();

        for (Class<? extends Application> appClass : appClasses) {
            final Application app = createApp(appClass, settings);
            startApp(app);
            final Component canvas1 = createCanvas(settings, app);
            init(canvas1, new JFrame(appClass.getSimpleName()), app);
        }
    }

    private static List<Class<? extends Application>> getAppClasses() {
        List<Class<? extends Application>> appClasses = new LinkedList<>();
        /*
        As many Application classes as you want
         */
        appClasses.add(TestBlenderObjectAnim.class);
        appClasses.add(TestMonkeyHead.class);
        return appClasses;
    }

    private static void init(final Component canvas, final JFrame frame, final Application app) {
        frame.add(canvas);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                app.stop();
            }
        });
    }
}

Just make sure all the JOGL binaries are on your classpath.

3 Likes

Interesting! Thank you, I am going to experiment with this and try it out on the weekend. If I understand correctly, this is the “fast” rendering, not the AWT panel slow thing? Btw, did you have any issues with data sharing between the contexts?