JavaFX 3d API and OpenGL

Official news from Oracle: JavaFX 3D early access !!!


https://wikis.oracle.com/display/OpenJDK/3D+Features

No sign of OpenGL though, they decided to wrap it (and DirectX), which is the wrong path IMO.
No please, I don’t want to learn another 3D API, there are just too many of them. It’s OpenGL or nothing for me.

Yet, this could open backdoors for the JOGL team, especially if all of this goes open source.

Julien, any feedback on this news ???

Well, it depends on how well they wrap it :wink:

It seems they’re wrapping it with high level concepts, basically they’re making a scenegraph.
Porting “low level” JOGL/LWJGL code to it will be more difficult, and we’re losing a lot of control.
And what if we don’t need a scenegraph at all, or using our own already…

Is it me, or people at Sun/Oracle are so obsessed with object-ville they can't stop wrapping things into objects ? That's something I hate in the java ecosystem: this tendency to over wrap things into other things until we can't see the whole picture anymore.

Looks interesting. Does it have lighting? What’s the performance like? Does it work in an applet? Wish I had more time.

It does support lighting. I didn’t test it, so I can’t speak about performances. If it works in JavaFX, the 3D feature will also work everywhere you can deploy JavaFX, including applets, I guess.

Looks like Java3D all over again.

Cas :slight_smile:

Scenegraphs are great for simple tools & basic 3D and sucks for everything else. So it depends on the target audience. But OMG, Phong…are you kidding me? Cookie cutter materials? So 80s/90s. Get with the shader program (yuck, yuck) baby. I’m too lazy to try to dig-up and look at the source to see if there’s a sane low level exposed…if not it’s pretty worthless.

Yep.
Can’t people learn from History ? Not always it seems…

I hope LWJGL/JOGL can benefit somehow.
spasi ? Julien ? Save us with a good news please ;D

JavaFX exposing a 3D API doesn’t change anything for integration purposes, since it’s at a level higher than the interesting stuff.

Speaking for LWJGL, we’re exploring different options and we won’t commit to anything until we try to integrate with JavaFX properly. We’re currently waiting for Prism and Glass to be fully open sourced, then we’ll see what’s possible. There’s been a lot of progress with the open sourcing of JavaFX (details here), but we’ll have to a wait a few more weeks for Prism.

Spasi can confirm that it is already possible to use LWJGL to render some JavaFX thingy in a FBO, this code should not be difficult to port to JOGL 2.0 and it would benefit of some helpers allowing to have some fallbacks where FBOs are not available or too slow.

There is already a JOGL backend for JavaFX, it was working with a very old version (prior to JavaFX 2). I already talked to you about that in your bug report, I tried to be extremely accurate.

I don’t want to be harsh but there are plenty of things to do with existing APIs. I won’t port another temporarily trendy thing, especially if it is only used by a very few people. JavaFX has some interesting features but some of them are already present in JogAmp or we already plan to provide alternatives.

I need the whole source code of Quantum, Prism and Glass. I have to admit that I have other priorities for the next siggraph, your help would be welcome.

Yep I saw spasi’s technique. I succeeded with glReadPixels and WritableImage. It’s slow, but fixed pipeline must work in my case. Didn’t try with FBOs.

I can’t be of much help, I have zero knowledge of JOGL/LWJGL’s inner working, and have my hands already more than dirty with a project using JOGL.
I’ll wait for what could be done when Quantum, Prism and Glass go open source, if they ever do…

In the meantime as you said there are workarounds: for me the easiest will be to mix JavaFX with Swing+JOGL.

Please can you share your source code? I need something working with the fixed pipeline too. Maybe I could help you a little bit but I will start using JavaFX only when it works with OpenJDK.

I have spent a lot of time in improving the environment (the APIs) required for my own project using JOGL during 6 years. Why not sharing your findings? It would be better than nothing.

You’re right but what do you mainly use in JavaFX? Personally, I’m interested in the charting API and a bit in CSS.

Edit.: I have to be more precise.

