[orx-camera] Add ChangeEvents interface
This commit is contained in:
@@ -5,6 +5,7 @@ import org.openrndr.MouseEvents
|
|||||||
import org.openrndr.Program
|
import org.openrndr.Program
|
||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
import org.openrndr.draw.RenderTarget
|
import org.openrndr.draw.RenderTarget
|
||||||
|
import org.openrndr.events.Event
|
||||||
import org.openrndr.math.Matrix44
|
import org.openrndr.math.Matrix44
|
||||||
import org.openrndr.math.transforms.buildTransform
|
import org.openrndr.math.transforms.buildTransform
|
||||||
|
|
||||||
@@ -15,13 +16,27 @@ import org.openrndr.math.transforms.buildTransform
|
|||||||
*
|
*
|
||||||
* Usage: `extend(Camera2D())`
|
* Usage: `extend(Camera2D())`
|
||||||
*/
|
*/
|
||||||
class Camera2D : Extension {
|
class Camera2D : Extension, ChangeEvents {
|
||||||
override var enabled = true
|
override var enabled = true
|
||||||
|
|
||||||
var view = Matrix44.IDENTITY
|
var view = Matrix44.IDENTITY
|
||||||
|
|
||||||
|
override val changed = Event<Unit>()
|
||||||
|
|
||||||
|
private var dirty = true
|
||||||
|
set(value) {
|
||||||
|
if (value && !field) {
|
||||||
|
changed.trigger(Unit)
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
override val hasChanged: Boolean
|
||||||
|
get() = dirty
|
||||||
|
|
||||||
fun setupMouseEvents(mouse: MouseEvents) {
|
fun setupMouseEvents(mouse: MouseEvents) {
|
||||||
mouse.dragged.listen {
|
mouse.dragged.listen {
|
||||||
view = buildTransform { translate(it.dragDisplacement) } * view
|
view = buildTransform { translate(it.dragDisplacement) } * view
|
||||||
|
dirty = true
|
||||||
}
|
}
|
||||||
mouse.scrolled.listen {
|
mouse.scrolled.listen {
|
||||||
val scaleFactor = 1.0 - it.rotation.y * 0.03
|
val scaleFactor = 1.0 - it.rotation.y * 0.03
|
||||||
@@ -30,6 +45,7 @@ class Camera2D : Extension {
|
|||||||
scale(scaleFactor)
|
scale(scaleFactor)
|
||||||
translate(-it.position)
|
translate(-it.position)
|
||||||
} * view
|
} * view
|
||||||
|
dirty = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun setup(program: Program) {
|
override fun setup(program: Program) {
|
||||||
@@ -43,6 +59,7 @@ class Camera2D : Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||||
|
dirty = false
|
||||||
drawer.popTransforms()
|
drawer.popTransforms()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
orx-camera/src/commonMain/kotlin/ChangeEvents.kt
Normal file
8
orx-camera/src/commonMain/kotlin/ChangeEvents.kt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package org.openrndr.extra.camera
|
||||||
|
|
||||||
|
import org.openrndr.events.Event
|
||||||
|
|
||||||
|
interface ChangeEvents {
|
||||||
|
val changed : Event<Unit>
|
||||||
|
val hasChanged: Boolean
|
||||||
|
}
|
||||||
@@ -3,14 +3,22 @@ package org.openrndr.extra.camera
|
|||||||
import org.openrndr.Extension
|
import org.openrndr.Extension
|
||||||
import org.openrndr.Program
|
import org.openrndr.Program
|
||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
|
import org.openrndr.events.Event
|
||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension that provides orbital camera view and controls.
|
* Extension that provides orbital camera view and controls.
|
||||||
*/
|
*/
|
||||||
class Orbital : Extension {
|
class Orbital : Extension, ChangeEvents {
|
||||||
override var enabled: Boolean = true
|
override var enabled: Boolean = true
|
||||||
|
|
||||||
|
override val changed = Event<Unit>()
|
||||||
|
override val hasChanged: Boolean
|
||||||
|
get() {
|
||||||
|
return camera.hasChanged
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var eye = Vector3.UNIT_Z * 10.0
|
var eye = Vector3.UNIT_Z * 10.0
|
||||||
var lookAt = Vector3.ZERO
|
var lookAt = Vector3.ZERO
|
||||||
var near = 0.1
|
var near = 0.1
|
||||||
@@ -28,6 +36,7 @@ class Orbital : Extension {
|
|||||||
val camera by lazy {
|
val camera by lazy {
|
||||||
OrbitalCamera(eye, lookAt, fov, near, far, projectionType).apply {
|
OrbitalCamera(eye, lookAt, fov, near, far, projectionType).apply {
|
||||||
dampingFactor = this@Orbital.dampingFactor
|
dampingFactor = this@Orbital.dampingFactor
|
||||||
|
this.changed.listen(this@Orbital.changed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val controls by lazy { OrbitalControls(camera, userInteraction, keySpeed) }
|
val controls by lazy { OrbitalControls(camera, userInteraction, keySpeed) }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.openrndr.Extension
|
|||||||
import org.openrndr.Program
|
import org.openrndr.Program
|
||||||
import org.openrndr.draw.DepthTestPass
|
import org.openrndr.draw.DepthTestPass
|
||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
|
import org.openrndr.events.Event
|
||||||
import org.openrndr.math.Matrix44
|
import org.openrndr.math.Matrix44
|
||||||
import org.openrndr.math.Spherical
|
import org.openrndr.math.Spherical
|
||||||
import org.openrndr.math.Vector3
|
import org.openrndr.math.Vector3
|
||||||
@@ -17,7 +18,21 @@ enum class ProjectionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OrbitalCamera(eye: Vector3 = Vector3.ZERO, lookAt: Vector3 = Vector3.UNIT_Z, var fov: Double = 90.0, var near: Double = 0.1, var far: Double = 1000.0, var projectionType: ProjectionType = ProjectionType.PERSPECTIVE) : Extension {
|
class OrbitalCamera(
|
||||||
|
eye: Vector3 = Vector3.ZERO,
|
||||||
|
lookAt: Vector3 = Vector3.UNIT_Z,
|
||||||
|
var fov: Double = 90.0,
|
||||||
|
var near: Double = 0.1,
|
||||||
|
var far: Double = 1000.0,
|
||||||
|
var projectionType: ProjectionType = ProjectionType.PERSPECTIVE
|
||||||
|
) : Extension, ChangeEvents {
|
||||||
|
|
||||||
|
override val changed = Event<Unit>()
|
||||||
|
|
||||||
|
override val hasChanged: Boolean
|
||||||
|
get() = dirty
|
||||||
|
|
||||||
|
|
||||||
// current position in spherical coordinates
|
// current position in spherical coordinates
|
||||||
var spherical = Spherical.fromVector(eye)
|
var spherical = Spherical.fromVector(eye)
|
||||||
private set
|
private set
|
||||||
@@ -32,6 +47,12 @@ class OrbitalCamera(eye: Vector3 = Vector3.ZERO, lookAt: Vector3 = Vector3.UNIT_
|
|||||||
private var sphericalEnd = Spherical.fromVector(eye)
|
private var sphericalEnd = Spherical.fromVector(eye)
|
||||||
private var lookAtEnd = lookAt
|
private var lookAtEnd = lookAt
|
||||||
private var dirty: Boolean = true
|
private var dirty: Boolean = true
|
||||||
|
set(value) {
|
||||||
|
if (value && !field) {
|
||||||
|
changed.trigger(Unit)
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
}
|
||||||
private var lastSeconds: Double = -1.0
|
private var lastSeconds: Double = -1.0
|
||||||
|
|
||||||
var fovEnd = fov
|
var fovEnd = fov
|
||||||
@@ -127,19 +148,21 @@ class OrbitalCamera(eye: Vector3 = Vector3.ZERO, lookAt: Vector3 = Vector3.UNIT_
|
|||||||
if (!dirty) return
|
if (!dirty) return
|
||||||
dirty = false
|
dirty = false
|
||||||
|
|
||||||
val dampingFactor = if (dampingFactor > 0.0) { dampingFactor * timeDelta / 0.0060 } else 1.0
|
val dampingFactor = if (dampingFactor > 0.0) {
|
||||||
|
dampingFactor * timeDelta / 0.0060
|
||||||
|
} else 1.0
|
||||||
val sphericalDelta = sphericalEnd - spherical
|
val sphericalDelta = sphericalEnd - spherical
|
||||||
val lookAtDelta = lookAtEnd - lookAt
|
val lookAtDelta = lookAtEnd - lookAt
|
||||||
val fovDelta = fovEnd - fov
|
val fovDelta = fovEnd - fov
|
||||||
val magnitudeDelta = magnitudeEnd - magnitude
|
val magnitudeDelta = magnitudeEnd - magnitude
|
||||||
if (
|
if (
|
||||||
abs(sphericalDelta.radius) > EPSILON ||
|
abs(sphericalDelta.radius) > EPSILON ||
|
||||||
abs(sphericalDelta.theta) > EPSILON ||
|
abs(sphericalDelta.theta) > EPSILON ||
|
||||||
abs(sphericalDelta.phi) > EPSILON ||
|
abs(sphericalDelta.phi) > EPSILON ||
|
||||||
abs(lookAtDelta.x) > EPSILON ||
|
abs(lookAtDelta.x) > EPSILON ||
|
||||||
abs(lookAtDelta.y) > EPSILON ||
|
abs(lookAtDelta.y) > EPSILON ||
|
||||||
abs(lookAtDelta.z) > EPSILON ||
|
abs(lookAtDelta.z) > EPSILON ||
|
||||||
abs(fovDelta) > EPSILON
|
abs(fovDelta) > EPSILON
|
||||||
) {
|
) {
|
||||||
fov += (fovDelta * dampingFactor)
|
fov += (fovDelta * dampingFactor)
|
||||||
spherical += (sphericalDelta * dampingFactor)
|
spherical += (sphericalDelta * dampingFactor)
|
||||||
@@ -222,4 +245,4 @@ fun OrbitalCamera.applyTo(drawer: Drawer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pow(a:Double, x:Double): Double = a.pow(x)
|
private fun pow(a: Double, x: Double): Double = a.pow(x)
|
||||||
@@ -3,6 +3,7 @@ package org.openrndr.extra.camera
|
|||||||
import org.openrndr.Extension
|
import org.openrndr.Extension
|
||||||
import org.openrndr.Program
|
import org.openrndr.Program
|
||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
|
import org.openrndr.events.Event
|
||||||
import org.openrndr.extra.parameters.Description
|
import org.openrndr.extra.parameters.Description
|
||||||
import org.openrndr.extra.parameters.DoubleParameter
|
import org.openrndr.extra.parameters.DoubleParameter
|
||||||
import org.openrndr.extra.parameters.Vector3Parameter
|
import org.openrndr.extra.parameters.Vector3Parameter
|
||||||
@@ -13,12 +14,25 @@ import org.openrndr.math.Vector3
|
|||||||
* Extension that provides orbital camera through annotated parameters
|
* Extension that provides orbital camera through annotated parameters
|
||||||
*/
|
*/
|
||||||
@Description("Orbital camera")
|
@Description("Orbital camera")
|
||||||
class ParametricOrbital : Extension {
|
class ParametricOrbital : Extension, ChangeEvents {
|
||||||
override var enabled: Boolean = true
|
override var enabled: Boolean = true
|
||||||
|
|
||||||
|
override val changed = Event<Unit>()
|
||||||
|
override val hasChanged: Boolean
|
||||||
|
get() = dirty
|
||||||
|
private var dirty = true
|
||||||
|
set(value) {
|
||||||
|
if (value && !field) {
|
||||||
|
changed.trigger(Unit)
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
}
|
||||||
@DoubleParameter("fov", 1.0, 90.0, order = 0)
|
@DoubleParameter("fov", 1.0, 90.0, order = 0)
|
||||||
var fov = 45.0
|
var fov = 45.0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
field = value
|
field = value
|
||||||
camera.zoomTo(fov)
|
camera.zoomTo(fov)
|
||||||
}
|
}
|
||||||
@@ -32,6 +46,9 @@ class ParametricOrbital : Extension {
|
|||||||
@DoubleParameter("phi", 0.0, 180.0, order = 2)
|
@DoubleParameter("phi", 0.0, 180.0, order = 2)
|
||||||
var phi = 0.0
|
var phi = 0.0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
field = value
|
field = value
|
||||||
camera.rotateTo(theta, phi.coerceAtLeast(1E-3))
|
camera.rotateTo(theta, phi.coerceAtLeast(1E-3))
|
||||||
}
|
}
|
||||||
@@ -39,6 +56,9 @@ class ParametricOrbital : Extension {
|
|||||||
@DoubleParameter("theta", -180.0, 180.0, order = 1)
|
@DoubleParameter("theta", -180.0, 180.0, order = 1)
|
||||||
var theta = 0.0
|
var theta = 0.0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
field = value
|
field = value
|
||||||
camera.rotateTo(theta, phi.coerceAtLeast(1E-3))
|
camera.rotateTo(theta, phi.coerceAtLeast(1E-3))
|
||||||
}
|
}
|
||||||
@@ -47,6 +67,9 @@ class ParametricOrbital : Extension {
|
|||||||
@DoubleParameter("orbit radius", 0.1, 100.0, order = 3)
|
@DoubleParameter("orbit radius", 0.1, 100.0, order = 3)
|
||||||
var radius = 10.0
|
var radius = 10.0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
field = value
|
field = value
|
||||||
camera.dollyTo(radius)
|
camera.dollyTo(radius)
|
||||||
}
|
}
|
||||||
@@ -55,6 +78,9 @@ class ParametricOrbital : Extension {
|
|||||||
@Vector3Parameter("center", order = 4)
|
@Vector3Parameter("center", order = 4)
|
||||||
var center = Vector3.ZERO
|
var center = Vector3.ZERO
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
field = value
|
field = value
|
||||||
camera.panTo(value)
|
camera.panTo(value)
|
||||||
}
|
}
|
||||||
@@ -72,6 +98,7 @@ class ParametricOrbital : Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||||
|
dirty = false
|
||||||
camera.afterDraw(drawer, program)
|
camera.afterDraw(drawer, program)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user