diff --git a/.github/resources/boosty.svg b/.github/resources/boosty.svg new file mode 100644 index 0000000..9642e3c --- /dev/null +++ b/.github/resources/boosty.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.github/resources/logo.png b/.github/resources/logo.png new file mode 100644 index 0000000..55bbc0b Binary files /dev/null and b/.github/resources/logo.png differ diff --git a/README.md b/README.md index 8c6fc82..9a7df50 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -![Logo](https://github.com/husker-dev/openglfx/assets/31825139/3968c34e-ad83-4613-a5ce-1524aa79aa83) +logo -### [Buy coffee](https://www.buymeacoffee.com/huskerdev) for the developer. + + boosty + @@ -10,17 +12,17 @@ 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. - [Dependency](#dependency) +- [Example](#example) - [Usage](#usage) - [Rendering events](#rendering-events) - [Antialiasing (MSAA)](#antialiasing-msaa) - - [Async rendering](#async-rendering) - [Y-flipping](#y-flipping) - [OpenGL profile](#opengl-profile) - - [Auto repaint](#auto-repaint) + - [FPS control](#fps-control) - [Image transfering](#image-transfering) - - [RenderDoc](#renderdoc) + - [RenderDoc](#renderdoc--nsight) + - [LibGDX](#libgdx) - [Notes](#notes) - - [Reflection opens](#reflection-opens) - [Under the hood](#under-the-hood) - [Thanks to](#thanks-to) @@ -34,8 +36,7 @@ dependencies { // implementation LWJGL // implementation ... - implementation 'com.huskerdev:openglfx:4.0.5' - implementation 'com.huskerdev:openglfx-lwjgl:4.0.5' + implementation 'com.huskerdev:openglfx-lwjgl:4.1.0' } ``` @@ -45,6 +46,10 @@ Available modules: - ```openglfx-jogl``` - ```openglfx-libgdx``` + +# 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. @@ -95,11 +100,13 @@ For maximum possible MSAA level, specify -1. GLCanvas(.., msaa = 4) ``` -### Async rendering -```GLCanvas``` can render graphics in a separated thread. This feature can either improve or decrease performance. Test it on your applications. +### 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`. ```kotlin -GLCanvas(.., async = true) +GLCanvas(.., swapBuffers = 1) ``` ### Y-flipping @@ -110,25 +117,30 @@ GLCanvas(.., flipY = true) ``` ### OpenGL profile -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. +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. ```kotlin -GLCanvas(.., profile = GLProfile.Core) -GLCanvas(.., profile = GLProfile.Compatibility) +GLCanvas(.., profile = GLProfile.CORE) +GLCanvas(.., profile = GLProfile.COMPATIBILITY) ``` -### 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. +### 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
(Keep in mind that the update may be triggered by resizing or other commands from JavaFX) | +| \> 0 | Update with desired FPS | ```kotlin -import com.huskerdev.openglfx.canvas.GLCanvasAnimator +// In constructor +val canvas = GLCanvas(..., fps = 30) -canvas.animator = GLCanvasAnimator(60.0) -canvas.animator = GLCanvasAnimator(GLCanvasAnimator.UNLIMITED_FPS) // For maximum available FPS -canvas.animator = null // To remove animator +// Or at runtime +canvas.fps = 40 ``` Don't forget to disable VSync before JavaFX initialization if you want to get FPS more than monitor's frequency. @@ -144,80 +156,78 @@ val fbo = GLImageManager.toGL(image) val image = GLImageManager.fromGL(fbo, width, height) ``` -### RenderDoc -```openglfx``` supports RenderDoc integration. Unfortunately, java and javaFX limit how this tool can be used, so the following features have been made. +### RenderDoc & NSight +```openglfx``` supports RenderDoc integration. +To use it, you need to set `externalWindow` in GLCanvas constructor to `true`. -- You can take a screenshot of the following frame using the hotkey: -```kotlin -RenderDoc.bind(canvas) // F12 by default -// or -RenderDoc.bind(canvas, keyCode = KeyCode.F11) -``` +This will create a separate window with the rendered image, which you can connect to via RenderDoc or NSight. -- You can insert the **beginning** and **ending** of capturing into the code: -```kotlin -RenderDoc.startFrameCapture() -// Renders here... -RenderDoc.endFrameCapture() -``` +### LibGDX +To use in LibGDX project, you should create new module. -It is better not to mix these two recording methods. +Minimal `build.gradle` example: +```groovy +plugins { + id("org.jetbrains.kotlin.jvm") +} -To view a scene in the Renderdoc application, you need to select one of the processes. It may change depending on the launch settings. +sourceSets.main.resources.srcDirs += [ rootProject.file('assets').path ] -# Notes -- RenderDoc + Windows crashes the JVM. Workaround is described in ([#39](https://github.com/husker-dev/openglfx/issues/39)); -- JOGL can't initialize on macOS ([#22](https://github.com/husker-dev/openglfx/issues/22)). -> If you know how to fix that problem I would be very happy +dependencies { + implementation project(':core') + implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion" + implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" -### Reflection opens + // openglfx + api("com.huskerdev:openglfx-libgdx:4.1.0") + + // implementation(/* JavaFX */) + // implementation(/* LWJGL */) +} ``` ---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 +Instead of using GLCanvas, you should use `LibGDXCanvas`: +```kotlin +val canvas = LibGDXCanvas(Main()) // Main is ApplicationAdapter ``` +# Notes +- JOGL can't initialize on macOS ([#22](https://github.com/husker-dev/openglfx/issues/22)). +> If you know how to fix that problem I would be very happy + # Under the hood -- ### Offscreen GL - [husker-dev/offscreen-jgl](https://github.com/husker-dev/offscreen-jgl) is used to create offscreen thread-independent GL context on Windows, MacOS and Linux. +- ### grapl + [husker-dev/grapl](https://github.com/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](https://github.com/husker-dev/openglfx/blob/master/lwjgl/src/main/kotlin/com/huskerdev/openglfx/lwjgl/LWJGLExecutor.kt) | [JOGLFXExecutor.kt](https://github.com/husker-dev/openglfx/blob/master/jogl/src/main/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt) | + | Class | [LWJGLExecutor.kt](https://github.com/husker-dev/openglfx/blob/master/modules/lwjgl/kotlin/com/huskerdev/openglfx/lwjgl/LWJGLExecutor.kt) | [JOGLFXExecutor.kt](https://github.com/husker-dev/openglfx/blob/master/modules/jogl/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt) | | Instance | LWJGL_MODULE | JOGL_MODULE | - If you want to add new OpenGL library, just create your implementation of [GLExecutor](https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/core/GLExecutor.kt) and use it as existing one: ```OpenGLCanvas.create(YOUR_EXECUTOR_INSTANCE)```. + If you want to add new OpenGL library, just create your implementation of [GLExecutor](https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/GLExecutor.kt) 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. - - [BlitCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/BlitCanvasImpl.kt - [SharedCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/SharedCanvasImpl.kt - [NVDXInteropCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/NVDXInteropCanvasImpl.kt - [IOSurfaceCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/IOSurfaceCanvasImpl.kt - - [AsyncBlitCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/async/AsyncBlitCanvasImpl.kt - [AsyncSharedCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/async/AsyncSharedCanvasImpl.kt - [AsyncNVDXInteropCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/async/AsyncNVDXInteropCanvasImpl.kt - [AsyncIOSurfaceCanvasImpl]: https://github.com/husker-dev/openglfx/blob/master/core/src/main/kotlin/com/huskerdev/openglfx/canvas/implementations/async/AsyncIOSurfaceCanvasImpl.kt + To efficiently connect OpenGL and JavaFX, OpenGLFX uses some techniques based on OS and supported extensions. - | | Description | Sync implementation | Async implementation | - | ----------- | ----------- | ------------------- | -------------------- | - | Windows | [NV_DX_interop](https://www.khronos.org/registry/OpenGL/extensions/NV/WGL_NV_DX_interop.txt) is used to synchronize textures between DirectX from JavaFX and OpenGL. | [NVDXInteropCanvasImpl.kt][NVDXInteropCanvasImpl] | [AsyncNVDXInteropCanvasImpl.kt][AsyncNVDXInteropCanvasImpl] - | Linux | Creates context that is shared with JavaFX's one. After rendering, shared texture is displayed in JavaFX frame. | [SharedCanvasImpl.kt][SharedCanvasImpl] | [AsyncSharedCanvasImpl.kt][AsyncSharedCanvasImpl] - | macOS | IOSurface is used to create memory block in VRAM that can be used in different OpenGL contexts. | [IOSurfaceCanvasImpl.kt][IOSurfaceCanvasImpl] | [AsyncIOSurfaceCanvasImpl.kt][AsyncIOSurfaceCanvasImpl] - | Other | Copies ByteBuffer from ```glReadPixels``` to JavaFX texture | [BlitCanvasImpl.kt][BlitCanvasImpl] | [AsyncBlitCanvasImpl.kt][AsyncBlitCanvasImpl] + [BlitCanvas]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/BlitCanvas.kt + [ExternalObjectsCanvasFd]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasFd.kt + [ExternalObjectsCanvasWinD3D]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinD3D.kt + [ExternalObjectsCanvasWinES2]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinES2.kt + [IOSurface]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/IOSurface.kt + [WGLDXInteropCanvas]: https://github.com/husker-dev/openglfx/blob/master/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/WGLDXInteropCanvas.kt + + | | Description | Implementation | + |-------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| + | **Windows**
(that supports EXT_external_objects) | [EXT_external_objects_win32](https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects_win32.txt) is used to create shared DXGI texture between DirectX 9 and OpenGL. | [ExternalObjectsCanvasWinD3D.kt][ExternalObjectsCanvasWinD3D] | + | **Windows**
(that supports WGL_NV_DX_interop) | [NV_DX_interop](https://www.khronos.org/registry/OpenGL/extensions/NV/WGL_NV_DX_interop.txt) is used to synchronize textures between DirectX 9 and OpenGL. | [WGLDXInteropCanvas.kt][WGLDXInteropCanvas] | + | **Windows**
(es2 pipeline) | [EXT_external_objects_win32](https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects_win32.txt) is used to create chain with shared texture:
OpenGL <-> Vulkan <-> OpenGL | [ExternalObjectsCanvasWinES2.kt][ExternalObjectsCanvasWinES2] | + | **Linux** | [EXT_external_objects_fd](https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects_fd.txt) is used to create chain with shared texture:
OpenGL <-> Vulkan <-> OpenGL | [ExternalObjectsCanvasFd.kt][ExternalObjectsCanvasFd] | + | **macOS** | IOSurface is used to create memory block in VRAM that can be used in different OpenGL contexts. | [IOSurface.kt][IOSurface] | + | *Other* | Copies ByteBuffer from ```glReadPixels``` to JavaFX texture | [BlitCanvas.kt][BlitCanvas] | # Thanks to diff --git a/gradle.properties b/gradle.properties index df65d19..19251c2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ projectName=openglfx version=4.1.0 kotlinVersion=2.0.0 -graplVersion=2.2.0 +graplVersion=2.3.0 javafxVersion=20.0.2 lwjglVersion=3.3.2 lwjgl2Version=2.9.3 diff --git a/modules/core/canvas_old/BlitCanvasImpl.kt b/modules/core/canvas_old/BlitCanvasImpl.kt deleted file mode 100644 index a6b392d..0000000 --- a/modules/core/canvas_old/BlitCanvasImpl.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.GLFXUtils.Companion.dispose -import com.huskerdev.openglfx.internal.GLFXUtils.Companion.updateData -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.sun.prism.Graphics -import com.sun.prism.Texture -import java.nio.ByteBuffer -import java.util.concurrent.atomic.AtomicBoolean - - -open class BlitCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private var needsRepaint = AtomicBoolean(false) - - private var resultSize = Size() - - private lateinit var fbo: Framebuffer - private lateinit var msaaFBO: MultiSampledFramebuffer - - private lateinit var context: GLContext - - private lateinit var dataBuffer: ByteBuffer - private lateinit var texture: Texture - - override fun renderContent(g: Graphics){ - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if(!::context.isInitialized){ - context = GLContext.create(0L, GLProfile.CORE) - context.makeCurrent() - executor.initGLFunctions() - canvas.fireInitEvent() - } - context.makeCurrent() - - resultSize.executeOnDifferenceWith(scaledSize){ width, height -> - resizeTextures(width, height) - canvas.fireReshapeEvent(width, height) - glViewport(0, 0, resultSize.width, resultSize.height) - } - canvas.fireRenderEvent(if(msaa != 0) msaaFBO.id else fbo.id) - - if(msaa != 0) - msaaFBO.blitTo(fbo) - fbo.readPixels(0, 0, resultSize.width, resultSize.height, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, dataBuffer) - texture.updateData(dataBuffer, resultSize.width, resultSize.height) - - drawResultTexture(g, texture) - super.renderContent(g) - } - - private fun resizeTextures(width: Int, height: Int) { - if(::fbo.isInitialized){ - texture.dispose() - dataBuffer.dispose() - fbo.delete() - if(msaa != 0) msaaFBO.delete() - } - - fbo = Framebuffer(width, height) - if(msaa != 0) { - msaaFBO = MultiSampledFramebuffer(msaa, resultSize.width, resultSize.height) - msaaFBO.bindFramebuffer() - } else fbo.bindFramebuffer() - - dataBuffer = ByteBuffer.allocateDirect(width * height * 4) - texture = GLFXUtils.createPermanentFXTexture(width, height) - } - - override fun requestRepaint() = needsRepaint.set(true) - - override fun timerTick() { - if(needsRepaint.getAndSet(false)) - makeDirty() - } - - override fun dispose() { - super.dispose() - GLFXUtils.runOnRenderThread { - context.makeCurrent() - canvas.fireDisposeEvent() - - if(::dataBuffer.isInitialized) dataBuffer.dispose() - if(::texture.isInitialized) texture.dispose() - if(::context.isInitialized) context.delete() - } - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/IOSurfaceCanvasImpl.kt b/modules/core/canvas_old/IOSurfaceCanvasImpl.kt deleted file mode 100644 index 2a27589..0000000 --- a/modules/core/canvas_old/IOSurfaceCanvasImpl.kt +++ /dev/null @@ -1,167 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glBindTexture -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glGenTextures -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.Size - -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.iosurface.IOSurface -import com.huskerdev.openglfx.internal.shaders.FXAAShader -import com.sun.prism.Graphics -import com.sun.prism.Texture -import com.sun.prism.es2.esTextureId -import java.util.concurrent.atomic.AtomicBoolean - -open class IOSurfaceCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile) { - - private lateinit var ioSurface: IOSurface - private lateinit var fxTexture: Texture - - private val drawSize = Size() - - private lateinit var fboFX: Framebuffer - private lateinit var sharedFboFX: Framebuffer - private lateinit var sharedFboGL: Framebuffer - private var msaaFBO: MultiSampledFramebuffer? = null - - private lateinit var fxContext: GLContext - private lateinit var fxWrapperContext: GLContext - private lateinit var context: GLContext - - private var needsRepaint = AtomicBoolean(false) - - private val fxaaShader by lazy { FXAAShader() } - - override fun renderContent(g: Graphics) { - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if(!::context.isInitialized){ - fxContext = GLContext.current() - fxWrapperContext = GLContext.create(fxContext, profile) - context = GLContext.create(0, profile) - context.makeCurrent() - executor.initGLFunctions() - } - context.makeCurrent() - - if(drawSize != scaledSize || - msaa != (msaaFBO?.requestedSamples ?: 0) - ){ - scaledSize.copyTo(drawSize) - updateFramebufferSize(drawSize.width, drawSize.height) - canvas.fireReshapeEvent(drawSize.width, drawSize.height) - } - - glViewport(0, 0, drawSize.width, drawSize.height) - canvas.fireRenderEvent(msaaFBO?.id ?: sharedFboGL.id) - msaaFBO?.blitTo(sharedFboGL) - glFinish() - - fxWrapperContext.makeCurrent() - glViewport(0, 0, drawSize.width, drawSize.height) - sharedFboFX.blitTo(fboFX) - if(fxaa) fxaaShader.apply(fboFX, fboFX) - glFinish() - fxContext.makeCurrent() - - drawResultTexture(g, fxTexture) - } - - private fun updateFramebufferSize(width: Int, height: Int){ - if(::ioSurface.isInitialized) - ioSurface.dispose() - ioSurface = IOSurface(width, height) - - // Create JavaFX texture - fxContext.makeCurrent() - if(::fxTexture.isInitialized) - fxTexture.dispose() - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - - fxWrapperContext.makeCurrent() - if(::fboFX.isInitialized){ - fboFX.delete() - sharedFboFX.delete() - } - - // Create FX-side shared texture - val ioFXTexture = glGenTextures() - glBindTexture(GL_TEXTURE_RECTANGLE, ioFXTexture) - ioSurface.cglTexImageIOSurface2D(fxWrapperContext, - GL_TEXTURE_RECTANGLE, - GL_RGBA, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, 0) - glBindTexture(GL_TEXTURE_RECTANGLE, 0) - - // Create JavaFX buffers - sharedFboFX = Framebuffer(width, height, existingTexture = ioFXTexture, existingTextureType = GL_TEXTURE_RECTANGLE) - fboFX = Framebuffer(width, height, existingTexture = fxTexture.esTextureId) - - // Create GL-side shared texture - context.makeCurrent() - if(::sharedFboGL.isInitialized){ - sharedFboGL.delete() - msaaFBO?.delete() - } - - val ioGLTexture = glGenTextures() - glBindTexture(GL_TEXTURE_RECTANGLE, ioGLTexture) - ioSurface.cglTexImageIOSurface2D(context, - GL_TEXTURE_RECTANGLE, - GL_RGBA, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, 0) - glBindTexture(GL_TEXTURE_RECTANGLE, 0) - - // Create GL buffers - sharedFboGL = Framebuffer(width, height, existingTexture = ioGLTexture, existingTextureType = GL_TEXTURE_RECTANGLE) - - // Create multi-sampled framebuffer - if(msaa != 0) { - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO?.bindFramebuffer() - } else { - msaaFBO = null - sharedFboGL.bindFramebuffer() - } - } - - override fun requestRepaint() = needsRepaint.set(true) - - override fun timerTick() { - if(needsRepaint.getAndSet(false)) - makeDirty() - } - - override fun dispose() { - super.dispose() - GLFXUtils.runOnRenderThread { - context.makeCurrent() - canvas.fireDisposeEvent() - fxContext.makeCurrent() - - if(::sharedFboFX.isInitialized) sharedFboFX.delete() - if(::fboFX.isInitialized) fboFX.delete() - - if(::fxTexture.isInitialized) fxTexture.dispose() - if(::ioSurface.isInitialized) ioSurface.dispose() - - if(::context.isInitialized) context.delete() - } - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/NVDXInteropCanvasImpl.kt b/modules/core/canvas_old/NVDXInteropCanvasImpl.kt deleted file mode 100644 index 248efa5..0000000 --- a/modules/core/canvas_old/NVDXInteropCanvasImpl.kt +++ /dev/null @@ -1,126 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.d3d9.D3D9Device -import com.huskerdev.openglfx.internal.d3d9.D3D9Texture -import com.huskerdev.openglfx.internal.d3d9.NVDXInterop -import com.huskerdev.openglfx.internal.d3d9.NVDXInterop.Companion.interopDevice -import com.huskerdev.openglfx.internal.d3d9.WGL_ACCESS_WRITE_DISCARD_NV -import com.sun.prism.Graphics -import com.sun.prism.Texture -import com.sun.prism.d3d.d3dTextureResource -import java.util.concurrent.atomic.AtomicBoolean - - -open class NVDXInteropCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private var lastSize = Size() - - private var needsRepaint = AtomicBoolean(false) - - private lateinit var fbo: Framebuffer - private lateinit var msaaFBO: MultiSampledFramebuffer - - private lateinit var context: GLContext - private val fxDevice = D3D9Device.jfx - - private lateinit var fxD3DTexture: D3D9Texture - private lateinit var fxTexture: Texture - - private lateinit var interopObject: NVDXInterop.NVDXObject - - override fun renderContent(g: Graphics) { - if(width == 0.0 || height == 0.0) - return - - if(!::context.isInitialized){ - context = GLContext.create(0, profile) - context.makeCurrent() - executor.initGLFunctions() - } - context.makeCurrent() - - lastSize.executeOnDifferenceWith(scaledSize) { width, height -> - updateFramebufferSize(width, height) - - interopObject.lock() - canvas.fireReshapeEvent(width, height) - } - interopObject.lock() - - glViewport(0, 0, lastSize.width, lastSize.height) - canvas.fireRenderEvent(if(msaa != 0) msaaFBO.id else fbo.id) - if(msaa != 0) - msaaFBO.blitTo(fbo) - - interopObject.unlock() - drawResultTexture(g, fxTexture) - } - - private fun updateFramebufferSize(width: Int, height: Int) { - if (::fbo.isInitialized) { - interopObject.dispose() - fxTexture.dispose() - - fbo.delete() - if(msaa != 0) msaaFBO.delete() - } - - // Create GL texture - fbo = Framebuffer(width, height) - fbo.bindFramebuffer() - - // Create multi-sampled framebuffer - if(msaa != 0) { - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO.bindFramebuffer() - } - - // Create and register D3D9 shared texture - fxD3DTexture = fxDevice.createTexture(width, height) - NVDXInterop.linkShareHandle(fxD3DTexture.handle, fxD3DTexture.sharedHandle) - - // Create default JavaFX texture and replace a native handle with custom one. - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - D3D9Device.replaceD3DTextureInResource(fxTexture.d3dTextureResource, fxD3DTexture.handle) - - // Create interop texture - interopObject = interopDevice.registerObject(fxD3DTexture.handle, fbo.texture, - GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV) - - // For some reason the context resets by this time, so make it current again. - context.makeCurrent() - } - - override fun requestRepaint() = needsRepaint.set(true) - - override fun timerTick() { - if(needsRepaint.getAndSet(false)) - makeDirty() - } - - override fun dispose() { - super.dispose() - GLFXUtils.runOnRenderThread { - context.makeCurrent() - canvas.fireDisposeEvent() - - if(::interopObject.isInitialized) interopObject.dispose() - if(::fxTexture.isInitialized) fxTexture.dispose() - if(::context.isInitialized) context.delete() - } - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/SharedCanvasImpl.kt b/modules/core/canvas_old/SharedCanvasImpl.kt deleted file mode 100644 index 780ac7b..0000000 --- a/modules/core/canvas_old/SharedCanvasImpl.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.sun.prism.Graphics -import com.sun.prism.Texture -import com.sun.prism.es2.esTextureId -import java.util.concurrent.atomic.AtomicBoolean - -open class SharedCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private var lastSize = Size() - - private lateinit var context: GLContext - private lateinit var fxContext: GLContext - - private lateinit var fbo: Framebuffer - private lateinit var msaaFBO: MultiSampledFramebuffer - - private lateinit var fxTexture: Texture - - private var needsRepaint = AtomicBoolean(false) - - override fun renderContent(g: Graphics) { - if (!::context.isInitialized) { - fxContext = GLContext.current() - context = GLContext.create(fxContext, GLProfile.CORE) - executor.initGLFunctions() - } - context.makeCurrent() - - lastSize.executeOnDifferenceWith(scaledSize, ::updateFramebufferSize, canvas::fireReshapeEvent) - - glViewport(0, 0, lastSize.width, lastSize.height) - canvas.fireRenderEvent(if(msaa != 0) msaaFBO.id else fbo.id) - if(msaa != 0) - msaaFBO.blitTo(fbo) - - glFinish() - fxContext.makeCurrent() - - drawResultTexture(g, fxTexture) - } - - private fun updateFramebufferSize(width: Int, height: Int) { - if(::fbo.isInitialized){ - fbo.delete() - if(msaa != 0) msaaFBO.delete() - } - - fxContext.makeCurrent() - // Create JavaFX texture - if(::fxTexture.isInitialized) - fxTexture.dispose() - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - context.makeCurrent() - - // Create framebuffer that connected to JavaFX's texture - fbo = Framebuffer(width, height, existingTexture = fxTexture.esTextureId) - fbo.bindFramebuffer() - - // Create multi-sampled framebuffer - if(msaa != 0){ - msaaFBO = MultiSampledFramebuffer(msaa, lastSize.width, lastSize.height) - msaaFBO.bindFramebuffer() - } - } - - override fun requestRepaint() = needsRepaint.set(true) - - override fun timerTick() { - if(needsRepaint.getAndSet(false)) - makeDirty() - } - - override fun dispose() { - super.dispose() - GLFXUtils.runOnRenderThread { - context.makeCurrent() - canvas.fireDisposeEvent() - fxContext.makeCurrent() - - if(::fxTexture.isInitialized) fxTexture.dispose() - if(::context.isInitialized) context.delete() - } - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/async/AsyncBlitCanvasImpl.kt b/modules/core/canvas_old/async/AsyncBlitCanvasImpl.kt deleted file mode 100644 index 2b8ed66..0000000 --- a/modules/core/canvas_old/async/AsyncBlitCanvasImpl.kt +++ /dev/null @@ -1,177 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old.async - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.* -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.GLFXUtils.Companion.dispose -import com.huskerdev.openglfx.internal.GLFXUtils.Companion.updateData -import com.huskerdev.openglfx.internal.shaders.PassthroughShader -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.shaders.FXAAShader -import com.sun.prism.Graphics -import com.sun.prism.Texture -import java.nio.ByteBuffer -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.concurrent.thread - -open class AsyncBlitCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private val paintLock = Object() - private val blitLock = Object() - - private var needsBlit = AtomicBoolean(false) - - private var drawSize = Size() - private var transferSize = Size() - private var resultSize = Size() - - private lateinit var fbo: Framebuffer - private var msaaFBO: MultiSampledFramebuffer? = null - private lateinit var transferFBO: Framebuffer - private lateinit var resultFBO: Framebuffer - - private lateinit var context: GLContext - private lateinit var contextWrapper: GLContext - private lateinit var resultContext: GLContext - - private lateinit var dataBuffer: ByteBuffer - private lateinit var texture: Texture - - private val passthroughShader by lazy { PassthroughShader() } - private val fxaaShader by lazy { FXAAShader() } - - private fun initializeThread(){ - context = GLContext.create(0L, profile) - contextWrapper = GLContext.create(context, profile) - resultContext = GLContext.create(context, profile) - - thread(isDaemon = true) { - context.makeCurrent() - executor.initGLFunctions() - canvas.fireInitEvent() - - while(!disposed){ - paint() - synchronized(blitLock) { - transferSize.executeOnDifferenceWith(drawSize, ::resizeTransferFramebuffer) - fbo.blitTo(transferFBO) - glFinish() - } - needsBlit.set(true) - - synchronized(paintLock){ - if(!disposed) paintLock.wait() - } - } - - // Dispose - canvas.fireDisposeEvent() - GLContext.clear() - GLFXUtils.runOnRenderThread { - if (::texture.isInitialized) texture.dispose() - if (::dataBuffer.isInitialized) dataBuffer.dispose() - context.delete() - resultContext.delete() - } - } - } - - private fun paint(){ - if(drawSize != scaledSize || - msaa != (msaaFBO?.requestedSamples ?: 0) - ){ - scaledSize.copyTo(drawSize) - resizeDrawFramebuffer(drawSize.width, drawSize.height) - canvas.fireReshapeEvent(drawSize.width, drawSize.height) - } - - glViewport(0, 0, drawSize.width, drawSize.height) - canvas.fireRenderEvent(msaaFBO?.id ?: fbo.id) - msaaFBO?.blitTo(fbo) - } - - override fun renderContent(g: Graphics){ - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if(!this::context.isInitialized) - initializeThread() - - if (needsBlit.getAndSet(false)) { - resultContext.makeCurrent() - synchronized(blitLock){ - resultSize.executeOnDifferenceWith(transferSize) { width, height -> - resizeResultTexture(width, height) - glViewport(0, 0, width, height) - } - (if(fxaa) fxaaShader else passthroughShader).apply(transferFBO, resultFBO) - resultFBO.readPixels(0, 0, resultSize.width, resultSize.height, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, dataBuffer) - texture.updateData(dataBuffer, resultSize.width, resultSize.height) - } - } - if(::texture.isInitialized) - drawResultTexture(g, texture) - } - - private fun resizeDrawFramebuffer(width: Int, height: Int) { - if(::fbo.isInitialized){ - fbo.delete() - msaaFBO?.delete() - } - - fbo = Framebuffer(width, height) - if(msaa > 0) { - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO?.bindFramebuffer() - } else { - msaaFBO = null - fbo.bindFramebuffer() - } - } - - private fun resizeTransferFramebuffer(width: Int, height: Int){ - if(::transferFBO.isInitialized) - transferFBO.delete() - transferFBO = Framebuffer(width, height) - } - - private fun resizeResultTexture(width: Int, height: Int) { - if(::dataBuffer.isInitialized) { - dataBuffer.dispose() - texture.dispose() - resultFBO.delete() - } - dataBuffer = ByteBuffer.allocateDirect(width * height * 4) - texture = GLFXUtils.createPermanentFXTexture(width, height) - resultFBO = Framebuffer(width, height) - } - - override fun requestRepaint() { - synchronized(paintLock){ - paintLock.notifyAll() - } - } - - override fun timerTick() { - if(needsBlit.get()) - makeDirty() - } - - override fun dispose() { - super.dispose() - requestRepaint() - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/async/AsyncIOSurfaceCanvasImpl.kt b/modules/core/canvas_old/async/AsyncIOSurfaceCanvasImpl.kt deleted file mode 100644 index 5e162da..0000000 --- a/modules/core/canvas_old/async/AsyncIOSurfaceCanvasImpl.kt +++ /dev/null @@ -1,211 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old.async - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.* -import com.huskerdev.openglfx.GLExecutor.Companion.glBindTexture -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glGenTextures -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.iosurface.IOSurface -import com.huskerdev.openglfx.internal.shaders.FXAAShader -import com.sun.prism.Graphics -import com.sun.prism.Texture -import com.sun.prism.es2.esTextureId -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.concurrent.thread - -open class AsyncIOSurfaceCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile) { - - private val paintLock = Object() - private val blitLock = Object() - - private var drawSize = Size() - private var interopTextureSize = Size() - private var resultSize = Size() - - private lateinit var ioSurface: IOSurface - private lateinit var fxTexture: Texture - - private lateinit var sharedFboFX: Framebuffer - private lateinit var sharedFboGL: Framebuffer - private lateinit var fboFX: Framebuffer - private lateinit var fboGL: Framebuffer - private var msaaFBO: MultiSampledFramebuffer? = null - - private lateinit var fxContext: GLContext - private lateinit var fxContextWrapper: GLContext - private lateinit var context: GLContext - - private var needsBlit = AtomicBoolean(false) - - private val fxaaShader by lazy { FXAAShader() } - - private fun initializeThread(){ - fxContext = GLContext.current() - fxContextWrapper = GLContext.create(fxContext, GLProfile.COMPATIBILITY) - - thread(isDaemon = true) { - context = GLContext.create(0, profile) - context.makeCurrent() - executor.initGLFunctions() - - while (!disposed){ - paint() - synchronized(blitLock) { - interopTextureSize.executeOnDifferenceWith(drawSize, ::updateSurfaceSize) - fboGL.blitTo(sharedFboGL) - } - needsBlit.set(true) - - synchronized(paintLock){ - paintLock.wait() - } - } - - // Dispose - canvas.fireDisposeEvent() - GLContext.clear() - GLFXUtils.runOnRenderThread { - if(::sharedFboFX.isInitialized) sharedFboFX.delete() - if(::fboFX.isInitialized) fboFX.delete() - - if(::fxTexture.isInitialized) fxTexture.dispose() - if(::ioSurface.isInitialized) ioSurface.dispose() - - if(::context.isInitialized) context.delete() - } - } - } - - private fun paint(){ - if(drawSize != scaledSize || - msaa != (msaaFBO?.requestedSamples ?: 0) - ){ - scaledSize.copyTo(drawSize) - updateFramebufferSize(drawSize.width, drawSize.height) - canvas.fireReshapeEvent(drawSize.width, drawSize.height) - } - - glViewport(0, 0, drawSize.width, drawSize.height) - canvas.fireRenderEvent(msaaFBO?.id ?: fboGL.id) - msaaFBO?.blitTo(fboGL) - } - - override fun renderContent(g: Graphics) { - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if(!::fxContext.isInitialized) - initializeThread() - - if (needsBlit.getAndSet(false)) { - synchronized(blitLock){ - resultSize.executeOnDifferenceWith(interopTextureSize) { width, height -> - updateResultTextureSize(width, height) - fxContextWrapper.makeCurrent() - glViewport(0, 0, width, height) - } - fxContextWrapper.makeCurrent() - // We can't skip this blit, so blit at first, then apply shader - sharedFboFX.blitTo(fboFX) - if(fxaa) fxaaShader.apply(fboFX, fboFX) - glFinish() - } - fxContext.makeCurrent() - } - if(this::fxTexture.isInitialized) - drawResultTexture(g, fxTexture) - } - - private fun updateFramebufferSize(width: Int, height: Int) { - if (::fboGL.isInitialized) { - fboGL.delete() - msaaFBO?.delete() - } - - // Create simple framebuffer - fboGL = Framebuffer(width, height) - - // Create multi-sampled framebuffer - if(msaa != 0) { - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO?.bindFramebuffer() - } else { - msaaFBO = null - fboGL.bindFramebuffer() - } - } - - private fun updateSurfaceSize(width: Int, height: Int){ - if (::ioSurface.isInitialized) { - sharedFboGL.delete() - ioSurface.dispose() - } - ioSurface = IOSurface(width, height) - - // Create GL-side shared texture - val ioGLTexture = glGenTextures() - glBindTexture(GL_TEXTURE_RECTANGLE, ioGLTexture) - ioSurface.cglTexImageIOSurface2D(context, - GL_TEXTURE_RECTANGLE, - GL_RGBA, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, 0) - glBindTexture(GL_TEXTURE_RECTANGLE, 0) - sharedFboGL = Framebuffer(width, height, existingTexture = ioGLTexture, existingTextureType = GL_TEXTURE_RECTANGLE) - } - - private fun updateResultTextureSize(width: Int, height: Int){ - // Create JavaFX texture - if (::fxTexture.isInitialized) - fxTexture.dispose() - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - - fxContextWrapper.makeCurrent() - if(::fboFX.isInitialized){ - fboFX.delete() - sharedFboFX.delete() - } - - // Create FX-side shared texture - val ioFXTexture = glGenTextures() - glBindTexture(GL_TEXTURE_RECTANGLE, ioFXTexture) - ioSurface.cglTexImageIOSurface2D(fxContextWrapper, - GL_TEXTURE_RECTANGLE, - GL_RGBA, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, 0) - glBindTexture(GL_TEXTURE_RECTANGLE, 0) - - // Create JavaFX buffers - sharedFboFX = Framebuffer(width, height, existingTexture = ioFXTexture, existingTextureType = GL_TEXTURE_RECTANGLE) - fboFX = Framebuffer(width, height, existingTexture = fxTexture.esTextureId) - } - - override fun requestRepaint() { - synchronized(paintLock){ - paintLock.notifyAll() - } - } - - override fun timerTick() { - if(needsBlit.get()) - makeDirty() - } - - override fun dispose() { - super.dispose() - requestRepaint() - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/async/AsyncNVDXInteropCanvasImpl.kt b/modules/core/canvas_old/async/AsyncNVDXInteropCanvasImpl.kt deleted file mode 100644 index a9687d7..0000000 --- a/modules/core/canvas_old/async/AsyncNVDXInteropCanvasImpl.kt +++ /dev/null @@ -1,195 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old.async - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.GLExecutor -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.GL_TEXTURE_2D -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.* -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.shaders.PassthroughShader -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.d3d9.D3D9Device -import com.huskerdev.openglfx.internal.d3d9.D3D9Texture -import com.huskerdev.openglfx.internal.d3d9.NVDXInterop -import com.huskerdev.openglfx.internal.d3d9.NVDXInterop.Companion.interopDevice -import com.huskerdev.openglfx.internal.d3d9.WGL_ACCESS_WRITE_DISCARD_NV -import com.huskerdev.openglfx.internal.shaders.FXAAShader -import com.sun.prism.Graphics -import com.sun.prism.Texture -import com.sun.prism.d3d.d3dTextureResource -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.concurrent.thread - -open class AsyncNVDXInteropCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private val paintLock = Object() - private val blitLock = Object() - - private var drawSize = Size() - private var interopTextureSize = Size() - private var resultSize = Size() - - private lateinit var resultFBO: Framebuffer - private lateinit var interThreadFBO: Framebuffer - private lateinit var fbo: Framebuffer - private var msaaFBO: MultiSampledFramebuffer? = null - - private lateinit var context: GLContext - private lateinit var resultContext: GLContext - private val fxDevice = D3D9Device.jfx - - private lateinit var fxD3DTexture: D3D9Texture - private lateinit var fxTexture: Texture - - private var needsBlit = AtomicBoolean(false) - private lateinit var interopObject: NVDXInterop.NVDXObject - - private val passthroughShader by lazy { PassthroughShader() } - private val fxaaShader by lazy { FXAAShader() } - - private fun initializeGLThread(){ - resultContext = GLContext.create(0, profile) - - thread(isDaemon = true) { - context = GLContext.create(resultContext.handle, profile) - context.makeCurrent() - executor.initGLFunctions() - - while(!disposed){ - paint() - synchronized(blitLock) { - interopTextureSize.executeOnDifferenceWith(drawSize, ::updateInterTextureSize) - fbo.blitTo(interThreadFBO) - glFinish() - } - needsBlit.set(true) - - synchronized(paintLock){ - if(!disposed) paintLock.wait() - } - } - - // Dispose - canvas.fireDisposeEvent() - GLContext.clear() - GLFXUtils.runOnRenderThread { - if(::fxTexture.isInitialized) fxTexture.dispose() - if(::interopObject.isInitialized) interopObject.dispose() - context.delete() - resultContext.delete() - } - } - } - - private fun paint(){ - if(drawSize != scaledSize || - msaa != (msaaFBO?.requestedSamples ?: 0) - ){ - scaledSize.copyTo(drawSize) - updateFramebufferSize(drawSize.width, drawSize.height) - canvas.fireReshapeEvent(drawSize.width, drawSize.height) - } - - glViewport(0, 0, drawSize.width, drawSize.height) - canvas.fireRenderEvent(msaaFBO?.id ?: fbo.id) - msaaFBO?.blitTo(fbo) - } - - private fun updateFramebufferSize(width: Int, height: Int) { - if (::fbo.isInitialized) { - fbo.delete() - msaaFBO?.delete() - } - - // Create GL texture - fbo = Framebuffer(width, height) - - // Create multi-sampled framebuffer - if(msaa > 0) { - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO!!.bindFramebuffer() - }else { - msaaFBO = null - fbo.bindFramebuffer() - } - } - - private fun updateInterTextureSize(width: Int, height: Int){ - if(::interThreadFBO.isInitialized) - interThreadFBO.delete() - interThreadFBO = Framebuffer(width, height) - } - - override fun renderContent(g: Graphics) { - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if(!::resultContext.isInitialized) - initializeGLThread() - - if (needsBlit.getAndSet(false)) { - resultContext.makeCurrent() - - synchronized(blitLock){ - resultSize.executeOnDifferenceWith(interopTextureSize){ width, height -> - updateInteropTextureSize(width, height) - glViewport(0, 0, width, height) - } - - interopObject.lock() - (if(fxaa) fxaaShader else passthroughShader).apply(interThreadFBO, resultFBO) - interopObject.unlock() - } - } - if(this::fxTexture.isInitialized) - drawResultTexture(g, fxTexture) - } - - private fun updateInteropTextureSize(width: Int, height: Int){ - if(this::fxTexture.isInitialized) { - interopObject.dispose() - resultFBO.delete() - fxTexture.dispose() - } - - resultFBO = Framebuffer(width, height) - resultFBO.bindFramebuffer() - - // Create and register D3D9 shared texture - fxD3DTexture = fxDevice.createTexture(width, height) - NVDXInterop.linkShareHandle(fxD3DTexture.handle, fxD3DTexture.sharedHandle) - - // Create default JavaFX texture and replace a native handle with custom one. - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - D3D9Device.replaceD3DTextureInResource(fxTexture.d3dTextureResource, fxD3DTexture.handle) - - // Create interop texture - interopObject = interopDevice.registerObject(fxD3DTexture.handle, resultFBO.texture, - GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV) - } - - override fun requestRepaint() { - synchronized(paintLock){ - paintLock.notifyAll() - } - } - - override fun timerTick() { - if(needsBlit.get()) - makeDirty() - } - - override fun dispose() { - super.dispose() - requestRepaint() - } -} \ No newline at end of file diff --git a/modules/core/canvas_old/async/AsyncSharedCanvasImpl.kt b/modules/core/canvas_old/async/AsyncSharedCanvasImpl.kt deleted file mode 100644 index b212f7b..0000000 --- a/modules/core/canvas_old/async/AsyncSharedCanvasImpl.kt +++ /dev/null @@ -1,181 +0,0 @@ -package com.huskerdev.openglfx.internal.canvas_old.async - -import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile -import com.huskerdev.openglfx.GLExecutor -import com.huskerdev.openglfx.GLExecutor.Companion.glFinish -import com.huskerdev.openglfx.GLExecutor.Companion.glViewport -import com.huskerdev.openglfx.canvas.GLCanvas -import com.huskerdev.openglfx.internal.* -import com.huskerdev.openglfx.internal.GLFXUtils -import com.huskerdev.openglfx.internal.shaders.PassthroughShader -import com.huskerdev.openglfx.internal.Size -import com.huskerdev.openglfx.internal.fbo.Framebuffer -import com.huskerdev.openglfx.internal.fbo.MultiSampledFramebuffer -import com.huskerdev.openglfx.internal.shaders.FXAAShader -import com.sun.prism.* -import com.sun.prism.es2.esTextureId -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.concurrent.thread - -open class AsyncSharedCanvasImpl( - canvas: GLCanvas, - executor: GLExecutor, - profile: GLProfile -): NGGLCanvas(canvas, executor, profile){ - - private val paintLock = Object() - private val blitLock = Object() - - private var drawSize = Size() - private var transferSize = Size() - private var resultSize = Size() - - private lateinit var context: GLContext - private lateinit var fxContextWrapper: GLContext - private lateinit var fxContext: GLContext - - private lateinit var fbo: Framebuffer - private var msaaFBO: MultiSampledFramebuffer? = null - private lateinit var transferFBO: Framebuffer - private lateinit var resultFBO: Framebuffer - - private lateinit var fxTexture: Texture - - private var needsBlit = AtomicBoolean(false) - - private val passthroughShader by lazy { PassthroughShader() } - private val fxaaShader by lazy { FXAAShader() } - - private fun initializeThread(){ - fxContext = GLContext.current() - fxContextWrapper = GLContext.create(fxContext, profile) - context = GLContext.create(fxContext, profile) - - thread(isDaemon = true) { - context.makeCurrent() - executor.initGLFunctions() - - while(!disposed){ - paint() - synchronized(blitLock) { - transferSize.executeOnDifferenceWith(drawSize, ::updateTransferTextureSize) - fbo.blitTo(transferFBO) - glFinish() - } - needsBlit.set(true) - - synchronized(paintLock){ - if(!disposed) paintLock.wait() - } - } - - // Dispose - canvas.fireDisposeEvent() - GLContext.clear() - GLFXUtils.runOnRenderThread { - if(::fxTexture.isInitialized) fxTexture.dispose() - - if(::resultFBO.isInitialized) resultFBO.delete() - if(::transferFBO.isInitialized) transferFBO.delete() - if(::fbo.isInitialized) fbo.delete() - msaaFBO?.delete() - - context.delete() - fxContextWrapper.delete() - fxContext.makeCurrent() - } - } - } - - private fun paint(){ - if(drawSize != scaledSize || - msaa != (msaaFBO?.requestedSamples ?: 0) - ){ - scaledSize.copyTo(drawSize) - updateRenderFramebufferSize(drawSize.width, drawSize.height) - canvas.fireReshapeEvent(drawSize.width, drawSize.height) - } - - glViewport(0, 0, drawSize.width, drawSize.height) - canvas.fireRenderEvent(msaaFBO?.id ?: fbo.id) - msaaFBO?.blitTo(fbo) - } - - override fun renderContent(g: Graphics) { - if(scaledWidth == 0 || scaledHeight == 0 || disposed) - return - - if (!::context.isInitialized) - initializeThread() - - if (needsBlit.getAndSet(false)) { - fxContextWrapper.makeCurrent() - synchronized(blitLock){ - resultSize.executeOnDifferenceWith(transferSize) { width, height -> - updateResultFramebufferSize(width, height) - glViewport(0, 0, width, height) - } - (if(fxaa) fxaaShader else passthroughShader).apply(transferFBO, resultFBO) - } - fxContext.makeCurrent() - } - - if(this::fxTexture.isInitialized) - drawResultTexture(g, fxTexture) - } - - private fun updateResultFramebufferSize(width: Int, height: Int) { - if(::resultFBO.isInitialized) { - resultFBO.delete() - fxTexture.dispose() - } - - // Create JavaFX texture - fxTexture = GLFXUtils.createPermanentFXTexture(width, height) - - // Create framebuffer that connected to JavaFX's texture - resultFBO = Framebuffer(width, height, existingTexture = fxTexture.esTextureId) - } - - private fun updateTransferTextureSize(width: Int, height: Int) { - if(::transferFBO.isInitialized) - transferFBO.delete() - transferFBO = Framebuffer(width, height) - } - - private fun updateRenderFramebufferSize(width: Int, height: Int) { - if(::fbo.isInitialized){ - fbo.delete() - msaaFBO?.delete() - } - - // Create framebuffer - fbo = Framebuffer(width, height) - - // Create multi-sampled framebuffer - if(msaa > 0){ - msaaFBO = MultiSampledFramebuffer(msaa, width, height) - msaaFBO!!.bindFramebuffer() - } else { - msaaFBO = null - fbo.bindFramebuffer() - } - } - - override fun requestRepaint() { - synchronized(paintLock){ - paintLock.notifyAll() - } - } - - override fun timerTick() { - if(needsBlit.get()) - makeDirty() - } - - override fun dispose() { - super.dispose() - requestRepaint() - } -} \ No newline at end of file diff --git a/modules/core/kotlin/com/huskerdev/openglfx/GLExecutor.kt b/modules/core/kotlin/com/huskerdev/openglfx/GLExecutor.kt index ebaa1a2..b5ad97d 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/GLExecutor.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/GLExecutor.kt @@ -1,16 +1,11 @@ package com.huskerdev.openglfx import com.huskerdev.grapl.gl.GLContext -import com.huskerdev.grapl.gl.GLProfile import com.huskerdev.openglfx.canvas.GLCanvas import com.huskerdev.openglfx.canvas.events.GLDisposeEvent import com.huskerdev.openglfx.canvas.events.GLInitializeEvent import com.huskerdev.openglfx.canvas.events.GLRenderEvent import com.huskerdev.openglfx.canvas.events.GLReshapeEvent -import com.huskerdev.openglfx.internal.NGGLCanvas -import com.huskerdev.openglfx.internal.canvas.BlitCanvas -import com.huskerdev.openglfx.internal.canvas.ExternalObjectsCanvasWinD3D -import com.huskerdev.openglfx.internal.canvas.IOSurfaceCanvas import java.nio.* @@ -42,9 +37,8 @@ internal const val GL_STATIC_DRAW = 0x88E4 internal const val GL_TRIANGLE_STRIP = 0x0005 internal const val GL_COMPILE_STATUS = 0x8B81 - +@Suppress("unused") open class GLExecutor { - companion object { @JvmStatic val NONE_MODULE = object: GLExecutor(){} @@ -114,29 +108,18 @@ open class GLExecutor { } else nInitGLFunctions() } } - /* - open fun blitNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile): NGGLCanvas = - BlitCanvas(canvas, executor, profile) - - open fun sharedNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile): NGGLCanvas = - throw UnsupportedOperationException() - open fun interopNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile) = - ExternalObjectsCanvasWinD3D(canvas, executor, profile) + open fun createRenderEvent(canvas: GLCanvas, currentFps: Int, delta: Double, width: Int, height: Int, fbo: Int) = + GLRenderEvent(GLRenderEvent.ANY, currentFps, delta, width, height, fbo) - open fun ioSurfaceNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile): NGGLCanvas = - IOSurfaceCanvas(canvas, executor, profile) + open fun createReshapeEvent(canvas: GLCanvas, width: Int, height: Int) = + GLReshapeEvent(GLReshapeEvent.ANY, width, height) - */ + open fun createInitEvent(canvas: GLCanvas) = + GLInitializeEvent(GLInitializeEvent.ANY) - open fun createRenderEvent(canvas: GLCanvas, currentFps: Int, delta: Double, width: Int, height: Int, fbo: Int) - = GLRenderEvent(GLRenderEvent.ANY, currentFps, delta, width, height, fbo) - open fun createReshapeEvent(canvas: GLCanvas, width: Int, height: Int) - = GLReshapeEvent(GLReshapeEvent.ANY, width, height) - open fun createInitEvent(canvas: GLCanvas) - = GLInitializeEvent(GLInitializeEvent.ANY) - open fun createDisposeEvent(canvas: GLCanvas) - = GLDisposeEvent(GLDisposeEvent.ANY) + open fun createDisposeEvent(canvas: GLCanvas) = + GLDisposeEvent(GLDisposeEvent.ANY) open fun initGLFunctions() = loadBasicFunctionPointers() diff --git a/modules/core/kotlin/com/huskerdev/openglfx/canvas/GLCanvas.kt b/modules/core/kotlin/com/huskerdev/openglfx/canvas/GLCanvas.kt index bfb77e8..4f0e977 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/canvas/GLCanvas.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/canvas/GLCanvas.kt @@ -32,17 +32,13 @@ import kotlin.math.ceil * @param msaa Multisampling anti-aliasing quality: * - 0 – disabled (default); * - -1 – maximum available samples. - * @param fxaa Fast approximate anti-aliasing: - * - false – disabled (default); - * - true – enabled. */ open class GLCanvas @JvmOverloads constructor( val executor: GLExecutor, val profile: GLProfile = GLProfile.CORE, var flipY: Boolean = false, var msaa: Int = 0, - var fxaa: Boolean = false, - fps: Int = 0, + fps: Int = -1, val glDebug: Boolean = false, val swapBuffers: Int = 2, val interopType: GLInteropType = GLInteropType.auto, @@ -87,7 +83,7 @@ open class GLCanvas @JvmOverloads constructor( set(value) { field = value RegionHelper.getPeer(this).fps = - if(value > 0) value else GLFXUtils.getPulseDuration() + if(value >= 0) value else GLFXUtils.getPulseDuration() } init { @@ -112,6 +108,7 @@ open class GLCanvas @JvmOverloads constructor( * @param listener * @return true (specified by [java.util.Collection.add]) */ + @Suppress("unused") fun addOnRenderEvent(listener: Consumer) = onRender.add(listener) /** @@ -120,6 +117,7 @@ open class GLCanvas @JvmOverloads constructor( * @param listener consumer with GLReshapeEvent * @return true (specified by [java.util.Collection.add]) */ + @Suppress("unused") fun addOnReshapeEvent(listener: Consumer) = onReshape.add(listener) /** @@ -128,6 +126,7 @@ open class GLCanvas @JvmOverloads constructor( * @param listener consumer with GLDisposeEvent * @return true (specified by [java.util.Collection.add]) */ + @Suppress("unused") fun addOnDisposeEvent(listener: Consumer) = onDispose.add(listener) /** @@ -136,6 +135,7 @@ open class GLCanvas @JvmOverloads constructor( * @param listener consumer with GLInitializeEvent * @return true (specified by [java.util.Collection.add]) */ + @Suppress("unused") fun addOnInitEvent(listener: Consumer) = onInit.add(listener) diff --git a/modules/core/kotlin/com/huskerdev/openglfx/internal/NGGLCanvas.kt b/modules/core/kotlin/com/huskerdev/openglfx/internal/NGGLCanvas.kt index 3c8eea4..8408b11 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/internal/NGGLCanvas.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/internal/NGGLCanvas.kt @@ -6,7 +6,9 @@ import com.huskerdev.grapl.gl.GLContext import com.huskerdev.grapl.gl.GLProfile import com.huskerdev.grapl.gl.GLWindow import com.huskerdev.openglfx.GLExecutor +import com.huskerdev.openglfx.GLExecutor.Companion.glGetInteger import com.huskerdev.openglfx.GLExecutor.Companion.glViewport +import com.huskerdev.openglfx.GL_MAX_SAMPLES import com.huskerdev.openglfx.canvas.GLCanvas import com.huskerdev.openglfx.internal.canvas.BlitCanvas import com.huskerdev.openglfx.internal.canvas.ExternalObjectsCanvasWinD3D @@ -63,7 +65,6 @@ abstract class NGGLCanvas( val flipY by canvas::flipY val msaa by canvas::msaa - val fxaa by canvas::fxaa var fps = 0 @@ -106,7 +107,7 @@ abstract class NGGLCanvas( it.disposeFXResources() } } - if(externalWindow){ + if(externalWindow && this::window.isInitialized){ window.destroy() com.huskerdev.grapl.core.platform.Platform.current.peekMessages() } @@ -204,6 +205,7 @@ abstract class NGGLCanvas( protected fun createFramebufferForRender(width: Int, height: Int) = if(msaa > 0) Framebuffer.MultiSampled(width, height, msaa) + else if(msaa < 0) Framebuffer.MultiSampled(width, height, glGetInteger(GL_MAX_SAMPLES)) else Framebuffer.Default(width, height) } diff --git a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasFd.kt b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasFd.kt index 2941def..a643e06 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasFd.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasFd.kt @@ -32,14 +32,14 @@ open class ExternalObjectsCanvasFd( private val vk = VkExtMemory.createVk() override fun onRenderThreadInit() = Unit - override fun createSwapBuffer() = EGLImageSwapBuffer() + override fun createSwapBuffer() = ExternalObjectsSwapBuffer() override fun dispose() { super.dispose() vk.dispose() } - protected inner class EGLImageSwapBuffer: SwapBuffer() { + protected inner class ExternalObjectsSwapBuffer: SwapBuffer() { private lateinit var fbo: Framebuffer private lateinit var interopFBO: Framebuffer.Default private lateinit var externalImage: VkExtMemory.ExternalImage diff --git a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinD3D.kt b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinD3D.kt index 1f41648..e4f8dc0 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinD3D.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinD3D.kt @@ -36,10 +36,10 @@ open class ExternalObjectsCanvasWinD3D( d3d9Device = D3D9.Device() } - override fun createSwapBuffer() = DXGISwapBuffer() + override fun createSwapBuffer() = ExternalObjectsSwapBuffer() - protected inner class DXGISwapBuffer: SwapBuffer() { + protected inner class ExternalObjectsSwapBuffer: SwapBuffer() { private lateinit var fbo: Framebuffer private lateinit var interopFBO: Framebuffer.Default private lateinit var d3d9Texture: D3D9.Texture diff --git a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinES2.kt b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinES2.kt index 8ad8847..a58394b 100644 --- a/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinES2.kt +++ b/modules/core/kotlin/com/huskerdev/openglfx/internal/canvas/ExternalObjectsCanvasWinES2.kt @@ -33,14 +33,14 @@ open class ExternalObjectsCanvasWinES2( private val vk = VkExtMemory.createVk() override fun onRenderThreadInit() = Unit - override fun createSwapBuffer() = DXGISwapBuffer() + override fun createSwapBuffer() = ExternalObjectsSwapBuffer() override fun dispose() { super.dispose() vk.dispose() } - protected inner class DXGISwapBuffer: SwapBuffer() { + protected inner class ExternalObjectsSwapBuffer: SwapBuffer() { private lateinit var fbo: Framebuffer private lateinit var interopFBO: Framebuffer.Default private lateinit var externalImage: VkExtMemory.ExternalImage diff --git a/modules/jogl/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt b/modules/jogl/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt index cf39b5d..951fb8a 100644 --- a/modules/jogl/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt +++ b/modules/jogl/kotlin/com/huskerdev/openglfx/jogl/JOGLFXExecutor.kt @@ -13,7 +13,7 @@ import com.huskerdev.openglfx.jogl.events.JOGLReshapeEvent import com.jogamp.opengl.GL3 import jogamp.opengl.GLDrawableFactoryImpl -@JvmField +@JvmField @Suppress("unused") val JOGL_MODULE = JOGLExecutor() class JOGLExecutor: GLExecutor() { @@ -22,13 +22,16 @@ class JOGLExecutor: GLExecutor() { override fun createRenderEvent(canvas: GLCanvas, currentFps: Int, delta: Double, width: Int, height: Int, fbo: Int) = JOGLRenderEvent(gl[canvas]!!, GLRenderEvent.ANY, currentFps, delta, width, height, fbo) + override fun createReshapeEvent(canvas: GLCanvas, width: Int, height: Int) = JOGLReshapeEvent(gl[canvas]!!, GLReshapeEvent.ANY, width, height) + override fun createInitEvent(canvas: GLCanvas): GLInitializeEvent { if(!gl.containsKey(canvas)) gl[canvas] = GLDrawableFactoryImpl.getFactoryImpl(com.jogamp.opengl.GLProfile.getDefault()).createExternalGLContext().gl.gL3 return JOGLInitializeEvent(gl[canvas]!!, GLInitializeEvent.ANY) } + override fun createDisposeEvent(canvas: GLCanvas): GLDisposeEvent { val gl = gl.remove(canvas) return JOGLDisposeEvent(gl!!, GLDisposeEvent.ANY) diff --git a/modules/libgdx/kotlin/com/huskerdev/openglfx/libgdx/LibGDXCanvas.kt b/modules/libgdx/kotlin/com/huskerdev/openglfx/libgdx/LibGDXCanvas.kt index dc932df..4ab6e6b 100644 --- a/modules/libgdx/kotlin/com/huskerdev/openglfx/libgdx/LibGDXCanvas.kt +++ b/modules/libgdx/kotlin/com/huskerdev/openglfx/libgdx/LibGDXCanvas.kt @@ -14,8 +14,7 @@ class LibGDXCanvas( val configuration: OGLFXApplicationConfiguration = OGLFXApplicationConfiguration(), flipY: Boolean = false, msaa: Int = 0, - fxaa: Boolean = false, - fps: Int = 0, + fps: Int = -1, glDebug: Boolean = false, swapBuffers: Int = 2, interopType: GLInteropType = GLInteropType.auto, @@ -23,7 +22,7 @@ class LibGDXCanvas( ): GLCanvas( LIBGDX_MODULE, GLProfile.CORE, - flipY, msaa, fxaa, fps, glDebug, swapBuffers, interopType, externalWindow + flipY, msaa, fps, glDebug, swapBuffers, interopType, externalWindow ) { private val invokeLater = arrayListOf() lateinit var application: Application @@ -42,17 +41,17 @@ class LibGDXCanvas( } override fun fireInitEvent() { - super.fireInitEvent() if(!::application.isInitialized) { application = OGLFXApplication(configuration, this) adapter.create() } + super.fireInitEvent() } override fun fireDisposeEvent() { - super.fireDisposeEvent() if(::application.isInitialized) adapter.dispose() + super.fireDisposeEvent() } fun invokeLater(runnable: Runnable){