You can now force panning/rotating mode by holding ctrl while clicking and dragging the mouse.

This commit is contained in:
Daan Vanden Bosch 2021-04-13 21:35:07 +02:00
parent 585ce44667
commit d6751b0151
5 changed files with 68 additions and 6 deletions

View File

@ -1,8 +1,11 @@
package world.phantasmal.web.core.rendering
import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.pointerevents.PointerEvent
import world.phantasmal.core.disposable.Disposable
import world.phantasmal.core.disposable.TrackedDisposable
import world.phantasmal.web.externals.three.*
import world.phantasmal.webui.dom.disposableListener
import world.phantasmal.webui.obj
import kotlin.math.ceil
import kotlin.math.floor
@ -15,7 +18,10 @@ class OrbitalCameraInputManager(
screenSpacePanning: Boolean,
enableRotate: Boolean = true,
) : TrackedDisposable(), InputManager {
private val controls = OrbitControls(camera, canvas)
private lateinit var controls: OrbitControls
@Suppress("JoinDeclarationAndAssignment")
private val pointerDownListener: Disposable
var enabled: Boolean
get() = controls.enabled
@ -24,12 +30,38 @@ class OrbitalCameraInputManager(
}
init {
// Switch mouse button actions when certain modifier keys are pressed to counteract
// OrbitControls switching left and right click behavior in that case.
pointerDownListener = canvas.disposableListener<PointerEvent>("pointerdown", {
if (it.ctrlKey || it.metaKey || it.shiftKey) {
controls.mouseButtons = obj {
LEFT = MOUSE.ROTATE
MIDDLE = MOUSE.DOLLY
RIGHT = MOUSE.PAN
}
} else {
controls.mouseButtons = obj {
LEFT = MOUSE.PAN
MIDDLE = MOUSE.DOLLY
RIGHT = MOUSE.ROTATE
}
}
})
// Ensure OrbitControls is instantiated after the pointerdown event listener is attached.
controls = OrbitControls(camera, canvas)
controls.mouseButtons = obj {
LEFT = MOUSE.PAN
MIDDLE = MOUSE.DOLLY
RIGHT = MOUSE.ROTATE
}
controls.touches = obj {
ONE = TOUCH.PAN
TWO = TOUCH.DOLLY_ROTATE
}
camera.position.copy(position)
controls.screenSpacePanning = screenSpacePanning
controls.enableRotate = enableRotate
@ -40,6 +72,7 @@ class OrbitalCameraInputManager(
override fun dispose() {
controls.dispose()
pointerDownListener.dispose()
super.dispose()
}

View File

@ -12,6 +12,11 @@ external interface OrbitControlsMouseButtons {
var RIGHT: MOUSE
}
external interface OrbitControlsMouseTouches {
var ONE: TOUCH
var TWO: TOUCH
}
external class OrbitControls(`object`: Camera, domElement: HTMLElement = definedExternally) {
var enabled: Boolean
var enablePan: Boolean
@ -23,6 +28,8 @@ external class OrbitControls(`object`: Camera, domElement: HTMLElement = defined
var mouseButtons: OrbitControlsMouseButtons
var touches: OrbitControlsMouseTouches
fun update(): Boolean
fun saveState()

View File

@ -744,6 +744,13 @@ external enum class MOUSE {
PAN,
}
external enum class TOUCH {
ROTATE,
PAN,
DOLLY_PAN,
DOLLY_ROTATE,
}
external class Raycaster(
origin: Vector3 = definedExternally,
direction: Vector3 = definedExternally,

View File

@ -73,7 +73,7 @@ class QuestInputManager(
renderContext.canvas.observeEntityDrop(::onEntityDrop),
)
// Ensure OrbitalCameraControls attaches its listeners after ours.
// Ensure OrbitalCameraControls attaches its listeners after we've attached ours.
cameraInputManager = OrbitalCameraInputManager(
renderContext.canvas,
renderContext.camera,

View File

@ -19,9 +19,18 @@ class IdleState(
private var shouldCheckHighlight = false
override fun processEvent(event: Evt): State {
// Don't highlight or manipulate entities in forced panning/rotating mode.
val forcedPanningRotatingMode = when (event) {
is KeyboardEvt -> event.key == "Control"
is PointerEvt -> event.ctrlKey
else -> false
}
when (event) {
is KeyboardEvt -> {
if (entityManipulationEnabled) {
if (forcedPanningRotatingMode) {
ctx.setHighlightedEntity(null)
} else if (entityManipulationEnabled) {
val quest = ctx.quest.value
val entity = ctx.selectedEntity.value
@ -32,7 +41,9 @@ class IdleState(
}
is PointerDownEvt -> {
val pick = pickEntity(event.pointerDevicePosition)
val pick =
if (forcedPanningRotatingMode) null
else pickEntity(event.pointerDevicePosition)
when (event.buttons) {
1 -> {
@ -93,8 +104,12 @@ class IdleState(
is PointerMoveEvt -> {
if (!panning && !rotating && !zooming) {
// User is hovering.
pointerDevicePosition.copy(event.pointerDevicePosition)
shouldCheckHighlight = true
if (forcedPanningRotatingMode) {
ctx.setHighlightedEntity(null)
} else {
pointerDevicePosition.copy(event.pointerDevicePosition)
shouldCheckHighlight = true
}
}
}