From 9fa2a69b1e7bf856d4e0ab7b73d4846c1dff06f1 Mon Sep 17 00:00:00 2001 From: Enaium <32991121+Enaium@users.noreply.github.com> Date: Thu, 30 Jan 2025 13:56:59 +0000 Subject: [PATCH] Update lwjgl-integration --- .../lwjgl-integration/build.gradle.kts | 5 +- .../lwjgl-integration/src/main/kotlin/App.kt | 11 ++-- .../src/main/kotlin/GlfwEvents.kt | 64 +++++++++++++++---- .../lwjgl-integration/src/main/kotlin/main.kt | 26 +++++--- 4 files changed, 76 insertions(+), 30 deletions(-) diff --git a/experimental/lwjgl-integration/build.gradle.kts b/experimental/lwjgl-integration/build.gradle.kts index 5d634fb891e..31fc5cec73d 100644 --- a/experimental/lwjgl-integration/build.gradle.kts +++ b/experimental/lwjgl-integration/build.gradle.kts @@ -2,8 +2,9 @@ import org.jetbrains.compose.compose import org.jetbrains.compose.desktop.application.dsl.TargetFormat plugins { - kotlin("jvm") version "1.5.31" - id("org.jetbrains.compose") version "1.0.0" + kotlin("jvm") version "2.1.10" + id("org.jetbrains.kotlin.plugin.compose") version "2.1.10" + id("org.jetbrains.compose") version "1.8.0-alpha02" } repositories { diff --git a/experimental/lwjgl-integration/src/main/kotlin/App.kt b/experimental/lwjgl-integration/src/main/kotlin/App.kt index 90dd9dd7b3c..389ed764218 100644 --- a/experimental/lwjgl-integration/src/main/kotlin/App.kt +++ b/experimental/lwjgl-integration/src/main/kotlin/App.kt @@ -1,16 +1,15 @@ import androidx.compose.foundation.VerticalScrollbar -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.material.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp diff --git a/experimental/lwjgl-integration/src/main/kotlin/GlfwEvents.kt b/experimental/lwjgl-integration/src/main/kotlin/GlfwEvents.kt index 1615614a143..7af025f36d7 100644 --- a/experimental/lwjgl-integration/src/main/kotlin/GlfwEvents.kt +++ b/experimental/lwjgl-integration/src/main/kotlin/GlfwEvents.kt @@ -1,8 +1,10 @@ -import androidx.compose.ui.ComposeScene -import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.InternalComposeUiApi import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.scene.ComposeScene import androidx.compose.ui.unit.Density import org.lwjgl.glfw.GLFW.* import java.awt.Component @@ -11,7 +13,7 @@ import java.awt.event.MouseEvent import java.awt.event.MouseWheelEvent import java.awt.event.KeyEvent as AwtKeyEvent -@OptIn(ExperimentalComposeUiApi::class) +@OptIn(InternalComposeUiApi::class) fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { glfwSetMouseButtonCallback(windowHandle) { _, button, action, mods -> sendPointerEvent( @@ -21,7 +23,7 @@ fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { GLFW_RELEASE -> PointerEventType.Release else -> PointerEventType.Unknown }, - nativeEvent = MouseEvent(getAwtMods(windowHandle)) + nativeEvent = MouseEvent(getAwtMods(windowHandle)) ) } @@ -29,7 +31,7 @@ fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { sendPointerEvent( position = Offset(xpos.toFloat(), ypos.toFloat()), eventType = PointerEventType.Move, - nativeEvent = MouseEvent(getAwtMods(windowHandle)) + nativeEvent = MouseEvent(getAwtMods(windowHandle)) ) } @@ -37,7 +39,7 @@ fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { sendPointerEvent( position = glfwGetCursorPos(windowHandle), eventType = if (entered) PointerEventType.Enter else PointerEventType.Exit, - nativeEvent = MouseEvent(getAwtMods(windowHandle)) + nativeEvent = MouseEvent(getAwtMods(windowHandle)) ) } @@ -46,7 +48,7 @@ fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { eventType = PointerEventType.Scroll, position = glfwGetCursorPos(windowHandle), scrollDelta = Offset(xoffset.toFloat(), -yoffset.toFloat()), - nativeEvent = MouseWheelEvent(getAwtMods(windowHandle)) + nativeEvent = MouseWheelEvent(getAwtMods(windowHandle)) ) } @@ -62,13 +64,31 @@ fun ComposeScene.subscribeToGLFWEvents(windowHandle: Long) { // Note that we don't distinguish between Left/Right Shift, Del from numpad or not, etc. // To distinguish we should change `location` parameter - sendKeyEvent(KeyEvent(awtId, time, getAwtMods(windowHandle), awtKey, 0.toChar(), AwtKeyEvent.KEY_LOCATION_STANDARD)) + sendKeyEvent( + KeyEvent( + awtId, + time, + getAwtMods(windowHandle), + awtKey, + 0.toChar(), + AwtKeyEvent.KEY_LOCATION_STANDARD + ) + ) } glfwSetCharCallback(windowHandle) { _, codepoint -> for (char in Character.toChars(codepoint)) { val time = System.nanoTime() / 1_000_000 - sendKeyEvent(KeyEvent(AwtKeyEvent.KEY_TYPED, time, getAwtMods(windowHandle), 0, char, AwtKeyEvent.KEY_LOCATION_UNKNOWN)) + sendKeyEvent( + KeyEvent( + AwtKeyEvent.KEY_TYPED, + time, + getAwtMods(windowHandle), + 0, + char, + AwtKeyEvent.KEY_LOCATION_UNKNOWN + ) + ) } } @@ -87,8 +107,12 @@ private fun glfwGetCursorPos(window: Long): Offset { // in the future versions of Compose we plan to get rid of the need of AWT events/components val awtComponent = object : Component() {} +@OptIn(InternalComposeUiApi::class) private fun KeyEvent(awtId: Int, time: Long, awtMods: Int, key: Int, char: Char, location: Int) = KeyEvent( - AwtKeyEvent(awtComponent, awtId, time, awtMods, key, char, location) + key = Key(key), + codePoint = char.code, + type = if (awtId == AwtKeyEvent.KEY_PRESSED) KeyEventType.KeyDown else if (awtId == AwtKeyEvent.KEY_RELEASED) KeyEventType.KeyUp else KeyEventType.Unknown, + nativeEvent = AwtKeyEvent(awtComponent, awtId, time, awtMods, key, char, location) ) private fun MouseEvent(awtMods: Int) = MouseEvent( @@ -111,11 +135,23 @@ private fun getAwtMods(windowHandle: Long): Int { awtMods = awtMods or (1 shl 14) if (glfwGetMouseButton(windowHandle, GLFW_MOUSE_BUTTON_5) == GLFW_PRESS) awtMods = awtMods or (1 shl 15) - if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(windowHandle, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) + if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey( + windowHandle, + GLFW_KEY_RIGHT_CONTROL + ) == GLFW_PRESS + ) awtMods = awtMods or InputEvent.CTRL_DOWN_MASK - if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(windowHandle, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) + if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey( + windowHandle, + GLFW_KEY_RIGHT_SHIFT + ) == GLFW_PRESS + ) awtMods = awtMods or InputEvent.SHIFT_DOWN_MASK - if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(windowHandle, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS) + if (glfwGetKey(windowHandle, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey( + windowHandle, + GLFW_KEY_RIGHT_ALT + ) == GLFW_PRESS + ) awtMods = awtMods or InputEvent.ALT_DOWN_MASK return awtMods -} +} \ No newline at end of file diff --git a/experimental/lwjgl-integration/src/main/kotlin/main.kt b/experimental/lwjgl-integration/src/main/kotlin/main.kt index feb92e63e21..68e40077573 100644 --- a/experimental/lwjgl-integration/src/main/kotlin/main.kt +++ b/experimental/lwjgl-integration/src/main/kotlin/main.kt @@ -1,6 +1,9 @@ -import androidx.compose.ui.ComposeScene -import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.InternalComposeUiApi +import androidx.compose.ui.graphics.asComposeCanvas +import androidx.compose.ui.scene.CanvasLayersComposeScene +import androidx.compose.ui.scene.ComposeScene import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntSize import org.jetbrains.skia.* import org.jetbrains.skia.FramebufferFormat.Companion.GR_GL_RGBA8 import org.jetbrains.skiko.FrameDispatcher @@ -11,6 +14,7 @@ import org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_BINDING import org.lwjgl.system.MemoryUtil.NULL import kotlin.system.exitProcess +@OptIn(InternalComposeUiApi::class) fun main() { var width = 640 var height = 480 @@ -35,9 +39,10 @@ fun main() { lateinit var composeScene: ComposeScene fun render() { - surface.canvas.clear(Color.WHITE) - composeScene.constraints = Constraints(maxWidth = width, maxHeight = height) - composeScene.render(surface.canvas, System.nanoTime()) + surface ?: return + surface!!.canvas.clear(Color.WHITE) + composeScene.size = IntSize(width, height) + composeScene.render(surface!!.canvas.asComposeCanvas(), System.nanoTime()) context.flush() glfwSwapBuffers(windowHandle) @@ -46,12 +51,17 @@ fun main() { val frameDispatcher = FrameDispatcher(glfwDispatcher) { render() } val density = Density(glfwGetWindowContentScale(windowHandle)) - composeScene = ComposeScene(glfwDispatcher, density, invalidate = frameDispatcher::scheduleFrame) + composeScene = + CanvasLayersComposeScene( + density = density, + coroutineContext = glfwDispatcher, + invalidate = frameDispatcher::scheduleFrame + ) glfwSetWindowSizeCallback(windowHandle) { _, windowWidth, windowHeight -> width = windowWidth height = windowHeight - surface.close() + surface?.close() surface = createSurface(width, height, context) glfwSwapInterval(0) @@ -71,7 +81,7 @@ fun main() { exitProcess(0) } -private fun createSurface(width: Int, height: Int, context: DirectContext): Surface { +private fun createSurface(width: Int, height: Int, context: DirectContext): Surface? { val fbId = GL11.glGetInteger(GL_FRAMEBUFFER_BINDING) val renderTarget = BackendRenderTarget.makeGL(width, height, 0, 8, fbId, GR_GL_RGBA8) return Surface.makeFromBackendRenderTarget(