diff --git a/orx-camera/src/commonMain/kotlin/Camera2D.kt b/orx-camera/src/commonMain/kotlin/Camera2D.kt
index 9887c136..c0c65e81 100644
--- a/orx-camera/src/commonMain/kotlin/Camera2D.kt
+++ b/orx-camera/src/commonMain/kotlin/Camera2D.kt
@@ -4,6 +4,7 @@ import org.openrndr.Extension
import org.openrndr.MouseEvents
import org.openrndr.Program
import org.openrndr.draw.Drawer
+import org.openrndr.draw.RenderTarget
import org.openrndr.math.Matrix44
import org.openrndr.math.transforms.buildTransform
@@ -36,6 +37,14 @@ class Camera2D : Extension {
}
override fun beforeDraw(drawer: Drawer, program: Program) {
+ drawer.pushTransforms()
+ drawer.ortho(RenderTarget.active)
drawer.view = view
}
-}
\ No newline at end of file
+
+ override fun afterDraw(drawer: Drawer, program: Program) {
+ drawer.popTransforms()
+ }
+}
+
+
diff --git a/orx-camera/src/commonMain/kotlin/OrbitalCamera.kt b/orx-camera/src/commonMain/kotlin/OrbitalCamera.kt
index 626180a6..5f814844 100644
--- a/orx-camera/src/commonMain/kotlin/OrbitalCamera.kt
+++ b/orx-camera/src/commonMain/kotlin/OrbitalCamera.kt
@@ -168,6 +168,9 @@ class OrbitalCamera(eye: Vector3 = Vector3.ZERO, lookAt: Vector3 = Vector3.UNIT_
override var enabled: Boolean = true
override fun beforeDraw(drawer: Drawer, program: Program) {
+
+ drawer.pushTransforms()
+
if (lastSeconds == -1.0) lastSeconds = program.seconds
val delta = program.seconds - lastSeconds
@@ -178,8 +181,7 @@ class OrbitalCamera(eye: Vector3 = Vector3.ZERO, lookAt: Vector3 = Vector3.UNIT_
}
override fun afterDraw(drawer: Drawer, program: Program) {
- drawer.view = Matrix44.IDENTITY
- drawer.ortho()
+ drawer.popTransforms()
}
}
@@ -206,7 +208,6 @@ fun OrbitalCamera.isolated(drawer: Drawer, function: Drawer.() -> Unit) {
* if you don't need to revert back to the orthographic projection.
*/
fun OrbitalCamera.applyTo(drawer: Drawer) {
-
if (projectionType == ProjectionType.PERSPECTIVE) {
drawer.perspective(fov, drawer.width.toDouble() / drawer.height, near, far)
} else {
diff --git a/orx-camera/src/commonMain/kotlin/OrbitalControls.kt b/orx-camera/src/commonMain/kotlin/OrbitalControls.kt
index d1cf619e..5b0b8702 100644
--- a/orx-camera/src/commonMain/kotlin/OrbitalControls.kt
+++ b/orx-camera/src/commonMain/kotlin/OrbitalControls.kt
@@ -57,14 +57,14 @@ class OrbitalControls(
// half of the fov is center to top of screen
val targetDistance = offset.length * tan(fov.asRadians / 2)
- val panX = (2 * delta.x * targetDistance / program.window.size.x)
- val panY = (2 * delta.y * targetDistance / program.window.size.y)
+ val panX = (2 * delta.x * targetDistance / program.width)
+ val panY = (2 * delta.y * targetDistance / program.height)
orbitalCamera.pan(panX, -panY, 0.0)
} else {
- val rotX = 360.0 * delta.x / program.window.size.x
- val rotY = 360.0 * delta.y / program.window.size.y
+ val rotX = 360.0 * delta.x / program.width
+ val rotY = 360.0 * delta.y / program.height
orbitalCamera.rotate(rotX, rotY)
}
}
diff --git a/orx-jvm/orx-file-watcher/src/main/kotlin/FileWatcher.kt b/orx-jvm/orx-file-watcher/src/main/kotlin/FileWatcher.kt
index 8e99e8b4..61373f6d 100644
--- a/orx-jvm/orx-file-watcher/src/main/kotlin/FileWatcher.kt
+++ b/orx-jvm/orx-file-watcher/src/main/kotlin/FileWatcher.kt
@@ -138,16 +138,3 @@ private val watchThread by lazy {
}
}
}
-
-fun main() {
- val a = watchFile(Program(), File("README.md")) {
- it.readText()
- }
- a.stop()
- a.triggerChange()
- while (true) {
- println(a())
- Thread.sleep(2000)
- }
-}
-
diff --git a/orx-jvm/orx-olive/src/main/kotlin/Olive.kt b/orx-jvm/orx-olive/src/main/kotlin/Olive.kt
index 32c1a7f6..5210fd88 100644
--- a/orx-jvm/orx-olive/src/main/kotlin/Olive.kt
+++ b/orx-jvm/orx-olive/src/main/kotlin/Olive.kt
@@ -77,7 +77,6 @@ class Olive
(val resources: Resources? = null, private var scriptMod
val originalExtensions = program.extensions.map { it }
val trackedListeners = listOf>(program.mouse.buttonDown,
program.mouse.buttonUp,
- program.mouse.clicked,
program.mouse.dragged,
program.mouse.moved,
program.mouse.scrolled,
diff --git a/orx-jvm/orx-olive/src/main/kotlin/OliveProgram.kt b/orx-jvm/orx-olive/src/main/kotlin/OliveProgram.kt
index 91cf7b31..d9174558 100644
--- a/orx-jvm/orx-olive/src/main/kotlin/OliveProgram.kt
+++ b/orx-jvm/orx-olive/src/main/kotlin/OliveProgram.kt
@@ -2,13 +2,14 @@ package org.openrndr.extra.olive
import org.openrndr.ApplicationBuilder
import org.openrndr.Program
+import org.openrndr.ProgramImplementation
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.reflect.KProperty
import kotlin.streams.toList
-open class OliveProgram(private val sourceLocation: String, private val scriptHost: OliveScriptHost, resources: Resources?) : Program() {
+open class OliveProgram(private val sourceLocation: String, private val scriptHost: OliveScriptHost, resources: Resources?) : ProgramImplementation() {
val olive = extend(Olive(scriptMode = ScriptMode.OLIVE_PROGRAM, resources = resources)) {
script = sourceLocation
scriptHost = this@OliveProgram.scriptHost
diff --git a/orx-jvm/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt b/orx-jvm/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt
index 5ba7e904..0c2e95a7 100644
--- a/orx-jvm/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt
+++ b/orx-jvm/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt
@@ -73,7 +73,7 @@ class ControlManager : Extension {
var body: Element? = null
val layouter = Layouter()
val fontManager = FontManager()
- lateinit var window: Program.Window
+ lateinit var window: Window
private val renderTargetCache = HashMap()
lateinit var program: Program
@@ -524,7 +524,7 @@ class ControlManager : Extension {
}
profile("draw image") {
- drawer.ortho()
+ drawer.ortho(RenderTarget.active)
drawer.view = Matrix44.IDENTITY
drawer.defaults()
program.drawer.image(renderTarget.colorBuffer(0), 0.0, 0.0)
diff --git a/orx-mesh-generators/build.gradle.kts b/orx-mesh-generators/build.gradle.kts
index a051393a..91e9555b 100644
--- a/orx-mesh-generators/build.gradle.kts
+++ b/orx-mesh-generators/build.gradle.kts
@@ -6,4 +6,6 @@ dependencies {
implementation(libs.openrndr.application)
implementation(libs.openrndr.math)
demoImplementation(project(":orx-shapes"))
+ demoImplementation(project(":orx-mesh-generators"))
+ demoImplementation(project(":orx-camera"))
}
\ No newline at end of file
diff --git a/orx-palette/src/main/kotlin/PaletteStudio.kt b/orx-palette/src/main/kotlin/PaletteStudio.kt
index c9e1b6a1..c88121ad 100644
--- a/orx-palette/src/main/kotlin/PaletteStudio.kt
+++ b/orx-palette/src/main/kotlin/PaletteStudio.kt
@@ -3,9 +3,7 @@ package org.openrndr.extra.palette
import mu.KotlinLogging
import com.google.gson.GsonBuilder
import com.google.gson.JsonParseException
-import org.openrndr.Extension
-import org.openrndr.Keyboard
-import org.openrndr.Program
+import org.openrndr.*
import org.openrndr.extra.noise.Random
import org.openrndr.color.ColorRGBa
import org.openrndr.color.ColorRGBa.Companion.BLACK
@@ -14,7 +12,6 @@ import org.openrndr.color.ColorRGBa.Companion.PINK
import org.openrndr.color.ColorRGBa.Companion.RED
import org.openrndr.color.ColorRGBa.Companion.YELLOW
import org.openrndr.color.ColorRGBa.Companion.fromHex
-import org.openrndr.resourceUrl
import java.io.File
import java.net.URL
import kotlin.math.max
@@ -232,7 +229,7 @@ class PaletteStudio(
palettes.clear()
}
- private fun registerKeybindings(keyboard: Keyboard) {
+ private fun registerKeybindings(keyboard: KeyEvents) {
keyboard.keyDown.listen {
if (!it.propagationCancelled) {
if (it.name == "$randomPaletteKey") {
diff --git a/orx-time-operators/src/main/kotlin/LFO.kt b/orx-time-operators/src/main/kotlin/LFO.kt
index cd883e1e..edbbf559 100644
--- a/orx-time-operators/src/main/kotlin/LFO.kt
+++ b/orx-time-operators/src/main/kotlin/LFO.kt
@@ -28,7 +28,8 @@ class LFO(wave: LFOWave = LFOWave.Saw) : TimeTools {
private var time = 0.0
override fun tick(seconds: Double, deltaTime: Double, frameCount: Int) {
- time += deltaTime
+ //time += deltaTime
+ time = seconds
}
fun sample(frequency: Double = 1.0, phase: Double = 0.0): Double {
diff --git a/orx-time-operators/src/main/kotlin/TimeOperators.kt b/orx-time-operators/src/main/kotlin/TimeOperators.kt
index c7fbcc5f..60cfdf7e 100644
--- a/orx-time-operators/src/main/kotlin/TimeOperators.kt
+++ b/orx-time-operators/src/main/kotlin/TimeOperators.kt
@@ -18,6 +18,6 @@ class TimeOperators : Extension {
}
override fun beforeDraw(drawer: Drawer, program: Program) {
- operators.forEach { it.tick(program.seconds, program.deltaTime, program.frameCount) }
+ operators.forEach { it.tick(program.seconds, 0.0, 0) }
}
}
diff --git a/orx-view-box/README.md b/orx-view-box/README.md
new file mode 100644
index 00000000..6b36727c
--- /dev/null
+++ b/orx-view-box/README.md
@@ -0,0 +1,4 @@
+# orx-view-box
+
+Tools to provide view box support
+
diff --git a/orx-view-box/build.gradle.kts b/orx-view-box/build.gradle.kts
new file mode 100644
index 00000000..4ef6a00c
--- /dev/null
+++ b/orx-view-box/build.gradle.kts
@@ -0,0 +1,43 @@
+import ScreenshotsHelper.collectScreenshots
+
+plugins {
+ org.openrndr.extra.convention.`kotlin-multiplatform`
+}
+
+kotlin {
+ jvm {
+ @Suppress("UNUSED_VARIABLE")
+ val demo by compilations.getting {
+ // TODO: Move demos to /jvmDemo
+ defaultSourceSet {
+ kotlin.srcDir("src/demo/kotlin")
+ }
+ collectScreenshots { }
+ }
+ testRuns["test"].executionTask {
+ useJUnitPlatform {
+ includeEngines("spek2")
+ }
+ }
+ }
+
+ sourceSets {
+ @Suppress("UNUSED_VARIABLE")
+ val commonMain by getting {
+ dependencies {
+ implementation(libs.openrndr.application)
+ implementation(libs.openrndr.draw)
+ }
+ }
+
+ @Suppress("UNUSED_VARIABLE")
+ val jvmDemo by getting {
+ dependencies {
+ implementation(project(":orx-camera"))
+ implementation(project(":orx-fx"))
+ implementation(project(":orx-mesh-generators"))
+ implementation(project(":orx-view-box"))
+ }
+ }
+ }
+}
diff --git a/orx-view-box/src/commonMain/kotlin/ViewBox.kt b/orx-view-box/src/commonMain/kotlin/ViewBox.kt
new file mode 100644
index 00000000..33f816d9
--- /dev/null
+++ b/orx-view-box/src/commonMain/kotlin/ViewBox.kt
@@ -0,0 +1,213 @@
+package org.openrndr.extra.viewbox
+
+
+import org.openrndr.*
+import org.openrndr.color.ColorRGBa
+import org.openrndr.draw.*
+import org.openrndr.events.Event
+import org.openrndr.math.Vector2
+import org.openrndr.shape.Rectangle
+import kotlin.math.ceil
+
+class ViewBox(override val program: Program, var clientArea: Rectangle) : Program by program {
+
+ override var width: Int
+ get() {
+ return renderTarget?.width ?: clientArea.width.toInt()
+ }
+ set(value) {}
+
+ override var height: Int
+ get() = renderTarget?.height ?: clientArea.height.toInt()
+ set(value) {}
+
+ private var renderTarget: RenderTarget? = null
+ private var resolved: ColorBuffer? = null
+
+ override val extensions: MutableList = mutableListOf()
+
+ override val mouse: MouseEvents = object :MouseEvents{
+ override val buttonDown = Event()
+ override val buttonUp = Event()
+ override val dragged = Event()
+ override val entered = Event()
+ override val exited = Event()
+ override val moved = Event()
+ override val position: Vector2
+ get() = TODO("Not yet implemented")
+ override val pressedButtons: MutableSet
+ get() = TODO("Not yet implemented")
+ override val scrolled = Event()
+ }
+
+ override val keyboard: KeyEvents = object: KeyEvents {
+ override val character: Event = Event()
+ override val keyDown: Event = Event()
+ override val keyRepeat: Event = Event()
+ override val keyUp: Event = Event()
+ }
+
+ override val pointers: Pointers by lazy { program.pointers }
+
+ var hasInputFocus = false
+ init {
+ program.mouse.moved.listen {
+ if (it.position in clientArea && !it.propagationCancelled) {
+ hasInputFocus = true
+ mouse.moved.trigger(it.copy(position = it.position - clientArea.corner))
+ it.cancelPropagation()
+ } else if (it.position !in clientArea) {
+ hasInputFocus = false
+ }
+ }
+
+ program.mouse.buttonUp.listen {
+ if (it.position in clientArea && !it.propagationCancelled) {
+ mouse.buttonUp.trigger(it.copy(position = it.position - clientArea.corner))
+ it.cancelPropagation()
+ }
+ }
+ program.mouse.dragged.listen {
+ if (it.position in clientArea && !it.propagationCancelled) {
+ mouse.dragged.trigger(it.copy(position = it.position - clientArea.corner))
+ it.cancelPropagation()
+ }
+ }
+ program.mouse.buttonDown.listen {
+ if (it.position in clientArea && !it.propagationCancelled) {
+ mouse.buttonDown.trigger(it.copy(position = it.position - clientArea.corner))
+ it.cancelPropagation()
+ }
+ }
+
+ program.mouse.scrolled.listen {
+ if (it.position in clientArea && !it.propagationCancelled) {
+ mouse.scrolled.trigger(it.copy(position = it.position - clientArea.corner))
+ it.cancelPropagation()
+ }
+ }
+
+ program.keyboard.keyDown.listen {
+ if (hasInputFocus && !it.propagationCancelled) {
+ keyboard.keyDown.trigger(it)
+ it.cancelPropagation()
+ }
+ }
+
+ program.keyboard.keyUp.listen {
+ if (hasInputFocus && !it.propagationCancelled) {
+ keyboard.keyUp.trigger(it)
+ it.cancelPropagation()
+ }
+ }
+
+ program.keyboard.keyRepeat.listen {
+ if (hasInputFocus && !it.propagationCancelled) {
+ keyboard.keyRepeat.trigger(it)
+ it.cancelPropagation()
+ }
+ }
+
+ program.keyboard.character.listen {
+ if (hasInputFocus && !it.propagationCancelled) {
+ keyboard.character.trigger(it)
+ it.cancelPropagation()
+ }
+ }
+ }
+
+ override fun extend(extension: T): T {
+ extensions.add(extension)
+ extension.setup(this)
+ return extension
+ }
+
+ override fun extend(extension: T, configure: T.() -> Unit): T {
+ extensions.add(extension)
+ extension.configure()
+ extension.setup(this)
+ return extension
+ }
+
+ override fun extend(stage: ExtensionStage, userDraw: Program.() -> Unit) {
+ val functionExtension = when (stage) {
+ ExtensionStage.SETUP ->
+ object : Extension {
+ override var enabled: Boolean = true
+ override fun setup(program: Program) {
+ program.userDraw()
+ }
+ }
+ ExtensionStage.BEFORE_DRAW ->
+ object : Extension {
+ override var enabled: Boolean = true
+ override fun beforeDraw(drawer: Drawer, program: Program) {
+ program.userDraw()
+ }
+ }
+ ExtensionStage.AFTER_DRAW ->
+ object : Extension {
+ override var enabled: Boolean = true
+ override fun afterDraw(drawer: Drawer, program: Program) {
+ program.userDraw()
+ }
+ }
+ }
+ extensions.add(functionExtension)
+ }
+
+ override fun draw() {
+
+ val widthCeil = ceil(clientArea.width).toInt()
+ val heightCeil = ceil(clientArea.height).toInt()
+
+ val lrt = renderTarget
+ if (lrt != null) {
+ if (lrt.width != widthCeil || lrt.height != heightCeil) {
+ lrt.colorBuffer(0).destroy()
+ lrt.depthBuffer?.destroy()
+ lrt.detachColorAttachments()
+ lrt.detachDepthBuffer()
+ lrt.destroy()
+ renderTarget = null
+
+ resolved?.destroy()
+ resolved = null
+ }
+
+ }
+
+ if (renderTarget == null) {
+ val art = RenderTarget.active
+ renderTarget = renderTarget(widthCeil, heightCeil, art.contentScale, art.multisample) {
+ colorBuffer()
+ depthBuffer()
+ }
+ if (art.multisample != BufferMultisample.Disabled) {
+ resolved = colorBuffer(widthCeil, heightCeil, art.contentScale, multisample = art.multisample)
+ }
+ }
+
+ program.drawer.isolatedWithTarget(renderTarget!!) {
+ drawer.clear(ColorRGBa.BLACK)
+ drawer.defaults()
+ drawer.ortho(renderTarget!!)
+ for (extension in extensions) {
+ extension.beforeDraw(program.drawer, this@ViewBox)
+ }
+ for (extension in extensions.reversed()) {
+ extension.afterDraw(program.drawer, this@ViewBox)
+ }
+ program.drawer.defaults()
+ }
+ program.drawer.isolated {
+ program.drawer.image(renderTarget!!.colorBuffer(0), clientArea.corner)
+ }
+ }
+}
+
+fun Program.viewBox(area: Rectangle, f: ViewBox.() -> Unit): ViewBox {
+ val viewBox = ViewBox(this, area)
+ viewBox.f()
+ return viewBox
+}
\ No newline at end of file
diff --git a/orx-view-box/src/demo/kotlin/DemoViewBox01.kt b/orx-view-box/src/demo/kotlin/DemoViewBox01.kt
new file mode 100644
index 00000000..e4ea58eb
--- /dev/null
+++ b/orx-view-box/src/demo/kotlin/DemoViewBox01.kt
@@ -0,0 +1,58 @@
+
+import org.openrndr.application
+import org.openrndr.draw.DrawPrimitive
+import org.openrndr.extensions.Screenshots
+import org.openrndr.extra.camera.Camera2D
+import org.openrndr.extra.camera.Orbital
+import org.openrndr.extra.fx.Post
+import org.openrndr.extra.fx.blur.ApproximateGaussianBlur
+import org.openrndr.extra.meshgenerators.boxMesh
+import org.openrndr.extra.viewbox.viewBox
+import org.openrndr.shape.Rectangle
+
+fun main() {
+ application {
+ configure {
+ width = 800
+ height = 800
+ }
+ program {
+ val vbx = viewBox(Rectangle(0.0, 0.0, 200.0, 800.0)) {
+ extend(Screenshots())
+ extend(Camera2D())
+ extend {
+ drawer.rectangle(20.0, 20.0, 100.0, 100.0)
+ }
+ }
+
+ val vbx2 = viewBox(Rectangle(200.0, 0.0, 200.0, 800.0)) {
+ extend(Post()) {
+ val blur = ApproximateGaussianBlur()
+ blur.sigma = 10.0
+ blur.window = 25
+ post { i, o ->
+ blur.apply(i, o)
+ }
+ }
+ extend(Camera2D())
+ extend {
+ drawer.rectangle(20.0, 20.0, 100.0, 100.0)
+ }
+ }
+
+ val vbx3d = viewBox(Rectangle(400.0, 0.0, 400.0, 800.0)) {
+ extend(Orbital())
+ val cube = boxMesh()
+ extend {
+ drawer.vertexBuffer(cube, DrawPrimitive.TRIANGLES)
+ }
+ }
+
+ extend {
+ vbx.draw()
+ vbx2.draw()
+ vbx3d.draw()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 570259c6..cae2febf 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -82,6 +82,7 @@ include(
"orx-jvm:orx-kinect-v1-demo",
"orx-jvm:orx-video-profiles",
"orx-depth-camera",
- "orx-jvm:orx-depth-camera-calibrator"
+ "orx-jvm:orx-depth-camera-calibrator",
+ "orx-view-box"
)
)
\ No newline at end of file