Skip to content

Commit a767a20

Browse files
committed
add scene interaction logic
1 parent a55ce01 commit a767a20

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
package solve.rendering.canvas
22

33
import javafx.beans.InvalidationListener
4+
import javafx.event.EventHandler
5+
import javafx.scene.input.MouseButton
6+
import javafx.scene.input.MouseEvent
7+
import javafx.scene.input.ScrollEvent
48
import org.joml.Vector2f
9+
import org.joml.Vector2i
510
import solve.rendering.engine.rendering.renderers.FramesRenderer
611
import solve.rendering.engine.scene.Scene
12+
import solve.rendering.engine.utils.minus
13+
import solve.rendering.engine.utils.toFloatVector
714
import solve.scene.SceneFacade
815
import solve.scene.controller.SceneController
916
import solve.utils.ServiceLocator
10-
import tornadofx.*
17+
import kotlin.math.pow
18+
import kotlin.math.sign
1119

1220
class SceneCanvas : OpenGLCanvas() {
1321
private var sceneController: SceneController? = null
1422
private var framesRenderer: FramesRenderer? = null
1523
private var canvasScene: Scene? = null
1624

25+
private var mousePosition = Vector2i()
26+
27+
private var isDraggingScene = false
28+
private var dragStartCameraPosition = Vector2f()
29+
private var dragStartPoint = Vector2i()
30+
1731
private val projectChangedEventHandler = InvalidationListener {
1832
val controller = sceneController ?: return@InvalidationListener
1933
framesRenderer?.setNewSceneFrames(controller.scene.frames)
@@ -23,12 +37,37 @@ class SceneCanvas : OpenGLCanvas() {
2337
framesRenderer?.setFramesSelection(controller.scene.frames)
2438
}
2539

40+
private val wheelScrolledEventHandler = EventHandler<ScrollEvent> { event ->
41+
val scrollValueSign = event.deltaY.sign.toInt()
42+
onWheelScrolled(scrollValueSign)
43+
}
44+
private val mouseMovedEventHandler = EventHandler<MouseEvent> { event ->
45+
mousePosition = extrudeEventMousePosition(event)
46+
}
47+
private val mouseDraggedEventHandler = EventHandler<MouseEvent> { event ->
48+
val mousePosition = extrudeEventMousePosition(event)
49+
if (event.button == MouseButton.MIDDLE)
50+
onMouseDragged(mousePosition)
51+
}
52+
private val wheelPressedEventHandler = EventHandler<MouseEvent> { event ->
53+
if (event.button != MouseButton.MIDDLE)
54+
return@EventHandler
55+
dragStartCameraPosition = window.camera.position
56+
dragStartPoint = fromScreenToCameraPoint(mousePosition)
57+
isDraggingScene = true
58+
}
59+
private val wheelReleasedEventHandler = EventHandler<MouseEvent> { event ->
60+
if (event.button != MouseButton.MIDDLE)
61+
return@EventHandler
62+
isDraggingScene = false
63+
}
64+
2665
init {
2766
initializeCanvasEvents()
2867
}
2968

3069
override fun onInit() {
31-
moveCamerToLeftUpperCorner()
70+
moveCameraToLeftUpperCorner()
3271

3372
val controller = ServiceLocator.getService<SceneController>() ?: return
3473
sceneController = controller
@@ -48,18 +87,52 @@ class SceneCanvas : OpenGLCanvas() {
4887
removeBindings()
4988
}
5089

51-
private fun moveCamerToLeftUpperCorner() {
90+
private fun onMouseDragged(mousePosition: Vector2i) {
91+
val mousePoint = fromScreenToCameraPoint(mousePosition)
92+
if (isDraggingScene) {
93+
val dragVector = mousePoint - dragStartPoint
94+
window.camera.position = dragStartCameraPosition - dragVector.toFloatVector() / window.camera.scaledZoom
95+
}
96+
}
97+
98+
private fun onWheelScrolled(scrollValueSign: Int) {
99+
val pointPosition = fromScreenToCameraPoint(mousePosition)
100+
val zoomMultiplier = OnWheelScrolledZoomMultiplier.pow(scrollValueSign)
101+
window.camera.zoomToPoint(pointPosition, zoomMultiplier)
102+
}
103+
104+
private fun extrudeEventMousePosition(event: MouseEvent) = Vector2i(event.x.toInt(), event.y.toInt())
105+
106+
private fun fromScreenToCameraPoint(screenPoint: Vector2i) = screenPoint - (window.size / 2)
107+
108+
private fun moveCameraToLeftUpperCorner() {
52109
window.camera.position =
53110
Vector2f(window.width.toFloat(), window.height.toFloat()) / (2f * window.camera.scaledZoom)
54111
}
55112

56113
private fun addBindings() {
57114
SceneFacade.lastVisualizationKeepSettingsProperty.addListener(projectChangedEventHandler)
58115
sceneController?.sceneProperty?.addListener(framesChangedEventHandler)
116+
117+
canvas.onMouseMoved = mouseMovedEventHandler
118+
canvas.onMouseDragged = mouseDraggedEventHandler
119+
canvas.onMousePressed = wheelPressedEventHandler
120+
canvas.onMouseReleased = wheelReleasedEventHandler
121+
canvas.onScroll = wheelScrolledEventHandler
59122
}
60123

61124
private fun removeBindings() {
62125
SceneFacade.lastVisualizationKeepSettingsProperty.removeListener(projectChangedEventHandler)
63126
sceneController?.sceneProperty?.removeListener(framesChangedEventHandler)
127+
128+
canvas.removeEventHandler(MouseEvent.MOUSE_MOVED, mouseMovedEventHandler)
129+
canvas.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDraggedEventHandler)
130+
canvas.removeEventHandler(MouseEvent.MOUSE_PRESSED, wheelPressedEventHandler)
131+
canvas.removeEventHandler(MouseEvent.MOUSE_RELEASED, wheelReleasedEventHandler)
132+
canvas.removeEventHandler(ScrollEvent.SCROLL, wheelScrolledEventHandler)
133+
}
134+
135+
companion object {
136+
private const val OnWheelScrolledZoomMultiplier = 1.1f
64137
}
65138
}

src/main/kotlin/solve/rendering/engine/camera/Camera.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ package solve.rendering.engine.camera
22

33
import org.joml.Matrix4f
44
import org.joml.Vector2f
5+
import org.joml.Vector2i
6+
import solve.rendering.engine.utils.plus
57
import solve.rendering.engine.utils.times
8+
import solve.rendering.engine.utils.toFloatVector
69

710
class Camera(var position: Vector2f = Vector2f(), zoom: Float = 1f) {
811
var zoom: Float = zoom
9-
set(value) {
12+
private set(value) {
1013
if (value <= 0f) {
1114
println("The camera scale should be positive number!")
1215
return
@@ -17,6 +20,15 @@ class Camera(var position: Vector2f = Vector2f(), zoom: Float = 1f) {
1720
val scaledZoom: Float
1821
get() = zoom * DefaultCameraScaleCoefficient
1922

23+
fun zoomToCenter(currentZoomMultiplier: Float) {
24+
zoom *= currentZoomMultiplier
25+
}
26+
27+
fun zoomToPoint(point: Vector2i, currentZoomMultiplier: Float) {
28+
zoom *= currentZoomMultiplier
29+
position += point.toFloatVector() * (currentZoomMultiplier - 1f) / scaledZoom
30+
}
31+
2032
fun calculateProjectionMatrix(projectionSize: Vector2f): Matrix4f {
2133
val orthoMatrix = calculateOrthoMatrix(projectionSize)
2234
val zoomMatrix = calculateZoomMatrix()

0 commit comments

Comments
 (0)