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