Skip to content

Instantly share code, notes, and snippets.

@ThomasGorisse
Last active September 27, 2022 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasGorisse/cec13d83cb88686e983b72b5e3a8fa2d to your computer and use it in GitHub Desktop.
Save ThomasGorisse/cec13d83cb88686e983b72b5e3a8fa2d to your computer and use it in GitHub Desktop.
package io.github.sceneview.node
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import com.google.android.filament.*
import com.google.android.filament.View.PickingQueryResult
import io.github.sceneview.SceneView
import io.github.sceneview.components.RenderableComponent
import io.github.sceneview.geometries.Plane
import io.github.sceneview.geometries.destroyGeometry
import io.github.sceneview.loaders.MaterialLoader
import io.github.sceneview.managers.NodeManager
import io.github.sceneview.managers.WindowViewManager
import io.github.sceneview.managers.geometry
import io.github.sceneview.math.Direction
import io.github.sceneview.texture.ViewTexture
import io.github.sceneview.view.ViewStream
import io.github.sceneview.view.destroyViewStream
/**
* ### A Node that can display an Android [View]
*
* This node contains a View for the rendering engine to render.
*
* @param view The 2D Android [View] that is rendered by this [ViewNode]
* @param unlit True to disable all lights influences on the rendered view
* @param invertFrontFaceWinding Inverts the winding order of front faces.
* Inverting the winding order of front faces is useful when rendering mirrored reflections
* (water, mirror surfaces, front camera in AR, etc.).
* True to invert front faces, false otherwise
*/
class ViewNode constructor(
engine: Engine,
nodeManager: NodeManager,
viewWindowViewManager: WindowViewManager,
materialLoader: MaterialLoader,
view: View,
unlit: Boolean = false,
invertFrontFaceWinding: Boolean = false
) : Node(engine, nodeManager, EntityManager.get().create(), isSelectable = true),
RenderableComponent {
val viewStream: ViewStream
val geometry: Plane
val texture: Texture
var material: MaterialInstance
val view get() = viewStream.view
init {
viewStream = ViewStream.Builder()
.view(view)
.build(engine, viewWindowViewManager)
geometry = Plane.Builder(size = viewStream.worldSize, normal = Direction(z = 1.0f))
.build(engine)
viewStream.onSizeChanged = { size ->
geometry.update(engine, size = size)
}
texture = ViewTexture.Builder()
.viewStream(viewStream)
.build(engine)
material = materialLoader.createViewMaterial(texture, unlit, invertFrontFaceWinding)
RenderableManager.Builder(geometry.submeshes.size)
.geometry(geometry)
.material(0, material)
.build(engine, entity)
}
constructor(
sceneView: SceneView,
view: View,
unlit: Boolean = false,
invertFrontFaceWinding: Boolean = false
) : this(
sceneView.engine,
sceneView.nodeManager,
sceneView.windowViewManager,
sceneView.materialLoader,
view,
unlit,
invertFrontFaceWinding
)
constructor(
sceneView: SceneView,
viewResourceId: Int,
unlit: Boolean = false,
invertFrontFaceWinding: Boolean = false
) : this(
sceneView,
LayoutInflater.from(sceneView.context).inflate(viewResourceId, null, false),
unlit,
invertFrontFaceWinding
)
override fun destroy() {
engine.destroyViewStream(viewStream)
engine.destroyGeometry(geometry)
engine.destroyTexture(texture)
engine.destroyMaterialInstance(material)
engine.renderableManager.destroy(entity)
super.destroy()
}
override fun getBoundingBox() = axisAlignedBoundingBox
fun onTouchEvent(motionEvent: MotionEvent, pickingResult: PickingQueryResult): Boolean {
//TODO: Use PickingQueryResult.getWorldSpacePosition()
// val scene: SceneView = node.getSceneViewInternal() ?: return false
// val pointerCount = motionEvent.pointerCount
// val pointerProperties = arrayOfNulls<MotionEvent.PointerProperties>(pointerCount)
// val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(pointerCount)
// val nodeTransformMatrix: Matrix = node.getTransformationMatrix()
// val nodePosition = Vector3()
// nodeTransformMatrix.decomposeTranslation(nodePosition)
// val nodeScale = Vector3()
// nodeTransformMatrix.decomposeScale(nodeScale)
// val nodeRotation = Quaternion()
// nodeTransformMatrix.decomposeRotation(nodeScale, nodeRotation)
// val nodeForward = Quaternion.rotateVector(nodeRotation, Vector3.forward())
// val nodeBack = Quaternion.rotateVector(nodeRotation, Vector3.back())
//
// /*
// * Cast a ray against a plane that extends to infinity located where the view is in 3D space
// * instead of casting against the node's collision shape. This is important for the UX of touch
// * events after the initial ACTION_DOWN event. i.e. If a user is dragging a slider and their
// * finger moves beyond the view the position of their finger relative to the slider should still
// * be respected.
// */
// val plane = Plane(nodePosition, nodeForward)
// val rayHit = RayHit()
//
// // Also cast a ray against a back-facing plane because we render the view as double-sided.
// val backPlane = Plane(nodePosition, nodeBack)
//
// // Convert the pointer coordinates for each pointer into the view's local coordinate space.
// for (i in 0 until pointerCount) {
// val props = MotionEvent.PointerProperties()
// val coords = MotionEvent.PointerCoords()
// motionEvent.getPointerProperties(i, props)
// motionEvent.getPointerCoords(i, coords)
// val camera: CameraNode? = scene.cameraNode
// val ray = camera!!.screenPointToRay(coords.x, coords.y)
// if (plane.rayIntersection(ray, rayHit)) {
// val viewPosition = convertWorldPositionToLocalView(node, rayHit.point)
// coords.x = viewPosition.x
// coords.y = viewPosition.y
// } else if (backPlane.rayIntersection(ray, rayHit)) {
// val viewPosition = convertWorldPositionToLocalView(node, rayHit.point)
//
// // Flip the x coordinate for the back-facing plane.
// coords.x = getView().width - viewPosition.x
// coords.y = viewPosition.y
// } else {
// coords.clear()
// props.clear()
// }
// pointerProperties[i] = props
// pointerCoords[i] = coords
// }
//
// // We must copy the touch event with the new coordinates and dispatch it to the view.
// val me = MotionEvent.obtain(
// motionEvent.downTime,
// motionEvent.eventTime,
// motionEvent.action,
// pointerCount,
// pointerProperties,
// pointerCoords,
// motionEvent.metaState,
// motionEvent.buttonState,
// motionEvent.xPrecision,
// motionEvent.yPrecision,
// motionEvent.deviceId,
// motionEvent.edgeFlags,
// motionEvent.source,
// motionEvent.flags
// )
// return getView().dispatchTouchEvent(me)
return true
}
// fun convertWorldPositionToLocalView(node: Node, worldPos: Vector3?): Vector3 {
// Preconditions.checkNotNull(node, "Parameter \"node\" was null.")
// Preconditions.checkNotNull(worldPos, "Parameter \"worldPos\" was null.")
//
// // Find where the view renderable is being touched in local space.
// // this will be in meters relative to the bottom-middle of the view.
// val localPos: Vector3 = node.getTransformationMatrixInverted().transformPoint(worldPos)
//
// // Calculate the pixels to meters ratio.
// val view = getView()
// val width = view.width
// val height = view.height
// val pixelsToMetersRatio = getPixelsToMetersRatio()
//
// // We must convert the position to pixels
// var xPixels = (localPos.x * pixelsToMetersRatio).toInt()
// var yPixels = (localPos.y * pixelsToMetersRatio).toInt()
//
// // We must convert the coordinates from the renderable's alignment origin to top-left origin.
// val halfWidth = width / 2
// val halfHeight = height / 2
// val verticalAlignment = getVerticalAlignment()
// yPixels = when (verticalAlignment) {
// VerticalAlignment.BOTTOM -> height - yPixels
// VerticalAlignment.CENTER -> height - (yPixels + halfHeight)
// VerticalAlignment.TOP -> height - (yPixels + height)
// }
// val horizontalAlignment = getHorizontalAlignment()
// when (horizontalAlignment) {
// HorizontalAlignment.LEFT -> {}
// HorizontalAlignment.CENTER -> xPixels = xPixels + halfWidth
// HorizontalAlignment.RIGHT -> xPixels = xPixels + width
// }
// return Vector3(xPixels.toFloat(), yPixels.toFloat(), 0.0f)
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment