Openglfx
OpenGL canvas for JavaFX
Install / Use
/learn @husker-dev/OpenglfxREADME
<a href="LICENSE"><img src="https://img.shields.io/github/license/husker-dev/openglfx?style=flat-square"></a> <a href="https://github.com/husker-dev/openglfx/releases/latest"><img src="https://img.shields.io/github/v/release/husker-dev/openglfx?style=flat-square"></a>
About
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.
Dependency
dependencies {
// implementation JavaFX
// implementation LWJGL
// implementation ...
implementation 'com.huskerdev:openglfx-lwjgl:4.2.3'
}
Available modules:
openglfx-lwjglopenglfx-lwjgl2openglfx-joglopenglfx-libgdx
JPMS
If you are using JPMS (Java 9+ modules), then you need to add the following module in module-info.java:
requires openglfx.lwjgl;
openglfx adds exports for JavaFX at runtime, but if you experience issues with package access, then add following arguments to JVM:
-Dopenglfx.disable.exports=true
Then add --add-exports by hand:
--add-exports=javafx.graphics/com.sun.prism=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.javafx.scene.layout=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.javafx.sg.prism=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.scenario=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED
--add-exports=javafx.graphics/com.sun.glass.ui=ALL-UNNAMED
Example
https://github.com/husker-dev/openglfx-example
Usage
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_MODULELWJGL2_MODULEJOGL_MODULELIBGDX_MODULE
Rendering events
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
}
Antialiasing (MSAA)
GLCanvas supports multi-sampling anti-aliasing. It can be enabled during creation.
For maximum possible MSAA level, specify -1.
GLCanvas(.., msaa = 4)
Swap buffers
GLCanvas based on the swap chain system - you can think of it as "double buffering".
The best UI performance is achieved with 2 (default). The most responsive to resizing is 1.
GLCanvas(.., swapBuffers = 1)
Y-flipping
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 profile
In GLCanvas you can specify the desired profile. I advise you to always choose Core. To do this, you need to specify a parameter in constructor.
GLCanvas(.., profile = GLProfile.CORE)
GLCanvas(.., profile = GLProfile.COMPATIBILITY)
FPS control
If you need to update content with a certain FPS, then you should use property fps. Keep in mind that JavaFX can limits the refresh rate.
| Value | Behavior | |-------|-----------------------------------------------------------------------------------------------------------------------------| | < 0 | Monitor refresh rate | | 0 | Do not updates automatically <br> (Keep in mind that the update may be triggered by resizing or other commands from JavaFX) | | > 0 | Update with desired FPS |
// In constructor
val canvas = GLCanvas(..., fps = 30)
// Or at runtime
canvas.fps = 40
A draw call can also be "requested" by calling the repaint() method.
It won't force a draw immediately, but will tell the renderer to prepare a frame as soon as possible.
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")
Image transfering
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)
RenderDoc & NSight
openglfx supports RenderDoc integration.
To use it, you need to set externalWindow in GLCanvas constructor to true.
This will create a separate window with the rendered image, which you can connect to via RenderDoc or NSight.
LibGDX
To use in LibGDX project, you should create new module.
Minimal build.gradle example:
plugins {
id("org.jetbrains.kotlin.jvm")
}
sourceSets.main.resources.srcDirs += [ rootProject.file('assets').path ]
dependencies {
implementation project(':core')
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
// openglfx
api("com.huskerdev:openglfx-libgdx:4.2.2")
// implementation(/* JavaFX */)
// implementation(/* LWJGL */)
}
Instead of using GLCanvas, you should use LibGDXCanvas:
val canvas = LibGDXCanvas(Main()) // Main is ApplicationAdapter
Under the hood
-
grapl
husker-dev/grapl is used to create offscreen thread-independent GL context on Windows, MacOS and Linux.
-
GLExecutor
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:
GLCanvas.create(YOUR_EXECUTOR_INSTANCE). -
Texture sharing
To efficiently connect OpenGL and JavaFX, OpenGLFX uses some techniques based on OS and supported extensions.
| | Description | Implementation | |-------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| | Windows <br> (that supports EXT_external_objects) | EXT_external_objects_win32 is used to create shared DXGI texture between DirectX 9 and OpenGL. | ExternalObjectsCanvasD3D.kt
