/openglfx

OpenGL implementation for JavaFX

Primary LanguageKotlinApache License 2.0Apache-2.0

OpenGLFX

Embedded OpenGL node for rendering using LWJGL and JOGL with the best performance available.

Written on Kotlin with Java compatibility.

Screenshots

Usage

NOTE: All examples are written in Kotlin, Gradle and LWJGL. If you want to use Java/JOGL/Maven, you can use example code generator.

Dependency

repositories {
    // ...
    maven { url 'https://jitpack.io' }
}

dependencies {
    // ...JavaFX and LWJGL libraries...
    implementation 'com.github.husker-dev.openglfx:core:3.0.5'
    implementation 'com.github.husker-dev.openglfx:lwjgl:3.0.5'
}

Creation

This library adds only one component - OpenGLCanvas, that can be used like a regular element in JavaFX.

import com.huskerdev.openglfx.OpenGLCanvas
import com.huskerdev.openglfx.lwjgl.LWJGLExecutor.Companion.LWJGL_MODULE

val canvas = OpenGLCanvas.create(LWJGL_MODULE)
// or
val canvas = OpenGLCanvas.create(LWJGL_MODULE, CORE_PROFILE) // For Core OpenGL profile

Rendering

OpenGLCanvas uses a logic similar to JOGL. The component has events where you can render content.

// JOGL only: Use the following code in each event to get the GL object
// val gl = (event as JOGLEvent).gl

canvas.addOnInitEvent { event ->
    // Init some gl properties only at start
}

canvas.addOnRenderEvent { event ->
    val fps = event.fps
    val delta = event.delta
    val width = event.width
    val height = event.height
    // Render some content
}

canvas.addOnReshapeEvent { event ->
    val width = event.width
    val height = event.height
    // Changing viewport and matrices
}

canvas.addOnDisposeEvent { event ->
    // Clear some native data
}

Auto repaint

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.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")

Notes

  • JOGL can't initialize on macOS (#22)

If you know how to fix that problem I would be very happy

Reflections opens

--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

Under the hood

  • Offscreen GL

    husker-dev/offscreen-jgl 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: OpenGLCanvas.create(YOUR_EXECUTOR_INSTANCE).

  • Texture sharing

    To efficiently connect OpenGL and JavaFX, OpenGLFX uses some techniques based on OS.

    Description Implementation
    Windows NV_DX_interop is used to synchronize textures between DirectX from JavaFX and OpenGL. InteropImpl.kt
    Linux/MacOS Creates a new GL context, that is shared with the JavaFX's one. Then renders to a JavaFX texture. SharedImpl.kt
    Other Copies PixelBuffer from glReadPixels to JavaFX Image UniversalImpl.kt

Thanks to