You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.8 KiB
86 lines
2.8 KiB
import androidx.compose.ui.ComposeScene |
|
import androidx.compose.ui.unit.Constraints |
|
import androidx.compose.ui.unit.Density |
|
import org.jetbrains.skia.* |
|
import org.jetbrains.skia.FramebufferFormat.Companion.GR_GL_RGBA8 |
|
import org.jetbrains.skiko.FrameDispatcher |
|
import org.lwjgl.glfw.GLFW.* |
|
import org.lwjgl.opengl.GL |
|
import org.lwjgl.opengl.GL11 |
|
import org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_BINDING |
|
import org.lwjgl.system.MemoryUtil.NULL |
|
import kotlin.system.exitProcess |
|
|
|
fun main() { |
|
var width = 640 |
|
var height = 480 |
|
|
|
glfwInit() |
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) |
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE) |
|
val windowHandle: Long = glfwCreateWindow(width, height, "Compose LWJGL Demo", NULL, NULL) |
|
glfwMakeContextCurrent(windowHandle) |
|
glfwSwapInterval(1) |
|
|
|
GL.createCapabilities() |
|
|
|
val context = DirectContext.makeGL() |
|
var surface = createSurface(width, height, context) // Skia Surface, bound to the OpenGL framebuffer |
|
val glfwDispatcher = GlfwCoroutineDispatcher() // a custom coroutine dispatcher, in which Compose will run |
|
|
|
glfwSetWindowCloseCallback(windowHandle) { |
|
glfwDispatcher.stop() |
|
} |
|
|
|
lateinit var composeScene: ComposeScene |
|
|
|
fun render() { |
|
surface.canvas.clear(Color.WHITE) |
|
composeScene.constraints = Constraints(maxWidth = width, maxHeight = height) |
|
composeScene.render(surface.canvas, System.nanoTime()) |
|
|
|
context.flush() |
|
glfwSwapBuffers(windowHandle) |
|
} |
|
|
|
val frameDispatcher = FrameDispatcher(glfwDispatcher) { render() } |
|
|
|
val density = Density(glfwGetWindowContentScale(windowHandle)) |
|
composeScene = ComposeScene(glfwDispatcher, density, invalidate = frameDispatcher::scheduleFrame) |
|
|
|
glfwSetWindowSizeCallback(windowHandle) { _, windowWidth, windowHeight -> |
|
width = windowWidth |
|
height = windowHeight |
|
surface.close() |
|
surface = createSurface(width, height, context) |
|
|
|
glfwSwapInterval(0) |
|
render() |
|
glfwSwapInterval(1) |
|
} |
|
|
|
composeScene.subscribeToGLFWEvents(windowHandle) |
|
composeScene.setContent { App() } |
|
glfwShowWindow(windowHandle) |
|
|
|
glfwDispatcher.runLoop() |
|
|
|
composeScene.dispose() |
|
glfwDestroyWindow(windowHandle) |
|
|
|
exitProcess(0) |
|
} |
|
|
|
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( |
|
context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.sRGB |
|
) |
|
} |
|
|
|
private fun glfwGetWindowContentScale(window: Long): Float { |
|
val array = FloatArray(1) |
|
glfwGetWindowContentScale(window, array, FloatArray(1)) |
|
return array[0] |
|
} |