Upgrade to OPENRNDR 0.4 snapshot

This commit is contained in:
Edwin Jakobs
2021-06-22 11:08:07 +02:00
parent 579ddf9bb5
commit 9435907ef9
339 changed files with 460 additions and 497 deletions

View File

@@ -0,0 +1,89 @@
# orx-syphon
Send frames to- and from OPENRNDR to other applications in real time using _Syphon_ for Mac.
![Example](./preview.gif)
### Syphon Server
#### Sharing the whole view
```kotlin
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import kotlin.math.sin
fun main() = application {
configure {
width = 1000
height = 1000
}
program {
extend(SyphonServer())
extend {
drawer.background(ColorRGBa.RED)
drawer.circle(width/2.0, height/2.0, sin(seconds) * width / 2.0)
}
}
}
```
#### Sharing a different render target
```kotlin
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget
import kotlin.math.*
fun main() = application {
configure {
width = 1000
height = 1000
}
program {
val rt = renderTarget(100, 100) {
colorBuffer()
}
// You can give the server a different name
extend(SyphonServer("Test", rt))
extend {
/**
* This is what will be sent to Syphon, and drawn in a small corner of the screen
*/
drawer.isolatedWithTarget(rt) {
drawer.background(ColorRGBa(sin(seconds), cos(seconds / 2.0), 0.5, 1.0))
}
drawer.background(ColorRGBa.GRAY)
drawer.circle(width/2.0, height/2.0, sin(seconds) * width / 2.0)
drawer.image(rt.colorBuffer(0))
}
}
}
```
### Syphon Client
```kotlin
fun main() = application {
configure {
width = 1000
height = 800
}
program {
val syphonClient = SyphonClient()
extend(syphonClient)
extend {
drawer.background(ColorRGBa.BLACK)
drawer.image(syphonClient.buffer)
}
}
}
```

View File

