Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] RPC AG & GameWindow #2236

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions korge/src/korlibs/graphics/AGObjects.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ open class AGObject : AutoCloseable {
}
}

internal inline fun <T : AGObject, R: AGNativeObject> T.createOnce(ag: AG, block: (T) -> R): R {
if (this._native == null || this._cachedContextVersion != ag.contextVersion) {
this._cachedContextVersion = ag.contextVersion
this._resetVersion()
this._native = block(this)
}
return this._native as R
}

class AGBuffer : AGObject() {
var mem: Buffer? = null
private set
Expand Down
8 changes: 8 additions & 0 deletions korge/src/korlibs/graphics/AGState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,13 @@ data class AGScissor private constructor(
val isNIL: Boolean get() = this == NIL
val isNotNIL: Boolean get() = !isNIL

val raw: Long get() = Long.fromLowHigh(
0.insert16(_left.toInt(), 0).insert16(_top.toInt(), 16),
0.insert16(_right.toInt(), 0).insert16(_bottom.toInt(), 16)
)

constructor(raw: Long) : this(raw.low.extractShort(0), raw.low.extractShort(1), raw.high.extractShort(0), raw.high.extractShort(1))

constructor(x: Int, y: Int, width: Int, height: Int) : this(x.toShortClamped(), y.toShortClamped(), (x + width).toShortClamped(), (y + height).toShortClamped())
constructor(x: Float, y: Float, width: Float, height: Float) : this(x.toIntRound(), y.toIntRound(), width.toIntRound(), height.toIntRound())
constructor(x: Double, y: Double, width: Double, height: Double) : this(x.toIntRound(), y.toIntRound(), width.toIntRound(), height.toIntRound())
Expand All @@ -656,6 +663,7 @@ data class AGScissor private constructor(
return "Scissor(x=${x}, y=${y}, width=${width}, height=${height})"
}

fun orNull(): AGScissor? = if (isNIL) null else this
fun toRect(): Rectangle = if (isNIL) Rectangle.NIL else Rectangle(x, y, width, height)
fun toRectOrNull(): Rectangle? = toRect().takeIf { it.isNotNIL }

Expand Down
26 changes: 9 additions & 17 deletions korge/src/korlibs/graphics/gl/GLObjects.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package korlibs.graphics.gl

import korlibs.datastructure.*
import korlibs.datastructure.lock.*
import korlibs.graphics.*
import korlibs.io.concurrent.atomic.*
import korlibs.kgl.*
import korlibs.memory.unit.*
import kotlinx.atomicfu.*

class GLGlobalState(val gl: KmlGl, val ag: AG) {
var texturesCreated = korAtomic(0)
var texturesDeleted = korAtomic(0)
var texturesSize = korAtomic(0L)
var texturesCreated = atomic(0)
var texturesDeleted = atomic(0)
var texturesSize = atomic(0L)

var buffersCreated = korAtomic(0)
var buffersDeleted = korAtomic(0)
var buffersSize = korAtomic(0L)
var buffersCreated = atomic(0)
var buffersDeleted = atomic(0)
var buffersSize = atomic(0L)

internal val objectsToDeleteLock = Lock()
internal val objectsToDeleteLock = korlibs.concurrent.lock.Lock()
internal val objectsToDelete = fastArrayListOf<GLBaseObject>()

fun readStats(out: AGStats) {
Expand Down Expand Up @@ -113,11 +112,4 @@ internal class GLTexture(state: GLGlobalState) : GLBaseObject(state) {

////////////////

internal fun <T : AGObject, R: AGNativeObject> T.createOnce(state: GLGlobalState, block: (T) -> R): R {
if (this._native == null || this._cachedContextVersion != state.ag.contextVersion) {
this._cachedContextVersion = state.ag.contextVersion
this._resetVersion()
this._native = block(this)
}
return this._native as R
}
internal inline fun <T : AGObject, R: AGNativeObject> T.createOnce(state: GLGlobalState, block: (T) -> R): R = createOnce(state.ag, block)
2 changes: 1 addition & 1 deletion korge/src/korlibs/render/GameWindow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ open class GameWindow :
@Deprecated("Deprecated setting fps")
set(value) = Unit

open var title: String get() = ""; set(value) = Unit
open var title: String = ""
open val width: Int = 0
open val height: Int = 0
open var vsync: Boolean = true
Expand Down
135 changes: 135 additions & 0 deletions korge/src@jvm/korlibs/render/remote/RPCAG.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package korlibs.render.remote

import korlibs.datastructure.*
import korlibs.graphics.*
import korlibs.image.color.*
import korlibs.memory.*


class RPCAGExecutor(val client: RPCClient, val ag: AG) : AutoCloseable {
val frameBuffer = LinkedHashMap<Int, AGFrameBufferBase>()
val textures = LinkedHashMap<Int, AGTexture>()
val buffers = LinkedHashMap<Int, AGBuffer>()

val handler = client.registerPacketHandler(1000 until 2000, ::handle)

override fun close() {
handler.close()
}

fun handle(packet: Packet) {
val data = packet.data
when (packet.id) {
RPCAG.CLIENT_AG_OBJECT_CREATE -> {
val poolId = data.getInt()
val id = data.getInt()
val info = data.getInt()
println("CLIENT_AG_OBJECT_CREATE: poolId=$poolId, id=$id, info=$info")
when (poolId) {
RPCAG.POOL_ID_FRAME -> frameBuffer.getOrPut(id) { AGFrameBufferBase(isMain = info != 0) }
RPCAG.POOL_ID_TEXTURE -> textures.getOrPut(id) { AGTexture() }
RPCAG.POOL_ID_BUFFER -> buffers.getOrPut(id) { AGBuffer() }
}
}
RPCAG.CLIENT_AG_OBJECT_DELETE -> {
val poolId = data.getInt()
val id = data.getInt()
println("CLIENT_AG_OBJECT_DELETE: poolId=$poolId, id=$id")
when (poolId) {
RPCAG.POOL_ID_FRAME -> frameBuffer.remove(id)?.close()
RPCAG.POOL_ID_TEXTURE -> textures.remove(id)?.close()
RPCAG.POOL_ID_BUFFER -> buffers.remove(id)?.close()
}
}
RPCAG.CLIENT_AG_CLEAR -> {
val frameBufferId = data.getInt()
val frameBufferInfo = AGFrameBufferInfo(data.getLong())
val color = RGBA(data.getInt())
val depth = data.getFloat()
val stencil = data.getInt()
val clearBits = data.getInt()
val scissor = AGScissor(data.getLong())
val clearColor = clearBits.extract(0)
val clearDepth = clearBits.extract(1)
val clearStencil = clearBits.extract(2)
println("CLEAR!")
ag.clear(
frameBuffer[frameBufferId]!!,
frameBufferInfo, color, depth, stencil, clearColor, clearDepth, clearStencil,
scissor
)
}
RPCAG.CLIENT_AG_DRAW -> {
//ag.draw(AGMultiBatch())
TODO()
}
}
}
}

class RPCAG(val client: RPCClient) : AG() {
val frameBufferIds = Pool { it }
val textureIds = Pool { it }
val bufferIds = Pool { it }

companion object {
const val POOL_ID_FRAME = 1
const val POOL_ID_TEXTURE = 2
const val POOL_ID_BUFFER = 3

// CLIENT -> SERVER
const val CLIENT_AG_OBJECT_CREATE = 1001
const val CLIENT_AG_OBJECT_DELETE = 1002
const val CLIENT_AG_CLEAR = 1011
const val CLIENT_AG_DRAW = 1012
const val CLIENT_AG_UPLOAD_TEX = 1021
const val CLIENT_AG_UPLOAD_BUFFER = 1022
}

override fun clear(
frameBuffer: AGFrameBufferBase,
frameBufferInfo: AGFrameBufferInfo,
color: RGBA,
depth: Float,
stencil: Int,
clearColor: Boolean,
clearDepth: Boolean,
clearStencil: Boolean,
scissor: AGScissor
) {
client.sendPacket(CLIENT_AG_CLEAR, 64) {
putInt(frameBuffer.obj().id)
putLong(frameBufferInfo.dataLong)
putInt(color.value)
putFloat(depth)
putInt(stencil)
putInt(0.insert(clearColor, 0).insert(clearDepth, 1).insert(clearStencil, 2))
putLong(scissor.raw)
}
}

fun AGFrameBufferBase.obj() = mobj(POOL_ID_FRAME, frameBufferIds) { if (this.isMain) 1 else 0 }
fun AGTexture.obj() = mobj(POOL_ID_TEXTURE, textureIds)
fun AGBuffer.obj() = mobj(POOL_ID_BUFFER, bufferIds)

internal inline fun <T : AGObject> T.mobj(poolId: Int, pool: Pool<Int>, genExtra: () -> Int = { 0 }) = this.createOnce(this@RPCAG) { RPCNativeObject(this, poolId, pool, genExtra()) }

inner class RPCNativeObject<T : AGObject>(val obj: T, val poolId: Int, val pool: Pool<Int>, val info: Int = 0) : AGNativeObject {
val id = pool.alloc()
init {
client.sendPacket(CLIENT_AG_OBJECT_CREATE, 12) {
putInt(poolId)
putInt(id)
putInt(info)
}
}

override fun markToDelete() {
pool.free(id)
client.sendPacket(CLIENT_AG_OBJECT_DELETE, 8) {
putInt(poolId)
putInt(id)
}
}
}
}
53 changes: 53 additions & 0 deletions korge/src@jvm/korlibs/render/remote/RPCGameWindow.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package korlibs.render.remote

import korlibs.io.util.*
import korlibs.render.*


class RPCGameWindowExecutor(val client: RPCClient, val gameWindow: GameWindow) : AutoCloseable {
val handler = client.registerPacketHandler(2000 until 3000, ::handle)

override fun close() {
handler.close()
}

fun handle(packet: Packet) {
val id = packet.id
val data = packet.data
when (id) {
RPCGameWindow.CLIENT_SET_TITLE -> {
gameWindow.title = data.toByteArray().decodeToString()
println("gameWindow.title=${gameWindow.title}")
}
}
}
}

class RPCGameWindow(val client: RPCClient) : GameWindow() {
companion object {
const val CLIENT_SET_TITLE = 2001

const val SERVER_DISPATCH_INIT = 2101
}

override var title: String = ""
set(value) {
field = value
client.sendPacket(CLIENT_SET_TITLE, value.encodeToByteArray())
}

val handler = client.registerPacketHandler(2000 until 3000, ::handle)

fun handle(packet: Packet) {
val id = packet.id
val data = packet.data
when (id) {
SERVER_DISPATCH_INIT -> dispatchInitEvent()
}
}

override fun close(exitCode: Int) {
handler.close()
super.close(exitCode)
}
}
Loading
Loading