/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
/**
- * Recursively hit test all the actors, without crossing into other layers.
- * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
- * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
- * of touch vector). The closest Hit-Tested Actor is that which is returned.
- * Exceptions to this rule are:
- * - When comparing against renderable parents, if Actor is the same distance
- * or closer than it's renderable parent, then it takes priority.
+ * Hit tests the given actor and updates the in/out variables appropriately
*/
-HitActor HitTestWithinLayer(Actor& actor,
- const RenderTask& renderTask,
- const RenderTaskList::ExclusivesContainer& exclusives,
- const Vector4& rayOrigin,
- const Vector4& rayDir,
- const float& nearClippingPlane,
- const float& farClippingPlane,
- HitTestInterface& hitCheck,
- const bool& overlayed,
- bool& overlayHit,
- bool layerIs3d,
- const RayTest& rayTest,
- const Integration::Point& point,
- const uint32_t eventTime)
+void HitTestActor(const RenderTask& renderTask,
+ const Vector4& rayOrigin,
+ const Vector4& rayDir,
+ const float& nearClippingPlane,
+ const float& farClippingPlane,
+ HitTestInterface& hitCheck,
+ const RayTest& rayTest,
+ const Integration::Point& point,
+ const uint32_t eventTime,
+ bool clippingActor,
+ bool overlayedActor,
+ Actor& actor,
+ bool& overlayHit,
+ HitActor& hit)
{
- HitActor hit;
-
- if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives))
- {
- return hit;
- }
-
- // For clipping, regardless of whether we have hit this actor or not.
- // This is used later to ensure all nested clipped children have hit
- // all clipping actors also for them to be counted as hit.
- bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED;
- bool overlayedActor = overlayed || actor.IsOverlay();
-
- // If we are a clipping actor or hittable...
if(clippingActor || hitCheck.IsActorHittable(&actor))
{
Vector3 size(actor.GetCurrentSize());
}
}
}
+}
+
+/**
+ * When iterating through the children of an actor, this method updates the child-hit-data.
+ */
+void UpdateChildHitData(const HitActor& hit, const HitActor& currentHit, const bool layerIs3d, const bool parentIsRenderable, HitActor& childHit)
+{
+ bool updateChildHit = false;
+ if(currentHit.distance >= 0.0f)
+ {
+ if(layerIs3d)
+ {
+ updateChildHit = ((currentHit.depth > childHit.depth) ||
+ ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance)));
+ }
+ else
+ {
+ updateChildHit = currentHit.depth >= childHit.depth;
+ }
+ }
+
+ if(updateChildHit)
+ {
+ if(!parentIsRenderable || currentHit.depth > hit.depth ||
+ (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance)))
+ {
+ childHit = currentHit;
+ }
+ }
+}
+
+/**
+ * Recursively hit test all the actors, without crossing into other layers.
+ * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
+ * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
+ * of touch vector). The closest Hit-Tested Actor is that which is returned.
+ * Exceptions to this rule are:
+ * - When comparing against renderable parents, if Actor is the same distance
+ * or closer than it's renderable parent, then it takes priority.
+ */
+HitActor HitTestWithinLayer(Actor& actor,
+ const RenderTask& renderTask,
+ const RenderTaskList::ExclusivesContainer& exclusives,
+ const Vector4& rayOrigin,
+ const Vector4& rayDir,
+ const float& nearClippingPlane,
+ const float& farClippingPlane,
+ HitTestInterface& hitCheck,
+ const bool& overlayed,
+ bool& overlayHit,
+ bool layerIs3d,
+ const RayTest& rayTest,
+ const Integration::Point& point,
+ const uint32_t eventTime)
+{
+ HitActor hit;
+
+ if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives))
+ {
+ return hit;
+ }
+
+ // For clipping, regardless of whether we have hit this actor or not.
+ // This is used later to ensure all nested clipped children have hit
+ // all clipping actors also for them to be counted as hit.
+ bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED;
+ bool overlayedActor = overlayed || actor.IsOverlay();
+
+ // If we are a clipping actor or hittable...
+ HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit);
// If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
if(clippingActor && !(hit.actor))
continue;
}
- bool updateChildHit = false;
- if(currentHit.distance >= 0.0f)
- {
- if(layerIs3d)
- {
- updateChildHit = ((currentHit.depth > childHit.depth) ||
- ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance)));
- }
- else
- {
- updateChildHit = currentHit.depth >= childHit.depth;
- }
- }
-
- if(updateChildHit)
- {
- if(!parentIsRenderable || currentHit.depth > hit.depth ||
- (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance)))
- {
- childHit = currentHit;
- }
- }
+ UpdateChildHitData(hit, currentHit, layerIs3d, parentIsRenderable, childHit);
}
}
}
Actor* sourceActor(renderTask.GetSourceActor());
if(sourceActor)
{
- Dali::Layer layer(sourceActor->GetLayer());
- if(layer)
+ Dali::Layer sourceLayer(sourceActor->GetLayer());
+ if(sourceLayer)
{
- const uint32_t sourceActorDepth(layer.GetProperty<bool>(Dali::Layer::Property::DEPTH));
+ const uint32_t sourceActorDepth(sourceLayer.GetProperty<bool>(Dali::Layer::Property::DEPTH));
CameraActor* cameraActor = renderTask.GetCameraActor();
bool pickingPossible = cameraActor->BuildPickingRay(
// If this layer is set to consume the hit, then do not check any layers behind it
if(hitCheck.DoesLayerConsumeHit(layer))
{
- layerConsumesHit = true;
+ // Consume the hit if this layer is same as SourceActor's layer
+ layerConsumesHit = (sourceLayer == Dali::Layer(layer));
break;
}
}
* @param[in] taskList The list of render tasks
* @param[out] results Ray information calculated by the camera
* @param[in] hitCheck The hit testing interface object to use
- * @param[in] onScreen True to test on-screen, false to test off-screen
* @return True if we have a hit, false otherwise
*/
bool HitTestRenderTaskList(const Vector2& sceneSize,
RenderTaskList& taskList,
const Vector2& screenCoordinates,
Results& results,
- HitTestInterface& hitCheck,
- bool onScreen)
+ HitTestInterface& hitCheck)
{
RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
const auto& exclusives = taskList.GetExclusivesList();
RayTest rayTest;
+ // Hit test order should be reverse of draw order
for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
{
- RenderTask& renderTask = *iter->Get();
- const bool isOffscreenRenderTask = renderTask.GetFrameBuffer();
- if((onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask))
- {
- // Skip to next task
- continue;
- }
+ RenderTask& renderTask = *iter->Get();
if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
{
// Return true when an actor is hit (or layer in our render-task consumes the hit)
- return true; // don't bother checking off screen tasks
+ return true;
}
}
* @param[in] taskList The list of render tasks
* @param[out] results Ray information calculated by the camera
* @param[in] hitCheck The hit testing interface object to use
- * @param[in] onScreen True to test on-screen, false to test off-screen
* @return True if we have a hit, false otherwise
*/
bool HitTestForEachRenderTask(const Vector2& sceneSize,
{
bool result = false;
- // Check on-screen tasks before off-screen ones.
- // Hit test order should be reverse of draw order (see ProcessRenderTasks() where off-screen tasks are drawn first).
- if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true) ||
- HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false))
+ if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck))
{
// Found hit.
result = true;