@@ -0,0 +1,5 @@
dependencies {
implementation "org.openrndr:openrndr-application:$openrndrVersion"
implementation "org.openrndr:openrndr-gl3:$openrndrVersion"
implementation "org.openrndr:openrndr-gl3-natives-macos:$openrndrVersion"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 KiB

View File

@@ -0,0 +1,61 @@
package org.openrndr.extra.syphon
import org.openrndr.Extension
import org.openrndr.Program
import org.openrndr.draw.*
import org.openrndr.extra.syphon.jsyphon.JSyphonClient
import org.openrndr.internal.gl3.ColorBufferGL3
import org.openrndr.internal.gl3.TextureStorageModeGL
class SyphonClient(private val appName: String? = null, private val serverName: String? = null): Extension {
override var enabled = true
private val client = JSyphonClient()
var buffer: ColorBuffer = colorBuffer(10, 10)
override fun setup(program: Program) {
buffer = colorBuffer(program.width, program.height)
client.init()
// Choosing a different server
if (appName != null) client.setApplicationName(appName)
if (serverName != null) client.setServerName(serverName)
}
override fun beforeDraw(drawer: Drawer, program: Program) {
if (client.hasNewFrame()) {
val img = client.newFrameImageForContext()
val name = img.textureName()
val w = img.textureWidth()
val h = img.textureHeight()
/**
* GL_TEXTURE_RECTANGLE is necessary
*/
val GL_TEXTURE_RECTANGLE = 0x84F5
val rectBuffer = ColorBufferGL3(GL_TEXTURE_RECTANGLE, name, TextureStorageModeGL.IMAGE, w, h, 1.0, ColorFormat.RGBa, ColorType.UINT8, 0, BufferMultisample.Disabled, Session.root)
/**
* Only create a new buffer if it's size changed
*/
if (buffer.height != h || buffer.width != w) {
buffer = colorBuffer(w, h)
}
rectBuffer.copyTo(buffer)
}
}
override fun shutdown(program: Program) {
client.stop()
}
}

View File

@@ -0,0 +1,66 @@
package org.openrndr.extra.syphon
import org.openrndr.Extension
import org.openrndr.Program
import org.openrndr.draw.Drawer
import org.openrndr.draw.RenderTarget
import org.openrndr.draw.renderTarget
import org.openrndr.extra.syphon.jsyphon.JSyphonServer
import org.openrndr.internal.gl3.ColorBufferGL3
class SyphonServer(private val name: String = "OPENRNDR", var providedTarget: RenderTarget? = null): Extension {
override var enabled = true
private val server = JSyphonServer()
private var targetToSend: RenderTarget? = null
override fun setup(program: Program) {
server.initWithName(name)
// Create a new target that binds to the main one if no target is provided
if (providedTarget == null) {
targetToSend = renderTarget(program.width, program.height) {
colorBuffer()
depthBuffer()
}
} else {
targetToSend = providedTarget
}
}
override fun beforeDraw(drawer: Drawer, program: Program) {
if (providedTarget == null) {
targetToSend?.bind()
}
}
override fun afterDraw(drawer: Drawer, program: Program) {
if (providedTarget == null) {
targetToSend?.unbind()
// Actually draw it, necessary because of bind().
// Only draw if it's the main target.
drawer.image(targetToSend?.colorBuffer(0)!!)
}
val glBuffer = targetToSend?.colorBuffer(0) as ColorBufferGL3
// Send to Syphon
server.publishFrameTexture(
glBuffer.texture, glBuffer.target, 0, 0,
program.width, program.height, program.width, program.height, false
)
}
override fun shutdown(program: Program) {
// Cleanup
server.stop()
}
}

View File

@@ -0,0 +1,52 @@
package org.openrndr.extra.syphon.jsyphon
import java.io.File
import java.util.*
class JSyphonClient
{
private var ptr: Long = 0
val native = JSyphonNative.check()
fun init() {
ptr = init(null)
}
fun setApplicationName(appName: String?) {
setApplicationName(ptr, appName)
}
fun setServerName(serverName: String?) {
setServerName(ptr, serverName)
}
val isValid: Boolean
get() = isValid(ptr)
fun newFrameImageForContext(): JSyphonImage {
val dict = newFrameDataForContext()
val name = dict["name"] as Long?
val width = dict["width"] as Double?
val height = dict["height"] as Double?
return JSyphonImage(name!!.toInt(), width!!.toInt(), height!!.toInt())
}
// Native method declarations
external fun init(options: HashMap<String?, Any?>?): Long
external fun setApplicationName(ptr: Long, appName: String?)
external fun setServerName(ptr: Long, serverName: String?)
external fun isValid(ptr: Long): Boolean
@JvmOverloads
external fun serverDescription(ptr: Long = this.ptr): HashMap<String?, String?>?
@JvmOverloads
external fun hasNewFrame(ptr: Long = this.ptr): Boolean
@JvmOverloads
external fun newFrameDataForContext(ptr: Long = this.ptr): HashMap<String, Any>
@JvmOverloads
external fun stop(ptr: Long = this.ptr)
}

View File

@@ -0,0 +1,15 @@
package org.openrndr.extra.syphon.jsyphon
class JSyphonImage(private val name: Int, private val width: Int, private val height: Int) {
fun textureName(): Int {
return name
}
fun textureWidth(): Int {
return width
}
fun textureHeight(): Int {
return height
}
}

View File

@@ -0,0 +1,36 @@
package org.openrndr.extra.syphon.jsyphon
import org.openrndr.platform.Platform
import org.openrndr.platform.PlatformType
import java.io.File
import java.io.IOException
object JSyphonNative {
init {
require(Platform.type == PlatformType.MAC) { "orx-syphon only works on macOS, your platform is not supported" }
val tempBase = Platform.tempDirectory()
val libraries = arrayOf("Syphon", "libJSyphon.jnilib")
val tempDir = File(tempBase, "orx-syphon")
tempDir.mkdirs()
for (library in libraries) {
val stream = JSyphonNative::class.java.getResourceAsStream("/jsyphon-natives/$library")
require(stream != null)
try {
val target = File(tempDir, library)
val bytes = stream.readBytes()
target.writeBytes(bytes)
} catch (e: IOException) {
throw RuntimeException(e)
} finally {
stream.close()
}
}
for (library in libraries) {
System.load(File(tempDir, library).absolutePath)
}
}
fun check() {
// -- do nothing
}
}

View File

@@ -0,0 +1,143 @@
package org.openrndr.extra.syphon.jsyphon
/*
JSyphonServer.java -
Copyright 2011 -Skye Book (sbook) & Anton Marini (vade)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class JSyphonServer // Public API
{
private var ptr: Long = 0
val native = JSyphonNative.check()
fun initWithName(name: String) {
ptr = initWithName(name, null)
}
val name: String
get() = getName(ptr)
fun hasClients(): Boolean = hasClients(ptr)
fun publishFrameTexture(
texID: Int,
texTarget: Int,
posX: Int,
posY: Int,
width: Int,
height: Int,
sizeX: Int,
sizeY: Int,
isFlipped: Boolean
) {
publishFrameTexture(ptr, texID, texTarget, posX, posY, width, height, sizeX, sizeY, isFlipped)
}
fun publishFrameTexture(
texID: Int,
texTarget: Int,
rect: NSRect,
size: NSSize,
isFlipped: Boolean
) {
publishFrameTexture(
ptr,
texID,
texTarget,
rect.origin.x,
rect.origin.y,
rect.size.x,
rect.size.y,
size.x,
size.y,
isFlipped
)
}
fun bindToDrawFrameOfSize(size: NSSize): Boolean =
bindToDrawFrameOfSize(ptr, size.x, size.y)
fun bindToDrawFrameOfSize(sizeX: Int, sizeY: Int): Boolean =
bindToDrawFrameOfSize(ptr, sizeX, sizeY)
fun unbindAndPublish() {
unbindAndPublish(ptr)
}
fun stop() {
stop(ptr)
}
// Native method declarations
private external fun initWithName(
name: String,
options: HashMap<String, Any>?
): Long
private external fun getName(ptr: Long): String
private external fun hasClients(ptr: Long): Boolean
private external fun publishFrameTexture(
ptr: Long,
texID: Int,
texTarget: Int,
posX: Int,
posY: Int,
width: Int,
height: Int,
sizeX: Int,
sizeY: Int,
isFlipped: Boolean
)
private fun publishFrameTexture(
ptr: Long,
texID: Int,
texTarget: Int,
rect: NSRect,
size: NSSize,
isFlipped: Boolean
) {
publishFrameTexture(
ptr,
texID,
texTarget,
rect.origin.x,
rect.origin.y,
rect.size.x,
rect.size.y,
size.x,
size.y,
isFlipped
)
}
private fun bindToDrawFrameOfSize(ptr: Long, size: NSSize): Boolean {
return bindToDrawFrameOfSize(ptr, size.x, size.y)
}
private external fun bindToDrawFrameOfSize(ptr: Long, sizeX: Int, sizeY: Int): Boolean
private external fun unbindAndPublish(ptr: Long)
private external fun stop(ptr: Long)
}

View File

@@ -0,0 +1,13 @@
package org.openrndr.extra.syphon.jsyphon
import java.io.File
import java.util.ArrayList
import java.util.HashMap
object JSyphonServerList {
val list: ArrayList<HashMap<String?, String?>?>?
external get
init {
System.load(File("orx-syphon/src/main/kotlin/jsyphon/libJSyphon.jnilib").absolutePath)
}
}

View File

@@ -0,0 +1,10 @@
package org.openrndr.extra.syphon.jsyphon
class NSSize (var x: Int, var y: Int)
class NSPoint(var x: Int, var y: Int)
class NSRect(var origin: NSPoint, var size: NSSize) {
constructor(startX: Int, xLength: Int, startY: Int, yLength: Int) : this(
NSPoint(startX, startY),
NSSize(xLength, yLength)
)
}

Binary file not shown.

View File

@@ -0,0 +1,21 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.syphon.SyphonClient
suspend fun main() = application {
configure {
width = 1000
height = 800
}
program {
val syphonClient = SyphonClient()
extend(syphonClient)
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.image(syphonClient.buffer)
}
}
}

View File

@@ -0,0 +1,25 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.syphon.SyphonClient
/**
* This example uses After Effects and OPENRNDR connected via Syphon
*/
suspend fun main() = application {
configure {
// The maximum resolution supported by the free
// version of AESyphon
width = 1024
height = 768
}
program {
val syphonClient = SyphonClient("Adobe After Effects", "Live Preview")
extend(syphonClient)
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.image(syphonClient.buffer)
}
}
}

