-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
369 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/build | ||
/.gradle | ||
/.idea | ||
/out | ||
/bin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import korlibs.korge.gradle.targets.android.* | ||
import korlibs.root.* | ||
|
||
plugins { | ||
//id "kotlin" version "1.6.21" | ||
id("kotlin") | ||
//id "org.jetbrains.kotlin.jvm" | ||
id("maven-publish") | ||
} | ||
|
||
description = "Multiplatform Game Engine written in Kotlin" | ||
group = RootKorlibsPlugin.KORGE_RELOAD_AGENT_GROUP | ||
|
||
val jversion = GRADLE_JAVA_VERSION_STR | ||
|
||
java { | ||
setSourceCompatibility(jversion) | ||
setTargetCompatibility(jversion) | ||
} | ||
|
||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class).all { | ||
kotlinOptions { | ||
jvmTarget = jversion | ||
apiVersion = "1.8" | ||
languageVersion = "1.8" | ||
suppressWarnings = true | ||
} | ||
} | ||
|
||
publishing { | ||
publications { | ||
val maven by creating(MavenPublication::class) { | ||
groupId = group.toString() | ||
artifactId = "korge-ipc" | ||
version = version | ||
from(components["kotlin"]) | ||
} | ||
} | ||
} | ||
|
||
val publishJvmPublicationToMavenLocal = tasks.register("publishJvmPublicationToMavenLocal", Task::class) { | ||
group = "publishing" | ||
dependsOn("publishMavenPublicationToMavenLocal") | ||
} | ||
|
||
afterEvaluate { | ||
if (tasks.findByName("publishMavenPublicationToMavenRepository") != null) { | ||
tasks.register("publishJvmPublicationToMavenRepository", Task::class) { | ||
group = "publishing" | ||
dependsOn("publishMavenPublicationToMavenRepository") | ||
} | ||
} | ||
} | ||
|
||
korlibs.NativeTools.groovyConfigurePublishing(project, false) | ||
korlibs.NativeTools.groovyConfigureSigning(project) | ||
|
||
dependencies { | ||
testImplementation(libs.bundles.kotlin.test) | ||
} | ||
|
||
tasks { val jvmTest by creating { dependsOn("test") } } |
176 changes: 176 additions & 0 deletions
176
korge-ipc/src/main/kotlin/korlibs/korge/ipc/KorgeIPC.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package korlibs.korge.ipc | ||
|
||
import java.io.* | ||
import java.nio.* | ||
import java.nio.channels.* | ||
import java.nio.file.* | ||
import kotlin.reflect.* | ||
|
||
class KorgeIPC(val path: String = System.getenv("KORGE_IPC") ?: DEFAULT_PATH) { | ||
init { | ||
println("KorgeIPC:$path") | ||
} | ||
|
||
companion object { | ||
val DEFAULT_PATH = "/tmp/KORGE_IPC" | ||
} | ||
val frame = KorgeFrameBuffer("$path.frame") | ||
val events = KorgeEventsBuffer("$path.events") | ||
|
||
val availableEvents get() = events.availableRead | ||
fun writeEvent(e: IPCEvent) = events.writeEvent(e) | ||
fun readEvent(e: IPCEvent = IPCEvent()): IPCEvent? = events.readEvent(e) | ||
fun setFrame(f: IPCFrame) = frame.setFrame(f) | ||
fun getFrame(): IPCFrame = frame.getFrame() | ||
fun getFrameId(): Int = frame.getFrameId() | ||
} | ||
|
||
data class IPCEvent( | ||
var timestamp: Long = System.currentTimeMillis(), | ||
var type: Int = 0, | ||
var p0: Int = 0, | ||
var p1: Int = 0, | ||
var p2: Int = 0, | ||
var p3: Int = 0, | ||
) { | ||
fun setNow(): IPCEvent { | ||
timestamp = System.currentTimeMillis() | ||
return this | ||
} | ||
|
||
companion object { | ||
val RESIZE = 1 | ||
|
||
val MOUSE_MOVE = 10 | ||
val MOUSE_DOWN = 11 | ||
val MOUSE_UP = 12 | ||
val MOUSE_CLICK = 13 | ||
|
||
val KEY_DOWN = 20 | ||
val KEY_UP = 21 | ||
val KEY_TYPE = 22 | ||
} | ||
} | ||
|
||
class KorgeEventsBuffer(val path: String) { | ||
val channel = FileChannel.open(Path.of(path), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE) | ||
val HEAD_SIZE = 32 | ||
val EVENT_SIZE = 32 | ||
val MAX_EVENTS = 4096 | ||
var buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0L, (HEAD_SIZE + EVENT_SIZE * MAX_EVENTS).toLong()) | ||
|
||
init { | ||
File(path).deleteOnExit() | ||
} | ||
|
||
var readPos: Long by DelegateBufferLong(buffer, 0) | ||
var writePos: Long by DelegateBufferLong(buffer, 8) | ||
|
||
|
||
fun eventOffset(index: Long): Int = 32 + ((index % MAX_EVENTS).toInt() * 32) | ||
|
||
fun readEvent(index: Long, e: IPCEvent = IPCEvent()): IPCEvent { | ||
val pos = eventOffset(index) | ||
e.timestamp = buffer.getLong(pos + 0) | ||
e.type = buffer.getInt(pos + 8) | ||
e.p0 = buffer.getInt(pos + 12) | ||
e.p1 = buffer.getInt(pos + 16) | ||
e.p2 = buffer.getInt(pos + 20) | ||
e.p3 = buffer.getInt(pos + 24) | ||
return e | ||
} | ||
|
||
fun writeEvent(index: Long, e: IPCEvent) { | ||
val pos = eventOffset(index) | ||
buffer.putLong(pos + 0, e.timestamp) | ||
buffer.putInt(pos + 8, e.type) | ||
buffer.putInt(pos + 12, e.p0) | ||
buffer.putInt(pos + 16, e.p1) | ||
buffer.putInt(pos + 20, e.p2) | ||
buffer.putInt(pos + 24, e.p3) | ||
} | ||
|
||
fun reset() { | ||
readPos = 0L | ||
writePos = 0L | ||
} | ||
|
||
val availableRead: Int get() = (writePos - readPos).toInt() | ||
val availableWriteWithoutOverflow: Int get() = MAX_EVENTS - availableRead | ||
|
||
fun writeEvent(e: IPCEvent) { | ||
//println("EVENT: $e") | ||
writeEvent(writePos++, e) | ||
} | ||
|
||
fun readEvent(e: IPCEvent = IPCEvent()): IPCEvent? { | ||
if (readPos >= writePos) return null | ||
return readEvent(readPos++, e) | ||
} | ||
|
||
fun close() { | ||
channel.close() | ||
} | ||
|
||
class DelegateBufferLong(val buffer: ByteBuffer, val index: Int) { | ||
operator fun getValue(obj: Any, property: KProperty<*>): Long = buffer.getLong(index) | ||
operator fun setValue(obj: Any, property: KProperty<*>, value: Long) { buffer.putLong(index, value) } | ||
} | ||
|
||
class DelegateBufferInt(val buffer: ByteBuffer, val index: Int) { | ||
operator fun getValue(obj: Any, property: KProperty<*>): Int = buffer.getInt(index) | ||
operator fun setValue(obj: Any, property: KProperty<*>, value: Int) { buffer.putInt(index, value) } | ||
} | ||
} | ||
|
||
class IPCFrame(val id: Int, val width: Int, val height: Int, val pixels: IntArray = IntArray(width * height)) | ||
|
||
class KorgeFrameBuffer(val path: String) { | ||
val channel = FileChannel.open(Path.of(path), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE) | ||
var width: Int = 0 | ||
var height: Int = 0 | ||
var buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0L, 16 + 0) | ||
var ibuffer = buffer.asIntBuffer() | ||
|
||
init { | ||
File(path).deleteOnExit() | ||
} | ||
|
||
fun ensureSize(width: Int, height: Int) { | ||
if (this.width < width || this.height < height) { | ||
this.width = width | ||
this.height = height | ||
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0L, (16 + (width * height * 4)).toLong()) | ||
ibuffer = buffer.asIntBuffer() | ||
} | ||
} | ||
|
||
fun setFrame(frame: IPCFrame) { | ||
ensureSize(frame.width, frame.height) | ||
ibuffer.clear() | ||
ibuffer.put(frame.id) | ||
ibuffer.put(frame.width) | ||
ibuffer.put(frame.height) | ||
ibuffer.put(frame.pixels) | ||
} | ||
|
||
fun getFrameId(): Int { | ||
ibuffer.clear() | ||
return ibuffer.get() | ||
} | ||
|
||
fun getFrame(): IPCFrame { | ||
ibuffer.clear() | ||
val id = ibuffer.get() | ||
val width = ibuffer.get() | ||
val height = ibuffer.get() | ||
ensureSize(width, height) | ||
val pixels = IntArray(width * height) | ||
ibuffer.get(pixels) | ||
return IPCFrame(id, width, height, pixels) | ||
} | ||
|
||
fun close() { | ||
channel.close() | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
korge-ipc/src/main/kotlin/korlibs/korge/ipc/KorgeIPCJPanel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package korlibs.korge.ipc | ||
|
||
import java.awt.* | ||
import java.awt.event.* | ||
import java.awt.image.* | ||
import javax.swing.* | ||
|
||
class KorgeIPCJPanel(val ipc: KorgeIPC = KorgeIPC()) : JPanel(), MouseListener, MouseMotionListener, MouseWheelListener, KeyListener { | ||
var image: BufferedImage? = null | ||
|
||
init { | ||
Timer(16) { | ||
readFrame() | ||
//println(events.availableRead) | ||
}.also { it.isRepeats = true }.start() | ||
} | ||
|
||
override fun paint(g: Graphics) { | ||
//g.color = Color.RED | ||
//g.fillRect(0, 0, 100, 100) | ||
if (image != null) { | ||
g.drawImage(image, 0, 0, width, height, null) | ||
} | ||
} | ||
|
||
fun rgbaToBgra(v: Int): Int = ((v shl 16) and 0x00FF0000) or ((v shr 16) and 0x000000FF) or (v and 0xFF00FF00.toInt()) | ||
|
||
var currentFrameId = -1 | ||
|
||
fun readFrame() { | ||
val frameId = ipc.getFrameId() | ||
if (frameId == currentFrameId) return // Do not update | ||
val frame = ipc.getFrame() | ||
if (frame.width == 0 || frame.height == 0) return // Empty frame | ||
currentFrameId = frame.id | ||
val image = BufferedImage(frame.width, frame.height, BufferedImage.TYPE_INT_ARGB) | ||
this.image = image | ||
val imgPixels = (image.raster.dataBuffer as DataBufferInt).data | ||
System.arraycopy(frame.pixels, 0, imgPixels, 0, frame.width * frame.height) | ||
for (n in imgPixels.indices) imgPixels[n] = rgbaToBgra(imgPixels[n]) | ||
repaint() | ||
} | ||
|
||
private fun sendEv(type: Int, e: KeyEvent) = ipc.writeEvent(IPCEvent(type = type, p0 = e.keyCode, p1 = e.keyChar.code)) | ||
private fun sendEv(type: Int, e: MouseEvent) = ipc.writeEvent(IPCEvent(type = type, p0 = e.x, p1 = e.y, p2 = e.button)) | ||
override fun keyTyped(e: KeyEvent) = sendEv(IPCEvent.KEY_TYPE, e) | ||
override fun keyPressed(e: KeyEvent) = sendEv(IPCEvent.KEY_DOWN, e) | ||
override fun keyReleased(e: KeyEvent) = sendEv(IPCEvent.KEY_UP, e) | ||
override fun mouseMoved(e: MouseEvent) = sendEv(IPCEvent.MOUSE_MOVE, e) | ||
override fun mouseDragged(e: MouseEvent) = sendEv(IPCEvent.MOUSE_MOVE, e) | ||
override fun mouseWheelMoved(e: MouseWheelEvent) = sendEv(IPCEvent.MOUSE_MOVE, e) | ||
override fun mouseExited(e: MouseEvent) = sendEv(IPCEvent.MOUSE_MOVE, e) | ||
override fun mouseEntered(e: MouseEvent) = sendEv(IPCEvent.MOUSE_MOVE, e) | ||
override fun mouseReleased(e: MouseEvent) = sendEv(IPCEvent.MOUSE_UP, e) | ||
override fun mousePressed(e: MouseEvent) = sendEv(IPCEvent.MOUSE_DOWN, e) | ||
override fun mouseClicked(e: MouseEvent) = sendEv(IPCEvent.MOUSE_CLICK, e) | ||
|
||
init { | ||
addKeyListener(this) | ||
addMouseListener(this) | ||
addMouseMotionListener(this) | ||
addMouseWheelListener(this) | ||
} | ||
|
||
companion object { | ||
@JvmStatic | ||
fun main() { | ||
val frame = JFrame() | ||
val frameHolder = korlibs.korge.ipc.KorgeIPCJPanel() | ||
frame.add(frameHolder) | ||
frame.addKeyListener(frameHolder) | ||
|
||
frame.preferredSize = Dimension(640, 480) | ||
frame.pack() | ||
frame.setLocationRelativeTo(null) | ||
|
||
frame.isVisible = true | ||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
korlibs.korge.StandardViewsCompleter | ||
korlibs.korge.IPCViewsCompleter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.