Skip to content

Commit 0210e28

Browse files
committed
New GestureListener an OnTouchEvent parameters.
1 parent f3155b4 commit 0210e28

File tree

6 files changed

+94
-60
lines changed

6 files changed

+94
-60
lines changed

arsceneview/src/main/java/io/github/sceneview/ar/ARScene.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.github.sceneview.ar
22

3+
import android.view.MotionEvent
4+
import android.widget.FrameLayout
35
import androidx.activity.ComponentActivity
46
import androidx.compose.foundation.background
57
import androidx.compose.foundation.layout.Box
@@ -32,6 +34,7 @@ import io.github.sceneview.ar.arcore.getUpdatedTrackables
3234
import io.github.sceneview.ar.camera.ARCameraStream
3335
import io.github.sceneview.ar.node.ARCameraNode
3436
import io.github.sceneview.collision.CollisionSystem
37+
import io.github.sceneview.collision.HitResult
3538
import io.github.sceneview.environment.Environment
3639
import io.github.sceneview.gesture.GestureDetector
3740
import io.github.sceneview.loaders.EnvironmentLoader
@@ -233,6 +236,7 @@ fun ARScene(
233236
* The listener invoked for all the gesture detector callbacks.
234237
*/
235238
onGestureListener: GestureDetector.OnGestureListener? = rememberOnGestureListener(),
239+
onTouchEvent: ((e: MotionEvent, hitResult: HitResult?) -> Boolean)? = null,
236240
activity: ComponentActivity? = LocalContext.current as? ComponentActivity,
237241
lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
238242
onViewUpdated: (ARSceneView.() -> Unit)? = null,
@@ -263,8 +267,6 @@ fun ARScene(
263267
environment,
264268
isOpaque,
265269
collisionSystem,
266-
gestureDetector,
267-
onGestureListener,
268270
cameraStream,
269271
sessionFeatures,
270272
sessionCameraConfig,
@@ -275,6 +277,8 @@ fun ARScene(
275277
onSessionPaused,
276278
onSessionFailed,
277279
onTrackingFailureChanged,
280+
onGestureListener,
281+
onTouchEvent,
278282
onSessionUpdated
279283
).also {
280284
onViewCreated?.invoke(it)
@@ -288,6 +292,7 @@ fun ARScene(
288292
sceneView.environment = environment
289293
sceneView.viewNodeWindowManager = viewNodeWindowManager
290294
sceneView.onGestureListener = onGestureListener
295+
sceneView.onTouchEvent = onTouchEvent
291296

292297
sceneView.planeRenderer.isEnabled = planeRenderer
293298

arsceneview/src/main/java/io/github/sceneview/ar/ARSceneView.kt

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -151,18 +151,6 @@ open class ARSceneView @JvmOverloads constructor(
151151
* Physics system to handle collision between nodes, hit testing on a nodes,...
152152
*/
153153
sharedCollisionSystem: CollisionSystem? = null,
154-
/**
155-
* Detects various gestures and events.
156-
*
157-
* The gesture listener callback will notify users when a particular motion event has occurred.
158-
*
159-
* Responds to Android touch events with listeners.
160-
*/
161-
sharedGestureDetector: GestureDetector? = null,
162-
/**
163-
* The listener invoked for all the gesture detector callbacks.
164-
*/
165-
sharedOnGestureListener: GestureDetector.OnGestureListener? = null,
166154
/**
167155
* The [ARCameraStream] to render the camera texture.
168156
*
@@ -231,6 +219,13 @@ open class ARSceneView @JvmOverloads constructor(
231219
* [TrackingState.TRACKING]
232220
*/
233221
var onTrackingFailureChanged: ((trackingFailureReason: TrackingFailureReason?) -> Unit)? = null,
222+
/**
223+
* The listener invoked for all the gesture detector callbacks.
224+
*
225+
* Responds to Android touch events with listeners.
226+
*/
227+
onGestureListener: GestureDetector.OnGestureListener? = null,
228+
onTouchEvent: ((e: MotionEvent, hitResult: io.github.sceneview.collision.HitResult?) -> Boolean)? = null,
234229
/**
235230
* Updates of the state of the ARCore system.
236231
*
@@ -628,6 +623,7 @@ open class ARSceneView @JvmOverloads constructor(
628623

629624
fun createARCameraStream(materialLoader: MaterialLoader) = ARCameraStream(materialLoader)
630625

631-
fun createAREnvironment(engine: Engine) = createEnvironment(engine, isOpaque = true, skybox = null)
626+
fun createAREnvironment(engine: Engine) =
627+
createEnvironment(engine, isOpaque = true, skybox = null)
632628
}
633629
}

sceneview/src/main/java/io/github/sceneview/Scene.kt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package io.github.sceneview
22

33
import android.content.Context
44
import android.opengl.EGLContext
5+
import android.os.Build
56
import android.view.MotionEvent
7+
import android.widget.FrameLayout
68
import androidx.activity.ComponentActivity
9+
import androidx.annotation.RequiresApi
710
import androidx.compose.foundation.background
811
import androidx.compose.foundation.layout.Box
912
import androidx.compose.runtime.Composable
@@ -20,20 +23,19 @@ import androidx.lifecycle.Lifecycle
2023
import com.google.android.filament.Engine
2124
import com.google.android.filament.IndirectLight
2225
import com.google.android.filament.MaterialInstance
26+
import com.google.android.filament.RenderableManager
2327
import com.google.android.filament.Renderer
2428
import com.google.android.filament.Scene
2529
import com.google.android.filament.View
2630
import com.google.android.filament.utils.Manipulator
2731
import dev.romainguy.kotlin.math.Float2
2832
import io.github.sceneview.collision.CollisionSystem
33+
import io.github.sceneview.collision.HitResult
2934
import io.github.sceneview.environment.Environment
3035
import io.github.sceneview.gesture.GestureDetector
31-
import io.github.sceneview.gesture.HitTestGestureDetector
3236
import io.github.sceneview.gesture.MoveGestureDetector
33-
import io.github.sceneview.gesture.PickGestureDetector
3437
import io.github.sceneview.gesture.RotateGestureDetector
3538
import io.github.sceneview.gesture.ScaleGestureDetector
36-
import io.github.sceneview.gesture.SelectedNodeGestureDetector
3739
import io.github.sceneview.loaders.EnvironmentLoader
3840
import io.github.sceneview.loaders.MaterialLoader
3941
import io.github.sceneview.loaders.ModelLoader
@@ -179,14 +181,8 @@ fun Scene(
179181
* The gesture listener callback will notify users when a particular motion event has occurred.
180182
* Responds to Android touch events with listeners.
181183
*/
182-
gestureDetector: GestureDetector = rememberHitTestGestureDetector(
183-
LocalContext.current,
184-
collisionSystem
185-
),
186-
/**
187-
* The listener invoked for all the gesture detector callbacks.
188-
*/
189184
onGestureListener: GestureDetector.OnGestureListener? = rememberOnGestureListener(),
185+
onTouchEvent: ((e: MotionEvent, hitResult: HitResult?) -> Boolean)? = null,
190186
activity: ComponentActivity? = LocalContext.current as? ComponentActivity,
191187
lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
192188
/**
@@ -229,6 +225,7 @@ fun Scene(
229225
cameraManipulator,
230226
viewNodeWindowManager,
231227
onGestureListener,
228+
onTouchEvent,
232229
activity,
233230
lifecycle,
234231
).also {
@@ -244,6 +241,7 @@ fun Scene(
244241
sceneView.cameraManipulator = cameraManipulator
245242
sceneView.viewNodeWindowManager = viewNodeWindowManager
246243
sceneView.onGestureListener = onGestureListener
244+
sceneView.onTouchEvent = onTouchEvent
247245
sceneView.onFrame = onFrame
248246

249247
onViewUpdated?.invoke(sceneView)

sceneview/src/main/java/io/github/sceneview/SceneView.kt

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,11 @@ open class SceneView @JvmOverloads constructor(
203203
var viewNodeWindowManager: ViewNode.WindowManager? = null,
204204
/**
205205
* The listener invoked for all the gesture detector callbacks.
206+
*
207+
* Responds to Android touch events with listeners.
206208
*/
207-
sharedOnGestureListener: GestureDetector.OnGestureListener? = null,
209+
onGestureListener: GestureDetector.OnGestureListener? = null,
210+
var onTouchEvent: ((e: MotionEvent, hitResult: HitResult?) -> Boolean)? = null,
208211
sharedActivity: ComponentActivity? = null,
209212
sharedLifecycle: Lifecycle? = null,
210213
) : SurfaceView(context, attrs, defStyleAttr, defStyleRes) {
@@ -414,16 +417,41 @@ open class SceneView @JvmOverloads constructor(
414417
* The gesture listener callback will notify users when a particular motion event has occurred.
415418
* Responds to Android touch events with listeners.
416419
*/
417-
var gestureDetector =
418-
(sharedGestureDetector ?: HitTestGestureDetector(context, collisionSystem)).apply {
419-
listener = sharedOnGestureListener
420-
}
420+
var gestureDetector: GestureDetector? =
421+
GestureDetector(context = context, listener = onGestureListener)
422+
private set
421423

422424
/**
423425
* The listener invoked for all the gesture detector callbacks.
426+
*
427+
* Responds to Android touch events with listeners.
428+
*/
429+
var onGestureListener: GestureDetector.OnGestureListener?
430+
get() = gestureDetector?.listener
431+
set(value) {
432+
gestureDetector?.listener = value
433+
}
434+
435+
var cameraGestureDetector: CameraGestureDetector? =
436+
CameraGestureDetector(viewHeight = ::getHeight, manipulator = cameraManipulator)
437+
private set
438+
439+
/**
440+
* Helper that enables camera interaction similar to sketchfab or Google Maps.
441+
*
442+
* Needs to be a callable function because it can be reinitialized in case of viewport change
443+
* or camera node manual position changed.
444+
*
445+
* The first onTouch event will make the first manipulator build. So you can change the camera
446+
* position before any user gesture.
447+
*
448+
* Clients notify the camera manipulator of various mouse or touch events, then periodically
449+
* call its getLookAt() method so that they can adjust their camera(s). Three modes are
450+
* supported: ORBIT, MAP, and FREE_FLIGHT. To construct a manipulator instance, the desired mode
451+
* is passed into the create method.
424452
*/
425-
var onGestureListener
426-
get() = gestureDetector.listener
453+
var cameraManipulator: Manipulator?
454+
get() = cameraGestureDetector?.manipulator
427455
set(value) {
428456
gestureDetector.listener = value
429457
}
@@ -665,24 +693,31 @@ open class SceneView @JvmOverloads constructor(
665693
super.onDetachedFromWindow()
666694
}
667695

668-
protected open fun onResized(width: Int, height: Int) {
669-
view.viewport = Viewport(0, 0, width, height)
670-
cameraNode.updateProjection()
671-
updateCameraManipulator()
672-
}
673-
674696
@SuppressLint("ClickableViewAccessibility")
675-
override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
697+
override fun onTouchEvent(event: MotionEvent): Boolean {
676698
// This makes sure that the view's onTouchListener is called.
677-
if (!super.onTouchEvent(motionEvent)) {
678-
lastTouchEvent = motionEvent
679-
gestureDetector.onTouchEvent(motionEvent)
680-
cameraGestureDetector?.onTouchEvent(motionEvent)
699+
if (!super.onTouchEvent(event)) {
700+
lastTouchEvent = event
701+
val hitResult = collisionSystem.hitTest(event).firstOrNull {
702+
it.node.isTouchable
703+
}
704+
if (onTouchEvent?.invoke(event, hitResult) != true &&
705+
hitResult?.node?.onTouchEvent(event, hitResult) != true
706+
) {
707+
gestureDetector?.onTouchEvent(event, hitResult)
708+
cameraGestureDetector?.onTouchEvent(event)
709+
}
710+
681711
return true
682712
}
683713
return false
684714
}
685715

716+
protected open fun onResized(width: Int, height: Int) {
717+
view.viewport = Viewport(0, 0, width, height)
718+
cameraNode.updateProjection()
719+
}
720+
686721
internal fun addNode(node: Node) {
687722
node.collisionSystem = collisionSystem
688723
addEntities(node.sceneEntities)

sceneview/src/main/java/io/github/sceneview/gesture/GestureDetector.kt

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ package io.github.sceneview.gesture
22

33
import android.content.Context
44
import android.view.MotionEvent
5-
import com.google.android.filament.View
65
import dev.romainguy.kotlin.math.Float2
7-
import io.github.sceneview.collision.CollisionSystem
6+
import io.github.sceneview.collision.HitResult
87
import io.github.sceneview.node.Node
9-
import io.github.sceneview.utils.pickNode
108

119
/**
1210
* Detects various gestures and events using the supplied {@link MotionEvent}s.
@@ -17,10 +15,7 @@ import io.github.sceneview.utils.pickNode
1715
*
1816
* Responds to Android touch events with listeners.
1917
*/
20-
open class GestureDetector(
21-
context: Context,
22-
var nodeSelector: (e: MotionEvent, (node: Node?) -> Unit) -> Unit
23-
) {
18+
open class GestureDetector(context: Context, var listener: OnGestureListener?) {
2419
interface OnGestureListener {
2520
fun onDown(e: MotionEvent, node: Node?)
2621
fun onShowPress(e: MotionEvent, node: Node?)
@@ -65,7 +60,6 @@ open class GestureDetector(
6560
override fun onScaleEnd(detector: ScaleGestureDetector, e: MotionEvent, node: Node?) {}
6661
}
6762

68-
var listener: OnGestureListener? = null
6963
var touchedNode: Node? = null
7064

7165
private var lastTouchEvent: MotionEvent? = null
@@ -221,16 +215,14 @@ open class GestureDetector(
221215
}
222216
)
223217

224-
fun onTouchEvent(event: MotionEvent): Boolean {
218+
fun onTouchEvent(event: MotionEvent, hitResult: HitResult?) {
225219
lastTouchEvent = event
226-
nodeSelector(event) { node ->
227-
touchedNode = node
228-
gestureDetector.onTouchEvent(event)
229-
moveGestureDetector.onTouchEvent(event)
230-
rotateGestureDetector.onTouchEvent(event)
231-
scaleGestureDetector.onTouchEvent(event)
232-
}
233-
return true
220+
touchedNode = hitResult?.node
221+
222+
gestureDetector.onTouchEvent(event)
223+
moveGestureDetector.onTouchEvent(event)
224+
rotateGestureDetector.onTouchEvent(event)
225+
scaleGestureDetector.onTouchEvent(event)
234226
}
235227
}
236228

sceneview/src/main/java/io/github/sceneview/node/Node.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.github.sceneview.animation.NodeAnimator
2626
import io.github.sceneview.collision.Collider
2727
import io.github.sceneview.collision.CollisionShape
2828
import io.github.sceneview.collision.CollisionSystem
29+
import io.github.sceneview.collision.HitResult
2930
import io.github.sceneview.collision.Matrix
3031
import io.github.sceneview.collision.TransformProvider
3132
import io.github.sceneview.gesture.MoveGestureDetector
@@ -47,6 +48,8 @@ import io.github.sceneview.math.slerp
4748
import io.github.sceneview.math.times
4849
import io.github.sceneview.math.toMatrix
4950
import io.github.sceneview.math.toQuaternion
51+
import io.github.sceneview.safeDestroyEntity
52+
import io.github.sceneview.safeDestroyTransformable
5053
import io.github.sceneview.utils.intervalSeconds
5154
import kotlin.reflect.KProperty1
5255

@@ -386,6 +389,7 @@ open class Node(
386389
var onAddedToScene: ((scene: Scene) -> Unit)? = null
387390
var onRemovedFromScene: ((scene: Scene) -> Unit)? = null
388391

392+
var onTouch: ((e: MotionEvent, hitResult: HitResult) -> Boolean)? = null
389393
var onDown: ((e: MotionEvent) -> Boolean)? = null
390394
var onShowPress: ((e: MotionEvent) -> Unit)? = null
391395
var onSingleTapUp: ((e: MotionEvent) -> Boolean)? = null
@@ -830,6 +834,10 @@ open class Node(
830834
childNodes.forEach { it.onWorldTransformChanged() }
831835
}
832836

837+
838+
open fun onTouchEvent(e: MotionEvent, hitResult: HitResult) =
839+
onTouch?.invoke(e, hitResult) ?: false
840+
833841
override fun onDown(e: MotionEvent) = onDown?.invoke(e) ?: false
834842
override fun onShowPress(e: MotionEvent) {
835843
onShowPress?.invoke(e)

0 commit comments

Comments
 (0)