View File

@@ -0,0 +1,22 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.syphon.SyphonServer
import kotlin.math.*
suspend fun main() = application {
configure {
width = 1000
height = 1000
}
program {
extend(SyphonServer("Test"))
extend {
drawer.clear(ColorRGBa.PINK)
drawer.fill = ColorRGBa.WHITE
drawer.circle(drawer.bounds.center, abs(cos(seconds)) * height * 0.5)
}
}
}

View File

@@ -0,0 +1,36 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget
import org.openrndr.extra.syphon.SyphonServer
import kotlin.math.*
suspend fun main() = application {
configure {
width = 1000
height = 1000
}
program {
val rt = renderTarget(100, 100) {
colorBuffer()
}
// You can give the server a different name
extend(SyphonServer("Test", rt))
extend {
/**
* This is what will be sent to Syphon, and drawn in a small corner of the screen
*/
drawer.isolatedWithTarget(rt) {
drawer.clear(ColorRGBa(sin(seconds), cos(seconds / 2.0), 0.5, 1.0))
}
drawer.clear(ColorRGBa.PINK)
drawer.fill = ColorRGBa.WHITE
drawer.circle(drawer.bounds.center, abs(cos(seconds)) * height * 0.5)
drawer.image(rt.colorBuffer(0))
}
}
}