Buy coffee for the developer.
This library adds a new element to the JavaFX for rendering OpenGL graphics using LWJGL, JOGL, LWJGL2 or LibGDX. It is optimized for each platform and includes some auxiliary functions for working with OpenGL from JavaFX.
NOTE: All examples are written in Kotlin + Gradle + LWJGL. If you want to use Java/JOGL/Maven, you can use example code generator.
dependencies {
// implementation JavaFX
// implementation LWJGL
// implementation ...
implementation 'com.huskerdev:openglfx:4.0.5'
implementation 'com.huskerdev:openglfx-lwjgl:4.0.5'
}
Available modules:
openglfx-lwjgl
openglfx-lwjgl2
openglfx-jogl
openglfx-libgdx
This library adds only one component - GLCanvas
, that can be used like a regular element in JavaFX.
After canvas is not needed anymore, call dispose()
to free the allocated memory.
import com.huskerdev.openglfx.canvas.GLCanvas
import com.huskerdev.openglfx.lwjgl.LWJGLExecutor.Companion.LWJGL_MODULE
val canvas = GLCanvas(LWJGL_MODULE)
Available modules:
LWJGL_MODULE
LWJGL2_MODULE
JOGL_MODULE
LIBGDX_MODULE
GLCanvas
uses a logic similar to JOGL. The component has events where you can render the content.
canvas.addOnInitEvent { event ->
// Init some gl properties only once
}
canvas.addOnRenderEvent { event ->
// Render some content every frame
}
canvas.addOnReshapeEvent { event ->
// Change viewport matrices at resizing
}
canvas.addOnDisposeEvent { event ->
// Clear native data at disposing
}
GLCanvas
supports multi-sampling anti-aliasing. It can be enabled during creation.
For maximum possible MSAA level, specify -1.
GLCanvas(.., msaa = 4)
GLCanvas
can render graphics in a separated thread. This feature can either improve or decrease performance. Test it on your applications.
GLCanvas(.., async = true)
By default, OpenGL draws the image upside down. GLCanvas
has the ability to flip it without loss of performance. To do this, specify the parameter at startup.
GLCanvas(.., flipY = true)
OpenGL has two initialization profiles - Core
and Compatibility
, you can read about them on the Internet.
In GLCanvas you can specify the desired option. I advise you to always choose Core. To do this, you need to specify a parameter when creating.
GLCanvas(.., profile = GLProfile.Core)
GLCanvas(.., profile = GLProfile.Compatibility)
If you need to update content with a certain FPS, then you should use GLCanvasAnimator
. Keep in mind that JavaFX can limits the refresh rate.
import com.huskerdev.openglfx.canvas.GLCanvasAnimator
canvas.animator = GLCanvasAnimator(60.0)
canvas.animator = GLCanvasAnimator(GLCanvasAnimator.UNLIMITED_FPS) // For maximum available FPS
canvas.animator = null // To remove animator
Don't forget to disable VSync before JavaFX initialization if you want to get FPS more than monitor's frequency.
System.setProperty("prism.vsync", "false")
openglfx
has the ability to move images from JavaFX to OpenGL textures and vice versa. A special class is used for this:
val fbo = GLImageManager.toGL(image)
val image = GLImageManager.fromGL(fbo, width, height)
openglfx
supports RenderDoc integration. Unfortunately, java and javaFX limit how this tool can be used, so the following features have been made.
- You can take a screenshot of the following frame using the hotkey:
RenderDoc.bind(canvas) // F12 by default
// or
RenderDoc.bind(canvas, keyCode = KeyCode.F11)
- You can insert the beginning and ending of capturing into the code:
RenderDoc.startFrameCapture()
// Renders here...
RenderDoc.endFrameCapture()
It is better not to mix these two recording methods.
To view a scene in the Renderdoc application, you need to select one of the processes. It may change depending on the launch settings.
- RenderDoc + Windows crashes the JVM. Workaround is described in (#39);
- JOGL can't initialize on macOS (#22).
If you know how to fix that problem I would be very happy
--add-opens javafx.base/com.sun.javafx=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.prism=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.prism.d3d=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.scene.layout=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.sg.prism=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED
--add-opens javafx.graphics/javafx.scene.image=ALL-UNNAMED
-
husker-dev/offscreen-jgl is used to create offscreen thread-independent GL context on Windows, MacOS and Linux.
-
Executors are the bridges from OpenGLFX inner logic to outer libraries like LWJGL or JOGL.
LWJGL JOGL Class LWJGLExecutor.kt JOGLFXExecutor.kt Instance LWJGL_MODULE JOGL_MODULE If you want to add new OpenGL library, just create your implementation of GLExecutor and use it as existing one:
OpenGLCanvas.create(YOUR_EXECUTOR_INSTANCE)
. -
To efficiently connect OpenGL and JavaFX, OpenGLFX uses some techniques based on OS.
Description Sync implementation Async implementation Windows NV_DX_interop is used to synchronize textures between DirectX from JavaFX and OpenGL. NVDXInteropCanvasImpl.kt AsyncNVDXInteropCanvasImpl.kt Linux Creates context that is shared with JavaFX's one. After rendering, shared texture is displayed in JavaFX frame. SharedCanvasImpl.kt AsyncSharedCanvasImpl.kt macOS IOSurface is used to create memory block in VRAM that can be used in different OpenGL contexts. IOSurfaceCanvasImpl.kt AsyncIOSurfaceCanvasImpl.kt Other Copies ByteBuffer from glReadPixels
to JavaFX textureBlitCanvasImpl.kt AsyncBlitCanvasImpl.kt
- streamingdv - big donation, debugging
- James H Ball - macOS tester
- Andrew Hamilton - macOS tester, suggested new additions