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:
Rein van der Woerd
2020-04-07 17:04:35 +02:00
committed by GitHub
parent b98d1b7369
commit 5d3eadd156
6 changed files with 177 additions and 11 deletions

View File

@@ -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.

View File

@@ -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)
} }

View File

@@ -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"

View File

@@ -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)
}
}
}

View File

@@ -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)
}
} }
} }