[tr][td]XML dialect of UI[/td][td]We can use XMLEncoder and XMLDecoder with Java beans to achieve something similar[/td][/tr]
[tr][td]Scripting languages[/td][td]Nothing prevents a developer from using a scripting engine with JogAmp[/td][/tr]
[tr][td]Web rendering engine[/td][td] :persecutioncomplex: - [/td][/tr]
[tr][td]Swing interoperability[/td][td]It has been working for years and it is possible to render Swing components without AWT thanks to GLG2D[/td][/tr]
[tr][td]High-performance hardware accelerated graphics pipeline[/td][td]There are already several efficient scenegraphs supporting JOGL 2.0, including Ardor3D (>= 0.9), JMonkeyEngine (>= 3.0), …[/td][/tr]
[tr][td]High-performance media engine[/td][td]There is already some video and audio playback in JogAmp but there is a lack of backends for some operating systems[/td][/tr]
[tr][td]Charting & CSS[/td][td]A NEWT backend based on GLG2D for JFreeChart or a port of this charting API is doable if and only if it is well decoupled from the rest.[/td][/tr]
[tr][td]Ubiquitous deployment[/td][td]We are still talking about providing full builds of OpenJDK or of our own JRE[/td][/tr]

Here it is.

It’s a JavaFX app, that displays a red triangle on a black background using JOGL 2 rc11 (the only needed lib). The drawing is done in a hidden GLCanvas, then using glReadPixels copied into a WritableImage. You may have to click the “redraw” button to see the result at the beginning.

2 downsides:

  • The GLCanvas is inside a JFrame, which must be shown then hidden, otherwise all OpenGL calls will be ignored. So you can see the JFrame flashing when the app starts, which is a bit annoying.
  • it’s very slow, it takes on average 11ms on my fairly good laptop (i7, gtx660m) mostly the call to glReadPixels I suppose

package todel;

import com.jogamp.common.nio.Buffers;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

public class Todel extends Application {

    static int width = 512;
    static int height = 480;
    static ByteBuffer byteBuffer;

    @Override
    public void start(Stage primaryStage) {
        final WritableImage writableImage = new WritableImage(640, 480);
//        final PixelFormat<ByteBuffer> pf = PixelFormat.getByteBgraPreInstance();
        final PixelFormat<ByteBuffer> pf = PixelFormat.getByteRgbInstance();


        //        SwingUtilities.invokeLater(new Runnable() {
//            @Override
//            public void run() {
        final JFrame win = new JFrame("Swing");
        win.setSize(width, height);
        win.setLocationRelativeTo(null);

        GLProfile glProfile = GLProfile.getDefault();
        GLCapabilities glCapabilities = new GLCapabilities(glProfile);
        final GLCanvas glcanvas = new GLCanvas(glCapabilities);
//        final GLWindow newtWindow = new  GLWindow(glCapabilities);
        glcanvas.addGLEventListener(new GLEventListener() {
//        newtWindow.addGLEventListener(new GLEventListener() {
            @Override
            public void init(GLAutoDrawable glad) {
                GL2 gl = (GL2) glad.getContext().getGL();
                gl.glClearColor(.1f, .1f, .1f, .1f);
            }

            @Override
            public void dispose(GLAutoDrawable glad) {
            }

            @Override
            public void display(GLAutoDrawable glad) {
                long startTime = System.currentTimeMillis();
                GL2 gl = (GL2) glad.getContext().getGL();
                gl.glColor4f(1, 0, 0, 1);
                gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
                gl.glBegin(GL2.GL_TRIANGLES);
                gl.glVertex2f(0, 0);
                gl.glVertex2f(1, 0);
                gl.glVertex2f(0, 1);
                gl.glEnd();

                gl.glReadBuffer(GL2.GL_FRONT);
                width = glcanvas.getWidth();
                height = glcanvas.getHeight();
                if (byteBuffer == null) {
                    byteBuffer = Buffers.newDirectByteBuffer(width * height * 3);
                }


                gl.glReadPixels(0, 0, width, height, GL2.GL_RGB, GL2.GL_UNSIGNED_BYTE, byteBuffer);
//                Thread
//                
//                BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//                int[] imageData = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
//                for (int y = 0; y < height; y++) {
//                    for (int x = 0; x < width; x++) {
//                        int b = 2 * byteBuffer.get();
//                        int g = 2 * byteBuffer.get();
//                        int r = 2 * byteBuffer.get();
//
//                        imageData[(height - y - 1) * width + x] = (r << 16) | (g << 8) | b | 0xFF000000;
//                    }
//                }
//                System.out.println("copied color buffer");
//                try {
//                    ImageIO.write(bufferedImage, "png", new File("C:\\Users\\arnaud\\Desktop\\todel.png"));
//                } catch (IOException ex) {
//                    System.out.println("Could not save image because " + ex);
//                }
//                byte[] bytes = new byte[width * height * 3];
//                PixelWriter pix = new PixelWriter() {}
//                byteBuffer.get(bytes);
//                bytes[0] = (byte)255;

                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
//                        try {
//                            Thread.sleep(1000);
//                        } catch (InterruptedException ex) {
//                            Logger.getLogger(Todel.class.getName()).log(Level.SEVERE, null, ex);
//                        }
                        writableImage.getPixelWriter().setPixels(0, 0, width, height, pf, byteBuffer, width * 3);
                    }
                });
                t.start();
//                writableImage.getPixelWriter().setPixels(0, 0, width, height, pf, byteBuffer, width * 3);
                //                for (int y = 0; y < height; y++) {
                //                    for (int x = 0; x < width; x++) {
                //                        int b = 2 * byteBuffer.get();
                //                        int g = 2 * byteBuffer.get();
                //                        int r = 2 * byteBuffer.get();
                //                        writableImage.getPixelWriter().setColor(x, y, new Color(r/255f, g/255f, b/255f, 1));
                //                    }
                //                }
//                try {
//                    Thread.sleep(1000);
//                } catch (InterruptedException ex) {
//                    Logger.getLogger(Todel.class.getName()).log(Level.SEVERE, null, ex);
//                }
                System.out.println("Displayed in " + (System.currentTimeMillis() - startTime) + " ms");
            }

