Skip to content

Instantly share code, notes, and snippets.

@Spasi
Last active April 20, 2016 16:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Spasi/41832fe66f3a8c770948 to your computer and use it in GitHub Desktop.
Save Spasi/41832fe66f3a8c770948 to your computer and use it in GitHub Desktop.
Zero-overhead, type-safe native interop with Kotlin
// WARNING: This is not valid Kotlin code. The typealias keyword
// has not been implemented yet and may not work as shown below.
// This is like a C typedef. You can pass a GLint/GLenum where an
// Int is expected, but you cannot do the opposite, would be a
// compile-time error.
typealias GLint = Int
typealias GLenum = Int
// Native pointer values are usually mapped to Java longs. We can
// get fancy here with type parameters (e.g. Pointer<Foo>) or be
// more specific (e.g. UINT32Pointer), but lets just treat this as
// an opaque pointer to an arbitrary native data structure.
typealias Pointer = Long
// Lets use GLsync from the ARB_sync OpenGL extension. This is an
// alias to an alias, so GLsync is still a primitive long.
typealias GLsync = Pointer
// We cannot assign Long to Pointer, so a cast is necessary.
public val NULL: Pointer = 0L as Pointer
// The following definitions would be auto-generated by LWJGL.
public val GL_SYNC_GPU_COMMANDS_COMPLETE: GLenum = 0x9117 as GLenum
public val GL_OBJECT_TYPE: GLenum = 0x9112 as GLenum
public val GL_SYNC_CONDITION: GLenum = 0x9113 as GLenum
public val GL_SYNC_STATUS: GLenum = 0x9114 as GLenum
public val GL_SYNC_FLAGS: GLenum = 0x9115 as GLenum
public val GL_UNSIGNALED: GLint = 0x9118 as GLint
public val GL_SIGNALED : GLint = 0x9119 as GLint
// virtual constructor
public fun GLsync(condition: GLenum, flags: Int): GLsync =
GL32.glFenceSync(condition, flags) as GLsync // glFenceSync returns a long, cast to GLsync
// extension function on the typealias
public fun GLsync.get(pname: GLenum): GLint =
GL32.glGetSynci(this, pname, NULL) as GLint
fun test() {
// We cannot pass simple ints to GLenum parameters.
// Also, auto-complete suggests GLenums only.
val sync = GLsync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)
glFinish()
// sync is just a long in bytecode, but in Kotlin
// we can use all kinds of goodies.
assertTrue(sync[GL_SYNC_STATUS], GL_SIGNALED)
}
// Structs are interesting too:
typealias BytePointer = Pointer // char*
// sun.misc.Unsafe stuff
fun BytePointer.get(offset: Int): Byte = memGetByte(this + offset)
fun BytePointer.set(offset: Int, value: Byte): Unit = memPutByte(this + offset, value)
// Generated
typealias GLFWimage = Pointer
var GLFWimage.width: Int
get() = memGetInt(this + 0)
set(width: Int) = memPutInt(this + 0, width)
var GLFWimage.height: Int
get() = memGetInt(this + 4)
set(height: Int) = memPutInt(this + 4, height)
val GLFWimage.pixels: BytePointer
get() = memGetAddress(8) as BytePointer
fun testStructs() {
val img: GLFWimage = ...
img.width = 32
img.height = 32
for ( y in 0..31 ) {
for ( x in 0..31 ) {
img.pixels[y * 32 + x] = 127
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment