Add optional QR-code overlay for orx-rabbit-control
* Optional QR-code overlay for orx-rabbit-control * Animate the QR-code overlay * Changed orx-rabbit-control to the new demo structure * Changed orx-rabbit-control README.MD
This commit is contained in:
committed by
GitHub
parent
b98d1b7369
commit
5d3eadd156
@@ -6,6 +6,10 @@
|
|||||||
<img src="https://rabbitcontrol.github.io/carrot-sketch-c-trans.png" width="50px">
|
<img src="https://rabbitcontrol.github.io/carrot-sketch-c-trans.png" width="50px">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
For examples, check out the [demo](./src/demo/kotlin) folder.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Using the web client
|
### Using the web client
|
||||||
|
|
||||||
Go to [rabbitcontrol.github.io/client](https://rabbitcontrol.github.io/client/) and enter your IP-address and port.
|
Go to [rabbitcontrol.github.io/client](https://rabbitcontrol.github.io/client/) and enter your IP-address and port.
|
||||||
|
|||||||
@@ -1,9 +1,27 @@
|
|||||||
|
repositories {
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
demo {
|
||||||
|
java {
|
||||||
|
srcDirs = ["src/demo/kotlin"]
|
||||||
|
compileClasspath += main.getCompileClasspath()
|
||||||
|
runtimeClasspath += main.getRuntimeClasspath()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":orx-parameters")
|
api project(":orx-parameters")
|
||||||
|
api project(":orx-compositor")
|
||||||
|
api project(":orx-image-fit")
|
||||||
|
|
||||||
implementation "org.openrndr:openrndr-core:$openrndrVersion"
|
|
||||||
implementation "org.openrndr:openrndr-gl3:$openrndrVersion"
|
|
||||||
implementation "org.lwjgl:lwjgl-opengl:3.2.3"
|
|
||||||
implementation "org.openrndr:openrndr-gl3-natives-macos:$openrndrVersion"
|
|
||||||
implementation "io.github.rabbitcontrol:rcp:0.3.0"
|
implementation "io.github.rabbitcontrol:rcp:0.3.0"
|
||||||
|
implementation "com.google.zxing:core:3.3.0"
|
||||||
|
implementation "com.google.zxing:javase:3.3.0"
|
||||||
|
|
||||||
|
demoRuntimeOnly("org.openrndr:openrndr-gl3:$openrndrVersion")
|
||||||
|
demoRuntimeOnly("org.openrndr:openrndr-gl3-natives-$openrndrOS:$openrndrVersion")
|
||||||
|
demoImplementation(sourceSets.getByName("main").output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import org.openrndr.math.Vector4
|
|||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
configure {
|
configure {
|
||||||
width = 400
|
width = 800
|
||||||
height = 400
|
height = 800
|
||||||
}
|
}
|
||||||
|
|
||||||
program {
|
program {
|
||||||
val rabbit = RabbitControlServer()
|
val rabbit = RabbitControlServer()
|
||||||
val font= loadFont("orx-rabbit-control/src/test/resources/fonts/Roboto-Regular.ttf", 20.0)
|
val font= loadFont("orx-rabbit-control/src/demo/resources/fonts/Roboto-Regular.ttf", 20.0)
|
||||||
val settings = object {
|
val settings = object {
|
||||||
@TextParameter("A string")
|
@TextParameter("A string")
|
||||||
var s: String = "Hello"
|
var s: String = "Hello"
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import org.openrndr.KEY_HOME
|
||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.parameters.*
|
||||||
|
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 800
|
||||||
|
height = 800
|
||||||
|
}
|
||||||
|
|
||||||
|
program {
|
||||||
|
val rabbit = RabbitControlServer(showQRUntilClientConnects = false)
|
||||||
|
|
||||||
|
val settings = object {
|
||||||
|
@BooleanParameter("White on black")
|
||||||
|
var whiteOnBlack: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
rabbit.add(settings)
|
||||||
|
extend(rabbit)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example: only show the QR code when the [KEY_HOME] button is pressed
|
||||||
|
*/
|
||||||
|
keyboard.keyDown.listen {
|
||||||
|
when (it.key) {
|
||||||
|
KEY_HOME -> rabbit.showQRCode = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyboard.keyUp.listen {
|
||||||
|
when (it.key) {
|
||||||
|
KEY_HOME -> rabbit.showQRCode = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extend {
|
||||||
|
drawer.background(if (settings.whiteOnBlack) ColorRGBa.BLACK else ColorRGBa.WHITE)
|
||||||
|
drawer.fill = if (settings.whiteOnBlack) ColorRGBa.WHITE else ColorRGBa.BLACK
|
||||||
|
drawer.circle(drawer.bounds.center, 250.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,78 @@
|
|||||||
|
import com.google.zxing.BarcodeFormat
|
||||||
|
import com.google.zxing.client.j2se.MatrixToImageWriter
|
||||||
|
import com.google.zxing.qrcode.QRCodeWriter
|
||||||
import org.openrndr.Extension
|
import org.openrndr.Extension
|
||||||
import org.openrndr.Program
|
import org.openrndr.Program
|
||||||
import org.openrndr.color.ColorRGBa
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.draw.ColorBufferProxy
|
||||||
|
import org.openrndr.draw.Drawer
|
||||||
|
import org.openrndr.draw.isolated
|
||||||
|
import org.openrndr.extra.compositor.*
|
||||||
|
import org.openrndr.extra.fx.blend.Darken
|
||||||
import org.openrndr.extra.parameters.Parameter
|
import org.openrndr.extra.parameters.Parameter
|
||||||
import org.openrndr.extra.parameters.ParameterType
|
import org.openrndr.extra.parameters.ParameterType
|
||||||
import org.openrndr.extra.parameters.listParameters
|
import org.openrndr.extra.parameters.listParameters
|
||||||
import org.openrndr.extra.parameters.title
|
import org.openrndr.extras.imageFit.FitMethod
|
||||||
|
import org.openrndr.extras.imageFit.imageFit
|
||||||
|
import org.openrndr.internal.colorBufferLoader
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
import org.openrndr.math.Vector4
|
import org.openrndr.math.Vector4
|
||||||
|
import org.openrndr.math.mix
|
||||||
import org.rabbitcontrol.rcp.RCPServer
|
import org.rabbitcontrol.rcp.RCPServer
|
||||||
import org.rabbitcontrol.rcp.model.interfaces.IParameter
|
import org.rabbitcontrol.rcp.model.interfaces.IParameter
|
||||||
import org.rabbitcontrol.rcp.model.parameter.*
|
import org.rabbitcontrol.rcp.model.parameter.*
|
||||||
import org.rabbitcontrol.rcp.transport.websocket.server.WebsocketServerTransporterNetty
|
import org.rabbitcontrol.rcp.transport.websocket.server.WebsocketServerTransporterNetty
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
|
import java.io.File
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.net.Socket
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Path
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
|
|
||||||
|
|
||||||
class RabbitControlServer : Extension {
|
class RabbitControlServer(private val showQRUntilClientConnects: Boolean = true, port: Int = 10000) : Extension {
|
||||||
private val rabbitServer = RCPServer()
|
private val rabbitServer = RCPServer()
|
||||||
private val transporter = WebsocketServerTransporterNetty()
|
private val transporter = WebsocketServerTransporterNetty()
|
||||||
|
|
||||||
private var parameterMap = mutableMapOf<IParameter, Pair<Any, Parameter>>()
|
private var parameterMap = mutableMapOf<IParameter, Pair<Any, Parameter>>()
|
||||||
|
|
||||||
|
private var qrCodeImageProxy: ColorBufferProxy? = null
|
||||||
|
private var qrImagePath: Path? = null
|
||||||
|
private var qrOverlayComposition: Composite? = null
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate the opacity to make it look smooooth
|
||||||
|
*/
|
||||||
|
private var currentOpacity = 0.0
|
||||||
|
|
||||||
|
private var targetOpacity: Double = 0.0
|
||||||
|
get() = if (shouldShowQR) 0.8 else 0.0
|
||||||
|
|
||||||
|
private var shouldShowQR = false
|
||||||
|
get() = (rabbitServer.connectionCount == 0 && showQRUntilClientConnects) || showQRCode
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to manually show and hide the QR code and override the default
|
||||||
|
* behaviour of (only) showing the code when no clients are connected
|
||||||
|
*/
|
||||||
|
var showQRCode = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
rabbitServer.addTransporter(transporter)
|
rabbitServer.addTransporter(transporter)
|
||||||
transporter.bind(10000)
|
transporter.bind(port)
|
||||||
|
|
||||||
|
// FIXME please help me find a better way to get the local address
|
||||||
|
val socket = Socket()
|
||||||
|
socket.connect(InetSocketAddress("google.com", 80))
|
||||||
|
val ip = socket.localAddress.toString().replace("/", "")
|
||||||
|
|
||||||
|
val clientUrlWithHash = "https://rabbitcontrol.github.io/client/#$ip:$port"
|
||||||
|
qrCodeImageProxy = getQRCodeImageProxy(barcodeText = clientUrlWithHash)
|
||||||
|
println("RabbitControl Web Client: $clientUrlWithHash")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the object when it has been updated in RabbitControl
|
* Update the object when it has been updated in RabbitControl
|
||||||
@@ -70,7 +118,38 @@ class RabbitControlServer : Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun add(objectWithParameters: Any, label: String? = objectWithParameters.title()) {
|
override fun setup(program: Program) {
|
||||||
|
/**
|
||||||
|
* Creating the Composite for the overlay needs to happen in setup(),
|
||||||
|
* as we need access to [Program.drawer]
|
||||||
|
*/
|
||||||
|
qrOverlayComposition = compose {
|
||||||
|
layer {
|
||||||
|
draw {
|
||||||
|
program.drawer.isolated {
|
||||||
|
fill = ColorRGBa.WHITE.opacify(currentOpacity)
|
||||||
|
stroke = null
|
||||||
|
rectangle(0.0,0.0, width.toDouble(), height.toDouble())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer {
|
||||||
|
blend(Darken()) {
|
||||||
|
clip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
draw {
|
||||||
|
qrCodeImageProxy!!.colorBuffer?.let {
|
||||||
|
program.drawer.imageFit(it, program.width / 4.0,program.height / 4.0, program.width * .5, program.height * .5, 0.0,0.0, FitMethod.Contain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun add(objectWithParameters: Any) {
|
||||||
val parameters = objectWithParameters.listParameters()
|
val parameters = objectWithParameters.listParameters()
|
||||||
|
|
||||||
parameters.forEach {
|
parameters.forEach {
|
||||||
@@ -142,6 +221,26 @@ class RabbitControlServer : Extension {
|
|||||||
|
|
||||||
override fun shutdown(program: Program) {
|
override fun shutdown(program: Program) {
|
||||||
transporter.dispose()
|
transporter.dispose()
|
||||||
|
// Delete the temporary file
|
||||||
|
File(qrImagePath!!.toUri()).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME is it possible to avoid the file entirely?
|
||||||
|
private fun getQRCodeImageProxy(barcodeText: String): ColorBufferProxy {
|
||||||
|
val qrCodeWriter = QRCodeWriter()
|
||||||
|
val bitMatrix = qrCodeWriter.encode(barcodeText, BarcodeFormat.QR_CODE, 500, 500)
|
||||||
|
qrImagePath = FileSystems.getDefault().getPath("./qr.JPG")
|
||||||
|
MatrixToImageWriter.writeToPath(bitMatrix, "JPG", qrImagePath)
|
||||||
|
return colorBufferLoader.loadFromUrl(qrImagePath!!.toUri().toURL().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||||
|
currentOpacity = mix(targetOpacity, currentOpacity, 0.8)
|
||||||
|
|
||||||
|
// Don't draw if it isn't necessary
|
||||||
|
if (currentOpacity > 0.0) {
|
||||||
|
qrOverlayComposition?.draw(drawer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user