            @Override
            public void reshape(GLAutoDrawable glad, int i, int i1, int i2, int i3) {
            }
        });
        win.getContentPane().add(glcanvas);
        win.setVisible(true);
        win.setVisible(false);
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//            }
//        });

        Button btn = new Button();
        btn.setText("Reraw");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                glcanvas.display();
            }
        });



        ImageView imgView = new ImageView(writableImage);

        Pane root = new FlowPane();
        root.getChildren().add(btn);
//        root.getChildren().add(new Button("gg"));
        root.getChildren().add(imgView);

        Scene scene = new Scene(root, 800, 600);

        primaryStage.setTitle("JavaFX");
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.toFront();
        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                win.dispose();
            }
        });

    }

    public static void main(String[] args) {
        launch(args);
    }
}


There may be a misunderstanding here. I have no finding to share, I’m enjoying JOGL so far. What I meant is: all my time must be devoted to wrapping my project, which is very late already

I need JavaFX

  1. to do almost exactly what spasi did in his “Dope” project here http://www.java-gaming.org/topics/tool-dope/27389/view.html. A node-based interface. In the meantime I’m using the Netbeans Visual library, but I find it clunky. I’ll definitely have to dump it at some point
  2. CSS GUI skinning. Swing + Nimbus is ok, but I’d prefer something more expressive.
  3. potentially the animation framework, and integrated browser, but later
    The neat thing with JavaFX is that it’s part of Java, so (hopefully) very well supported. I try to use as few libs as possible.

Why would you provide your own JRE ?

Downloaded the API. Not familiar with JavaFx, but can’t see how to do fog or fade to grey with distance.

However a quick googling suggests that there is a Shader language compiler for JavaFx, although I can’t find anything more.
http://mail.openjdk.java.net/pipermail/openjfx-dev/2012-November/004292.html
Anyone know anything about that?

Edit: After reading more carefully, I think Decora isn’t a end-user tool and only is of use to Oracle. Unless anyone can find a way of bolting stuff on via any unsupported APIs.
Edit2: I found this: http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-February/006136.html

Edit 3: Our current 3D implementation makes no use of the decora-compiler translator, which means that the 3d shaders are hand written which means they are different, and theoretically could introduce a bit of shader code that isn’t as well tested (In practice it isn’t that big of a deal). Prism’s use of JSL itself is also in need of work since writing a shader is only half the battle. We need to be able to provide flexible vertex data objects/interfaces and manage these in a way that is simple and flexible if we are to provide shaders to developers.

Oh well, never mind.

I’m not sure I can follow what these guys are talking about, but it seems we’re going to have to write OSL/Decora/Pixel Bender code, then it’ll be automagically translated into GLSL / HLSL ? Well, why not… but although it’d make it easier (higher level) we could potentially be losing a lot of control if we need precise results, since we’d be relying on the underlying OSL/Decora/Pixel Bender-compatible renderer.