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">
|
||||
</a>
|
||||
|
||||
For examples, check out the [demo](./src/demo/kotlin) folder.
|
||||
|
||||
|
||||
|
||||
### Using the web client
|
||||
|
||||
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 {
|
||||
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 "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 {
|
||||
configure {
|
||||
width = 400
|
||||
height = 400
|
||||
width = 800
|
||||
height = 800
|
||||
}
|
||||
|
||||
program {
|
||||
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 {
|
||||
@TextParameter("A string")
|
||||
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.Program
|
||||
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.ParameterType
|
||||
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.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.mix
|
||||
import org.rabbitcontrol.rcp.RCPServer
|
||||
import org.rabbitcontrol.rcp.model.interfaces.IParameter
|
||||
import org.rabbitcontrol.rcp.model.parameter.*
|
||||
import org.rabbitcontrol.rcp.transport.websocket.server.WebsocketServerTransporterNetty
|
||||
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
|
||||
|
||||
|
||||
class RabbitControlServer : Extension {
|
||||
class RabbitControlServer(private val showQRUntilClientConnects: Boolean = true, port: Int = 10000) : Extension {
|
||||
private val rabbitServer = RCPServer()
|
||||
private val transporter = WebsocketServerTransporterNetty()
|
||||
|
||||
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 {
|
||||
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
|
||||
@@ -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()
|
||||
|
||||
parameters.forEach {
|
||||
@@ -142,6 +221,26 @@ class RabbitControlServer : Extension {
|
||||
|
||||
override fun shutdown(program: Program) {
|
||||
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