// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
+#include <dali/internal/event/actors/actor-coords.h>
#include <dali/internal/event/actors/actor-impl.h>
#include <dali/internal/event/actors/camera-actor-impl.h>
#include <dali/internal/event/actors/layer-impl.h>
#include <dali/internal/event/actors/layer-list.h>
#include <dali/internal/event/common/projection.h>
+#include <dali/internal/event/common/scene-impl.h>
#include <dali/internal/event/events/ray-test.h>
#include <dali/internal/event/render-tasks/render-task-impl.h>
#include <dali/internal/event/render-tasks/render-task-list-impl.h>
{
namespace
{
-struct HitActor
+enum HitType
{
- HitActor()
- : actor(nullptr),
- distance(std::numeric_limits<float>::max()),
- depth(std::numeric_limits<int>::min())
+ HIT_ACTOR,
+ HIT_MAPPING_ACTOR
+};
+
+struct Ray
+{
+ Vector4 origin;
+ Vector4 direction;
+};
+
+struct HitResult
+{
+ HitResult(Actor* actor, Vector2 hitPosition, float distance, HitType hitType, Ray ray)
+ : mActor(actor),
+ mHitPosition(hitPosition),
+ mDistance(distance),
+ mHitType(hitType),
+ mRay(ray)
{
}
- Actor* actor; ///< The actor hit (if actor is hit, then this is initialised).
- Vector2 hitPosition; ///< Position of hit (only valid if actor valid).
- float distance; ///< Distance from ray origin to hit actor.
- int32_t depth; ///< Depth index of this actor.
+ Actor* mActor; ///< The actor hit (if actor is hit, then this is initialised).
+ Vector2 mHitPosition; ///< Position of hit (only valid if actor valid).
+ float mDistance;
+ HitType mHitType;
+ Ray mRay;
+};
+
+struct HitCommonInformation
+{
+ const RenderTaskList::ExclusivesContainer& exclusives;
+ std::unordered_map<uint32_t, RenderTaskPtr> mappingActors;
+ LayerList& layers;
};
/**
return false;
}
- bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, const Integration::Scene::TouchPropagationType propagationType) override
+ bool ActorRequiresHitResultCheck(Actor* actor, Vector2 hitPointLocal) override
{
// Geometry way does not require Hittest from the client.
- if(propagationType == Integration::Scene::TouchPropagationType::PARENT)
+ if(GetPropagationType() == Integration::Scene::TouchPropagationType::PARENT)
{
- return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+ return actor->EmitHitTestResultSignal(GetPoint(), hitPointLocal, GetTimeStamp());
}
return true;
}
return layer->IsTouchConsumed();
}
- bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, const Integration::Scene::TouchPropagationType propagationType) override
+ bool ActorRequiresHitResultCheck(Actor* actor, Vector2 hitPointLocal) override
{
// The Geometry way behaves like AllowedOnlyOwnTouch is enabled.
- if(point.GetState() != PointState::STARTED && (propagationType == Integration::Scene::TouchPropagationType::GEOMETRY || actor->IsAllowedOnlyOwnTouch()) && ownActor != actor)
+ if(GetPoint().GetState() != PointState::STARTED && (GetPropagationType() == Integration::Scene::TouchPropagationType::GEOMETRY || actor->IsAllowedOnlyOwnTouch()) && ownActor != actor)
{
return false;
}
// Geometry way does not require Hittest from the client.
- if(propagationType == Integration::Scene::TouchPropagationType::PARENT)
+ if(GetPropagationType() == Integration::Scene::TouchPropagationType::PARENT)
{
- return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+ return actor->EmitHitTestResultSignal(GetPoint(), hitPointLocal, GetTimeStamp());
}
return true;
}
};
/**
- * Check to see if the actor we're about to hit test is exclusively owned by another rendertask?
+ * Return true if actor is sourceActor or a descendent of sourceActor
*/
-bool IsActorExclusiveToAnotherRenderTask(const Actor& actor,
- const RenderTask& renderTask,
- const RenderTaskList::ExclusivesContainer& exclusives)
-
+bool IsWithinSourceActors(const Actor& sourceActor, const Actor& actor)
{
- bool exclusiveByOtherTask = false;
- if(exclusives.size())
+ if(&sourceActor == &actor)
{
- for(const auto& exclusive : exclusives)
- {
- if(exclusive.actor.GetActor() == &actor)
- {
- if(exclusive.renderTaskPtr != &renderTask)
- {
- exclusiveByOtherTask = true;
- }
- else
- {
- // Fast-out if render task is itself
- return false;
- }
- }
- }
+ return true;
+ }
+
+ Actor* parent = actor.GetParent();
+ if(parent)
+ {
+ return IsWithinSourceActors(sourceActor, *parent);
}
- return exclusiveByOtherTask;
+
+ // Not within source actors
+ return false;
}
/**
- * Checks if actor or anyone of it's parents are an overlay, until either the currentActor is reached or the root actor
- * @param actor The child-actor and it's parents to check
- * @param currentActor The top actor of this current branch which we should not go above
- * @return True if the actor or a parent is an overlay, false otherwise
+ * Returns true if the actor and all of the actor's parents are hittable.
*/
-inline bool IsOnOverlay(Actor* actor, Actor* currentActor)
+bool IsActorActuallyHittable(Actor* actor, HitTestInterface& hitCheck)
{
- while(actor && actor != currentActor)
+ Actor* currentActor = actor;
+ // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
+ while(currentActor)
{
- if(actor->IsOverlay())
+ if(!hitCheck.DescendActorHierarchy(currentActor))
{
- return true;
+ return false;
}
- actor = actor->GetParent();
+ currentActor = currentActor->GetParent();
}
- return false;
+
+ return true;
}
/**
- * Hit tests the given actor and updates the in/out variables appropriately
+ * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task.
*/
-bool 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,
- const Integration::Scene::TouchPropagationType propagationType)
+void GetCameraClippingPlane(RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane)
{
- bool isClippingOrHittable = clippingActor || hitCheck.IsActorHittable(&actor);
- bool isGeometry = propagationType == Integration::Scene::TouchPropagationType::GEOMETRY;
- if(isClippingOrHittable || isGeometry)
- {
- Vector3 size(actor.GetCurrentSize());
+ CameraActor* cameraActor = renderTask.GetCameraActor();
+ nearClippingPlane = cameraActor->GetNearClippingPlane();
+ farClippingPlane = cameraActor->GetFarClippingPlane();
+}
- // Ensure the actor has a valid size.
- // If so, perform a quick ray sphere test to see if our ray is close to the actor.
- if(size.x > 0.0f && size.y > 0.0f && rayTest.SphereTest(actor, rayOrigin, rayDir))
- {
- Vector2 hitPointLocal;
- float distance;
+RenderTask* curRenderTask;
- // Finally, perform a more accurate ray test to see if our ray actually hits the actor.
- if(rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance))
- {
- // Calculate z coordinate value in Camera Space.
- const Matrix& viewMatrix = renderTask.GetCameraActor()->GetViewMatrix();
- const Vector4& hitDir = Vector4(rayDir.x * distance, rayDir.y * distance, rayDir.z * distance, 0.0f);
- const float cameraDepthDistance = (viewMatrix * hitDir).z;
+bool HitTestRenderTask(std::vector<std::shared_ptr<HitResult>>& hitResultList,
+ RenderTask& renderTask,
+ HitCommonInformation& hitCommonInformation,
+ const Vector2& screenSize,
+ Vector2 screenCoordinates,
+ HitTestInterface& hitCheck);
- // Check if cameraDepthDistance is between clipping plane
- if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= farClippingPlane)
- {
- if(isGeometry && actor.GetParent())
- {
- // If the child touches outside the parent's size boundary, it should not be hit.
- if(!overlayedActor && !clippingActor && !actor.GetParent()->IsLayer())
- {
- Vector2 hitPointLocal;
- float distance;
- if(!(rayTest.SphereTest(*actor.GetParent(), rayOrigin, rayDir) &&
- rayTest.ActorTest(*actor.GetParent(), rayOrigin, rayDir, hitPointLocal, distance)))
- {
- return false;
- }
- }
- }
-
- if(overlayHit && !overlayedActor)
- {
- // If we have already hit an overlay and current actor is not an overlay ignore current actor.
- }
- else
- {
- if(overlayedActor)
- {
- overlayHit = true;
- }
-
- // If the hit actor does not want to hit, the hit-test continues.
- if(isClippingOrHittable && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime, propagationType))
- {
- hit.actor = &actor;
- hit.hitPosition = hitPointLocal;
- hit.distance = distance;
- hit.depth = actor.GetSortingDepth();
-
- if(actor.GetRendererCount() > 0)
- {
- // Get renderer with maximum depth
- int rendererMaxDepth(actor.GetRendererAt(0).Get()->GetDepthIndex());
- for(uint32_t i(1); i < actor.GetRendererCount(); ++i)
- {
- int depth = actor.GetRendererAt(i).Get()->GetDepthIndex();
- if(depth > rendererMaxDepth)
- {
- rendererMaxDepth = depth;
- }
- }
- hit.depth += rendererMaxDepth;
- }
- }
- }
- }
- }
- }
+bool IsActorPickable(const Ray& ray,
+ const float& projectedNearClippingDistance,
+ const float& projectedFarClippingDistance,
+ Actor& actor)
+{
+ Vector2 hitPointLocal;
+ float distance;
+ if(!RayTest::ActorTest(actor, ray.origin, ray.direction, hitPointLocal, distance))
+ {
+ return false;
+ }
+
+ if(distance < projectedNearClippingDistance || distance > projectedFarClippingDistance)
+ {
+ return false;
}
return true;
}
/**
- * When iterating through the children of an actor, this method updates the child-hit-data.
+ * Hit tests the given actor and updates the in/out variables appropriately
*/
-void UpdateChildHitData(const HitActor& hit, const HitActor& currentHit, const bool layerIs3d, const bool parentIsRenderable, HitActor& childHit)
+std::shared_ptr<HitResult> HitTestActor(const Ray& ray,
+ const float& projectedNearClippingDistance,
+ const float& projectedFarClippingDistance,
+ HitTestInterface& hitCheck,
+ Actor& actor,
+ Dali::Layer::Behavior layerBehavior)
{
- bool updateChildHit = false;
- if(currentHit.distance >= 0.0f)
+ if(!hitCheck.IsActorHittable(&actor) && !actor.IsRenderTaskMappingActor())
{
- if(layerIs3d)
+ return nullptr;
+ }
+
+ Vector3 size = actor.GetCurrentSize();
+ if(size.x <= 0.0f || size.y < 0.0f)
+ {
+ return nullptr;
+ }
+
+ Vector2 hitPointLocal;
+ float distance;
+ if(layerBehavior == Dali::Layer::Behavior::LAYER_3D)
+ {
+ Vector3 hitPointLocalVector3;
+ bool hitSucceeded = RayTest::ActorBoundingBoxTest(actor, ray.origin, ray.direction, hitPointLocalVector3, distance);
+ hitPointLocal = Vector2(hitPointLocalVector3);
+ if(!hitSucceeded)
{
- updateChildHit = ((currentHit.depth > childHit.depth) ||
- ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance)));
+ return nullptr;
}
- else
+ }
+ else
+ {
+ if(!RayTest::SphereTest(actor, ray.origin, ray.direction))
{
- updateChildHit = currentHit.depth >= childHit.depth;
+ return nullptr;
}
- }
- if(updateChildHit)
- {
- if(!parentIsRenderable || currentHit.depth > hit.depth ||
- (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance)))
+ if(!RayTest::ActorTest(actor, ray.origin, ray.direction, hitPointLocal, distance))
{
- childHit = currentHit;
+ return nullptr;
}
}
-}
-/**
- * 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,
- std::list<Dali::Internal::Actor*>& actorLists,
- const Integration::Scene::TouchPropagationType propagationType)
-{
- HitActor hit;
+ if(distance < projectedNearClippingDistance || distance > projectedFarClippingDistance)
+ {
+ return nullptr;
+ }
- if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives))
+ if(!hitCheck.ActorRequiresHitResultCheck(&actor, hitPointLocal))
{
- return hit;
+ return nullptr;
}
- // 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.
- const ClippingMode::Type clippingMode = actor.GetClippingMode();
- bool clippingActor = clippingMode != ClippingMode::DISABLED;
- bool overlayedActor = overlayed || actor.IsOverlay();
+ std::shared_ptr<HitResult> hitResult = std::make_shared<HitResult>(&actor, hitPointLocal, distance, (actor.IsRenderTaskMappingActor()) ? HitType::HIT_MAPPING_ACTOR : HitType::HIT_ACTOR, ray);
+
+ return hitResult;
+}
+
+bool IsActorExclusive(const Actor& actor,
+ const RenderTaskList::ExclusivesContainer& exclusives)
+
+{
+ auto result = std::find_if(exclusives.begin(), exclusives.end(), [&actor](const RenderTaskList::Exclusive& exclusive)
+ { return exclusive.actor.GetActor() == &actor; });
+ return (result != exclusives.end());
+}
- // If we are a clipping actor or hittable...
- if(!HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit, propagationType))
+inline bool IsActorValid(Actor& actor,
+ const RenderTaskList::ExclusivesContainer& exclusives,
+ HitTestInterface& hitCheck)
+{
+ if(IsActorExclusive(actor, exclusives))
{
- return hit;
+ return false;
}
- // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
- // Only do this if we're using CLIP_CHILDREN though, as children whose drawing mode is OVERLAY_2D are not clipped when CLIP_TO_BOUNDING_BOX is selected.
- if(clippingActor && !(hit.actor) && (clippingMode == ClippingMode::CLIP_CHILDREN))
+ if(actor.IsLayer())
{
- return hit;
+ return false;
}
- else if(propagationType == Integration::Scene::TouchPropagationType::GEOMETRY && hit.actor)
+
+ if(!hitCheck.DescendActorHierarchy(&actor))
{
- // Saves the actors that can be hit as a list
- actorLists.push_back(hit.actor);
+ return false;
}
- // Find a child hit, until we run out of actors in the current layer.
- HitActor childHit;
- if(actor.GetChildCount() > 0)
+ return true;
+}
+
+bool HitTestActorRecursively(std::vector<std::shared_ptr<HitResult>>& hitResultList,
+ ActorPtr currentActor,
+ HitCommonInformation& hitCommonInformation,
+ const Ray& ray,
+ const float& projectedNearClippingDistance,
+ const float& projectedFarClippingDistance,
+ HitTestInterface& hitCheck,
+ Dali::Layer::Behavior layerBehavior,
+ bool isKeepingHitTestRequired,
+ bool isOverlay)
+{
+ if(!isOverlay && currentActor->IsOverlay())
{
- childHit.distance = std::numeric_limits<float>::max();
- childHit.depth = std::numeric_limits<int32_t>::min();
- ActorContainer& children = actor.GetChildrenInternal();
+ return false;
+ }
- // Hit test ALL children and calculate their distance.
- bool parentIsRenderable = actor.IsRenderable();
+ std::shared_ptr<HitResult> hitResultOfThisActor;
+ bool isClippingRequired = (layerBehavior != Dali::Layer::LAYER_3D) && ((currentActor->GetClippingMode() != ClippingMode::DISABLED) || (hitCheck.GetPropagationType() == Integration::Scene::TouchPropagationType::GEOMETRY));
- for(ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter)
+ if(isClippingRequired)
+ {
+ if(!currentActor->IsLayer() && !IsActorPickable(ray, projectedNearClippingDistance, projectedFarClippingDistance, *(currentActor)))
{
- // Descend tree only if...
- if(!(*iter)->IsLayer() && // Child is NOT a layer, hit testing current layer only
- (hitCheck.DescendActorHierarchy((*iter).Get()))) // We can descend into child hierarchy
- {
- HitActor currentHit(HitTestWithinLayer((*iter->Get()),
- renderTask,
- exclusives,
- rayOrigin,
- rayDir,
- nearClippingPlane,
- farClippingPlane,
- hitCheck,
- overlayedActor,
- overlayHit,
- layerIs3d,
- rayTest,
- point,
- eventTime,
- actorLists,
- propagationType));
- // Make sure the set hit actor is actually hittable. This is usually required when we have some
- // clipping as we need to hit-test all actors as we descend the tree regardless of whether they
- // are hittable or not.
- if(currentHit.actor && (!hitCheck.IsActorHittable(currentHit.actor)))
- {
- continue;
- }
-
- UpdateChildHitData(hit, currentHit, layerIs3d, parentIsRenderable, childHit);
- }
+ return false;
}
}
- if(childHit.actor)
+ if(currentActor->GetChildCount() > 0)
{
- // If child has been hit & current actor is clipping to bounding box...
- if(clippingMode == ClippingMode::CLIP_TO_BOUNDING_BOX)
+ ActorContainer& children = currentActor->GetChildrenInternal();
+ ActorContainer::reverse_iterator endIter = children.rend();
+ for(ActorContainer::reverse_iterator iter = children.rbegin(); endIter != iter; ++iter)
{
- // ...then make sure the clipping actor has actually been hit unless the child hit actor is on a child overlay.
- if(hit.actor || IsOnOverlay(childHit.actor, &actor))
+ ActorPtr childActor = *iter;
+ if(!IsActorValid(*childActor, hitCommonInformation.exclusives, hitCheck))
{
- // Only then should we return the child hit in this scenario.
- return childHit;
+ continue;
+ }
+
+ bool isHit = HitTestActorRecursively(hitResultList, childActor, hitCommonInformation, ray, projectedNearClippingDistance, projectedFarClippingDistance, hitCheck, layerBehavior, isKeepingHitTestRequired, isOverlay);
+ if(isKeepingHitTestRequired)
+ {
+ continue;
+ }
+
+ if(isHit)
+ {
+ return true;
}
- }
- else
- {
- // no clipping concerns, return child hit.
- return childHit;
}
}
- return hit;
-}
-
-/**
- * Return true if actor is sourceActor or a descendent of sourceActor
- */
-bool IsWithinSourceActors(const Actor& sourceActor, const Actor& actor)
-{
- if(&sourceActor == &actor)
+ hitResultOfThisActor = HitTestActor(ray, projectedNearClippingDistance, projectedFarClippingDistance, hitCheck, *currentActor, layerBehavior);
+ if(!hitResultOfThisActor)
{
- return true;
+ return false;
}
- Actor* parent = actor.GetParent();
- if(parent)
+ RenderTaskPtr fboRenderTask = nullptr;
+ if(hitResultOfThisActor->mHitType == HitType::HIT_MAPPING_ACTOR)
{
- return IsWithinSourceActors(sourceActor, *parent);
+ auto iter = hitCommonInformation.mappingActors.find(hitResultOfThisActor->mActor->GetId());
+ if(iter != hitCommonInformation.mappingActors.end())
+ {
+ fboRenderTask = iter->second;
+ }
+ else
+ {
+ hitResultOfThisActor->mHitType = HitType::HIT_ACTOR;
+ }
}
- // Not within source actors
- return false;
-}
-
-/**
- * Returns true if the actor and all of the actor's parents are hittable.
- */
-bool IsActorActuallyHittable(Actor* actor, HitTestInterface& hitCheck)
-{
- Actor* currentActor = actor;
- // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
- while(currentActor)
+ if(fboRenderTask)
{
- if(!hitCheck.DescendActorHierarchy(currentActor))
+ std::vector<std::shared_ptr<HitResult>> frameBufferHitResultList;
+ Vector2 hitPosition = hitResultOfThisActor->mHitPosition;
+ Vector2 screenSize = hitResultOfThisActor->mActor->GetCurrentSize().GetVectorXY();
+ if(!HitTestRenderTask(frameBufferHitResultList, *fboRenderTask, hitCommonInformation, screenSize, hitPosition, hitCheck))
{
return false;
}
- currentActor = currentActor->GetParent();
+
+ // Every FBO hit result should have same distance of this camera.
+ for(auto&& hitResult : frameBufferHitResultList)
+ {
+ hitResult->mDistance = hitResultOfThisActor->mDistance;
+ hitResultList.push_back(hitResult);
+ }
+ }
+ else
+ {
+ hitResultList.push_back(hitResultOfThisActor);
}
return true;
}
-/**
- * Returns true if the layer and all of the layer's parents are hittable.
- */
-inline bool IsActuallyHittable(Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck)
+void RetrieveValidActorTrees(ActorContainer& validActorRoots,
+ ActorPtr parentActor,
+ const RenderTaskList::ExclusivesContainer& exclusives,
+ HitTestInterface& hitCheck,
+ const Ray& ray,
+ const float& projectedNearClippingDistance,
+ const float& projectedFarClippingDistance)
{
- bool hittable(true);
+ if(parentActor->GetChildCount() == 0)
+ {
+ return;
+ }
- if(layer.IsClipping())
+ if((parentActor->GetClippingMode() == ClippingMode::CLIP_CHILDREN) &&
+ !IsActorPickable(ray, projectedNearClippingDistance, projectedFarClippingDistance, *parentActor))
{
- ClippingBox box = layer.GetClippingBox();
+ return;
+ }
- if(screenCoordinates.x < static_cast<float>(box.x) ||
- screenCoordinates.x > static_cast<float>(box.x + box.width) ||
- screenCoordinates.y < stageSize.y - static_cast<float>(box.y + box.height) ||
- screenCoordinates.y > stageSize.y - static_cast<float>(box.y))
+ ActorContainer& children = parentActor->GetChildrenInternal();
+ ActorContainer::iterator endIter = children.end();
+ for(ActorContainer::iterator iter = children.begin(); endIter != iter; ++iter)
+ {
+ ActorPtr childActor = *iter;
+ if(childActor->IsLayer())
{
- // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
- hittable = false;
+ continue;
}
- }
- if(hittable)
- {
- Actor* actor(&layer);
- hittable = IsActorActuallyHittable(actor, hitCheck);
+ if(childActor->IsOverlay())
+ {
+ bool valid = true;
+ ActorPtr currentNode = childActor;
+ while(currentNode)
+ {
+ if(!IsActorValid(*childActor, exclusives, hitCheck))
+ {
+ valid = false;
+ break;
+ }
+ currentNode = currentNode->GetParent();
+ }
+ if(valid)
+ {
+ validActorRoots.push_back(iter->Get());
+ }
+ }
+ else
+ {
+ RetrieveValidActorTrees(validActorRoots, iter->Get(), exclusives, hitCheck, ray, projectedNearClippingDistance, projectedFarClippingDistance);
+ }
}
-
- return hittable;
}
-/**
- * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task.
- */
-void GetCameraClippingPlane(RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane)
+bool HitTestWithinSubTree(std::vector<std::shared_ptr<HitResult>>& hitResultList,
+ Actor& actor,
+ HitCommonInformation& hitCommonInformation,
+ const Ray& ray,
+ const float& projectedNearClippingDistance,
+ const float& projectedFarClippingDistance,
+ HitTestInterface& hitCheck,
+ Dali::Layer::Behavior layerBehavior)
{
- CameraActor* cameraActor = renderTask.GetCameraActor();
- nearClippingPlane = cameraActor->GetNearClippingPlane();
- farClippingPlane = cameraActor->GetFarClippingPlane();
-}
+ ActorContainer validActorRoots;
+ validActorRoots.push_back(&actor);
-void GeoHitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
- const Vector2& sceneSize,
- LayerList& layers,
- RenderTask& renderTask,
- Vector2 screenCoordinates,
- Results& results,
- HitTestInterface& hitCheck,
- const RayTest& rayTest)
-{
- if(renderTask.IsHittable(screenCoordinates))
+ if(actor.GetScene().HasOverlayContent())
{
- Viewport viewport;
- renderTask.GetHittableViewport(viewport);
+ RetrieveValidActorTrees(validActorRoots, &actor, hitCommonInformation.exclusives, hitCheck, ray, projectedNearClippingDistance, projectedFarClippingDistance);
+ }
- if(screenCoordinates.x < static_cast<float>(viewport.x) ||
- screenCoordinates.x > static_cast<float>(viewport.x + viewport.width) ||
- screenCoordinates.y < static_cast<float>(viewport.y) ||
- screenCoordinates.y > static_cast<float>(viewport.y + viewport.height))
+ bool isKeepingHitTestRequired = (hitCheck.GetPropagationType() == Integration::Scene::TouchPropagationType::GEOMETRY) || (layerBehavior == Dali::Layer::Behavior::LAYER_3D);
+
+ ActorContainer::reverse_iterator endIter = validActorRoots.rend();
+ for(ActorContainer::reverse_iterator iter = validActorRoots.rbegin(); endIter != iter; ++iter)
+ {
+ if(HitTestActorRecursively(hitResultList, *iter, hitCommonInformation, ray, projectedNearClippingDistance, projectedFarClippingDistance, hitCheck, layerBehavior, isKeepingHitTestRequired, iter->Get()->IsOverlay()))
{
- // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
- return;
+ break;
}
+ }
- float nearClippingPlane, farClippingPlane;
- GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
-
- // Determine the layer depth of the source actor
- Actor* sourceActor(renderTask.GetSourceActor());
- if(sourceActor)
- {
- Dali::Layer sourceLayer(sourceActor->GetLayer());
- if(sourceLayer)
- {
- const uint32_t sourceActorDepth(sourceLayer.GetProperty<int32_t>(Dali::Layer::Property::DEPTH));
- CameraActor* cameraActor = renderTask.GetCameraActor();
- bool pickingPossible = cameraActor->BuildPickingRay(screenCoordinates,
- viewport,
- results.rayOrigin,
- results.rayDirection);
- if(!pickingPossible)
- {
- return;
- }
+ if(hitResultList.empty())
+ {
+ return false;
+ }
- // Hit test starting with the top layer, working towards the bottom layer.
- bool overlayHit = false;
+ if(layerBehavior == Dali::Layer::Behavior::LAYER_3D)
+ {
+ std::stable_sort(hitResultList.begin(), hitResultList.end(), [](std::shared_ptr<HitResult> first, std::shared_ptr<HitResult> second)
+ {
+ if(std::abs(first->mDistance - second->mDistance) < Dali::Epsilon<1000>::value)
+ {
+ return first->mActor->GetSortingDepth() > second->mActor->GetSortingDepth();
+ }
+ else
+ {
+ return first->mDistance < second->mDistance;
+ } });
+ }
- for(uint32_t i = 0; i < layers.GetLayerCount(); ++i)
- {
- Layer* layer(layers.GetLayer(i));
- overlayHit = false;
- HitActor hit;
-
- // Ensure layer is touchable (also checks whether ancestors are also touchable)
- if(IsActuallyHittable(*layer, screenCoordinates, sceneSize, hitCheck))
- {
- // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
- if(sourceActorDepth == i)
- {
- // Recursively hit test the source actor & children, without crossing into other layers.
- hit = HitTestWithinLayer(*sourceActor,
- renderTask,
- exclusives,
- results.rayOrigin,
- results.rayDirection,
- nearClippingPlane,
- farClippingPlane,
- hitCheck,
- overlayHit,
- overlayHit,
- layer->GetBehavior() == Dali::Layer::LAYER_3D,
- rayTest,
- results.point,
- results.eventTime,
- results.actorLists,
- Integration::Scene::TouchPropagationType::GEOMETRY);
- }
- else if(IsWithinSourceActors(*sourceActor, *layer))
- {
- // Recursively hit test all the actors, without crossing into other layers.
- hit = HitTestWithinLayer(*layer,
- renderTask,
- exclusives,
- results.rayOrigin,
- results.rayDirection,
- nearClippingPlane,
- farClippingPlane,
- hitCheck,
- overlayHit,
- overlayHit,
- layer->GetBehavior() == Dali::Layer::LAYER_3D,
- rayTest,
- results.point,
- results.eventTime,
- results.actorLists,
- Integration::Scene::TouchPropagationType::GEOMETRY);
- }
- }
-
- if(hit.actor)
- {
- results.renderTask = RenderTaskPtr(&renderTask);
- results.actor = Dali::Actor(hit.actor);
- results.actorCoordinates = hit.hitPosition;
- }
- }
- }
- }
+ if(hitCheck.GetPropagationType() == Integration::Scene::TouchPropagationType::PARENT)
+ {
+ hitResultList.resize(1);
}
- return;
+
+ return true;
}
/**
* Hit test a RenderTask
*/
-bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
- const Vector2& sceneSize,
- LayerList& layers,
- RenderTask& renderTask,
- Vector2 screenCoordinates,
- Results& results,
- HitTestInterface& hitCheck,
- const RayTest& rayTest)
+bool HitTestRenderTask(std::vector<std::shared_ptr<HitResult>>& hitResultList,
+ RenderTask& renderTask,
+ HitCommonInformation& hitCommonInformation,
+ const Vector2& screenSize,
+ Vector2 screenCoordinates,
+ HitTestInterface& hitCheck)
{
- if(renderTask.IsHittable(screenCoordinates))
+ curRenderTask = &renderTask;
+ if(!renderTask.IsInputAvailable())
{
- Viewport viewport;
- renderTask.GetHittableViewport(viewport);
+ return false;
+ }
- if(screenCoordinates.x < static_cast<float>(viewport.x) ||
- screenCoordinates.x > static_cast<float>(viewport.x + viewport.width) ||
- screenCoordinates.y < static_cast<float>(viewport.y) ||
- screenCoordinates.y > static_cast<float>(viewport.y + viewport.height))
- {
- // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
- return false;
- }
+ Actor* sourceActor(renderTask.GetSourceActor());
+ if(!sourceActor)
+ {
+ return false;
+ }
- float nearClippingPlane, farClippingPlane;
- GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
+ Dali::Layer sourceLayer(sourceActor->GetLayer());
+ if(!sourceLayer)
+ {
+ return false;
+ }
+
+ Ray ray;
+ if(!renderTask.GetCameraActor()->BuildPickingRay(screenCoordinates, screenSize, ray.origin, ray.direction))
+ {
+ return false;
+ }
+
+ float nearClippingPlane, farClippingPlane;
+ GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
- // Determine the layer depth of the source actor
- Actor* sourceActor(renderTask.GetSourceActor());
+ // Recompute near and far clipping plane distance with the picking ray.
+ Vector3 centerDirection = renderTask.GetCameraActor()->GetCurrentWorldOrientation().Rotate(Dali::Vector3::ZAXIS);
+ centerDirection.Normalize();
+ float projectionFactor = centerDirection.Dot(Vector3(ray.direction));
+ float projectedNearClippingDistance = nearClippingPlane / projectionFactor;
+ float projectedFarClippingDistance = farClippingPlane / projectionFactor;
- // Check the source actor is actually hittable or not.
- if(sourceActor && IsActorActuallyHittable(sourceActor, hitCheck))
+ Vector2 hitPosition;
+ for(int32_t i = hitCommonInformation.layers.GetLayerCount() - 1; i >= 0; --i)
+ {
+ Layer* layer(hitCommonInformation.layers.GetLayer(i));
+ Actor* testRootActor = (sourceLayer == layer) ? sourceActor : ((IsWithinSourceActors(*sourceActor, *layer)) ? layer : nullptr);
+ if(!testRootActor)
{
- Dali::Layer sourceLayer(sourceActor->GetLayer());
- if(sourceLayer)
- {
- const uint32_t sourceActorDepth(sourceLayer.GetProperty<int32_t>(Dali::Layer::Property::DEPTH));
-
- CameraActor* cameraActor = renderTask.GetCameraActor();
- bool pickingPossible = cameraActor->BuildPickingRay(
- screenCoordinates,
- viewport,
- results.rayOrigin,
- results.rayDirection);
- if(!pickingPossible)
- {
- return false;
- }
+ continue;
+ }
- // Hit test starting with the top layer, working towards the bottom layer.
- HitActor hit;
- bool overlayHit = false;
- bool layerConsumesHit = false;
-
- // Be used when we decide to consume layer.
- // We should not consume hit if sourceLayer is above on consumable layer. Otherwise, we should consume. So just initialize it as 0.
- // sourceLayerIndex can be a relative value to calculate the relationship with the layer.
- // If the layer is consumed first, sourceLayerIndex is not the actual index, but it must be guaranteed to have an index smaller than the layer.
- // If there is a sourceLayer above the consumable layer, the sourceLayerIndex is determined and the index of the consumable layer is also determined.
- // Then we can calculate the relationship between the two layers.
- bool IsHitTestWithinLayer = false;
- int32_t sourceLayerIndex = 0;
- int32_t consumedLayerIndex = -1;
-
- for(int32_t i = layers.GetLayerCount() - 1; i >= 0 && !(hit.actor); --i)
- {
- Layer* layer(layers.GetLayer(i));
- overlayHit = false;
- IsHitTestWithinLayer = false;
-
- if(sourceLayer == layer)
- {
- sourceLayerIndex = i;
- }
-
- // Ensure layer is touchable (also checks whether ancestors are also touchable)
- if(IsActuallyHittable(*layer, screenCoordinates, sceneSize, hitCheck))
- {
- // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
- if(sourceActorDepth == static_cast<uint32_t>(i))
- {
- IsHitTestWithinLayer = true;
- // Recursively hit test the source actor & children, without crossing into other layers.
- hit = HitTestWithinLayer(*sourceActor,
- renderTask,
- exclusives,
- results.rayOrigin,
- results.rayDirection,
- nearClippingPlane,
- farClippingPlane,
- hitCheck,
- overlayHit,
- overlayHit,
- layer->GetBehavior() == Dali::Layer::LAYER_3D,
- rayTest,
- results.point,
- results.eventTime,
- results.actorLists,
- Integration::Scene::TouchPropagationType::PARENT);
- }
- else if(IsWithinSourceActors(*sourceActor, *layer))
- {
- IsHitTestWithinLayer = true;
- // Recursively hit test all the actors, without crossing into other layers.
- hit = HitTestWithinLayer(*layer,
- renderTask,
- exclusives,
- results.rayOrigin,
- results.rayDirection,
- nearClippingPlane,
- farClippingPlane,
- hitCheck,
- overlayHit,
- overlayHit,
- layer->GetBehavior() == Dali::Layer::LAYER_3D,
- rayTest,
- results.point,
- results.eventTime,
- results.actorLists,
- Integration::Scene::TouchPropagationType::PARENT);
- }
-
- // If this layer is set to consume the hit, then do not check any layers behind it
- if(IsHitTestWithinLayer && hitCheck.DoesLayerConsumeHit(layer))
- {
- consumedLayerIndex = i;
- layerConsumesHit = true;
- break;
- }
- }
- }
+ // If source Actor is been exclusive by other RenderTask, skip it.
+ if(IsActorExclusive(*testRootActor, hitCommonInformation.exclusives) && (!renderTask.IsExclusive() || testRootActor != sourceActor))
+ {
+ continue;
+ }
- if(hit.actor)
- {
- results.renderTask = RenderTaskPtr(&renderTask);
- results.actor = Dali::Actor(hit.actor);
- results.actorCoordinates = hit.hitPosition;
+ if(!IsActorActuallyHittable(testRootActor, hitCheck))
+ {
+ continue;
+ }
- return true; // Success
- }
+ std::vector<std::shared_ptr<HitResult>> subTreeHitResultList;
+ bool isHit = HitTestWithinSubTree(subTreeHitResultList,
+ *testRootActor,
+ hitCommonInformation,
+ ray,
+ projectedNearClippingDistance,
+ projectedFarClippingDistance,
+ hitCheck,
+ layer->GetBehavior());
+
+ if(!isHit && hitCheck.DoesLayerConsumeHit(layer))
+ {
+ hitResultList.push_back(std::make_shared<HitResult>(layer, Vector2(0.0f, 0.0f), 0.0f, HitType::HIT_ACTOR, ray));
+ break;
+ }
- if(layerConsumesHit)
- {
- // Consumes if the hitted layer is above the SourceActor's layer.
- bool ret = sourceLayerIndex <= consumedLayerIndex;
- if(ret)
- {
- DALI_LOG_RELEASE_INFO("layer is set to consume the hit\n");
- results.renderTask = RenderTaskPtr(&renderTask);
- results.actor = Dali::Layer(layers.GetLayer(consumedLayerIndex));
- }
- return ret;
- }
- }
+ hitResultList.insert(hitResultList.end(), subTreeHitResultList.begin(), subTreeHitResultList.end());
+
+ if(isHit && hitCheck.GetPropagationType() == Integration::Scene::TouchPropagationType::PARENT)
+ {
+ break;
}
}
- return false;
+
+ if(hitResultList.empty())
+ {
+ return false;
+ }
+
+ return true;
}
-/**
- * Selects Prior Actor that is rendered later between firstActor and secondActor in the layer of rootActor.
- * if only one of Actor is included in the layer, returns the Actor.
- * if both of the firstActor and secondActor are not included in the layer, returns empty Actor.
- */
-Dali::Actor FindPriorActorInLayer(Dali::Actor rootActor, Dali::Actor firstActor, Dali::Actor secondActor)
+bool ConvertScreenCoordinates(Vector2& convertedScreenCoordinates, const Vector2& screenCoordinates, const RenderTask& targetRenderTask)
{
- Dali::Actor priorActor;
- Dali::Layer layer = rootActor.GetLayer();
- bool firstActorIncluded = firstActor.GetLayer() == layer;
- bool secondActorIncluded = secondActor.GetLayer() == layer;
+ Viewport viewport;
+ targetRenderTask.GetViewport(viewport);
- if(firstActorIncluded && !secondActorIncluded)
- {
- priorActor = firstActor;
- }
- else if(!firstActorIncluded && secondActorIncluded)
- {
- priorActor = secondActor;
- }
- else if(firstActorIncluded && secondActorIncluded)
+ if(screenCoordinates.x < static_cast<float>(viewport.x) ||
+ screenCoordinates.x > static_cast<float>(viewport.x + viewport.width) ||
+ screenCoordinates.y < static_cast<float>(viewport.y) ||
+ screenCoordinates.y > static_cast<float>(viewport.y + viewport.height))
{
- priorActor = (GetImplementation(firstActor).GetSortingDepth() < GetImplementation(secondActor).GetSortingDepth()) ? secondActor : firstActor;
+ // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
+ return false;
}
+ convertedScreenCoordinates = screenCoordinates - Vector2(static_cast<float>(viewport.x), static_cast<float>(viewport.y));
- return priorActor;
+ return true;
}
-/**
- * Selects Prior Actor that is rendered later between firstActor and secondActor from child scene tree of rootActor.
- */
-Dali::Actor FindPriorActorInLayers(const LayerList& layers, Dali::Actor rootActor, Dali::Actor firstActor, Dali::Actor secondActor)
+void CollectMappingActors(RenderTaskList::RenderTaskContainer& tasks, std::unordered_map<uint32_t, RenderTaskPtr>& mappingActors)
{
- Dali::Layer sourceLayer = rootActor.GetLayer();
- const uint32_t sourceActorDepth(sourceLayer.GetProperty<int>(Dali::Layer::Property::DEPTH));
-
- Dali::Actor priorActor;
- uint32_t layerCount = layers.GetLayerCount();
- if(layerCount > 0)
+ RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
+ for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
{
- for(int32_t i = layerCount - 1; i >= 0; --i)
+ RenderTask& renderTask = *iter->Get();
+ if(renderTask.GetFrameBuffer() && renderTask.GetScreenToFrameBufferMappingActor())
{
- Layer* layer(layers.GetLayer(i));
- if(sourceActorDepth == static_cast<uint32_t>(i))
- {
- priorActor = FindPriorActorInLayer(rootActor, firstActor, secondActor);
- }
- else if(IsWithinSourceActors(GetImplementation(rootActor), *layer))
- {
- Dali::Actor layerRoot = Dali::Actor(layer);
- priorActor = FindPriorActorInLayer(layerRoot, firstActor, secondActor);
- }
-
- if(priorActor)
- {
- break;
- }
+ uint32_t mappingActorId = renderTask.GetScreenToFrameBufferMappingActor().GetProperty<int32_t>(Dali::Actor::Property::ID);
+ mappingActors[mappingActorId] = RenderTaskPtr(&renderTask);
}
}
- return priorActor;
}
/**
* @return True if we have a hit, false otherwise
*/
bool HitTestRenderTaskList(const Vector2& sceneSize,
- LayerList& layers,
RenderTaskList& taskList,
+ LayerList& layers,
const Vector2& screenCoordinates,
- Results& results,
HitTestInterface& hitCheck,
- const Integration::Scene::TouchPropagationType propagationType)
+ const Integration::Scene::TouchPropagationType propagationType,
+ Results& results)
{
- if(propagationType == Integration::Scene::TouchPropagationType::GEOMETRY)
- {
- RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
- RenderTaskList::RenderTaskContainer::iterator endIter = tasks.end();
- const auto& exclusives = taskList.GetExclusivesList();
- RayTest rayTest;
+ bool isHitSucceeded = false;
+ RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
+ const auto& exclusives = taskList.GetExclusivesList();
- // Hit test order should be of draw order
- for(RenderTaskList::RenderTaskContainer::iterator iter = tasks.begin(); endIter != iter; ++iter)
- {
- RenderTask& renderTask = *iter->Get();
- GeoHitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest);
- }
+ HitCommonInformation hitCommonInformation{exclusives, std::unordered_map<uint32_t, RenderTaskPtr>(), layers};
+ CollectMappingActors(tasks, hitCommonInformation.mappingActors);
- return !results.actorLists.empty();
- }
- else
+ RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
+ for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
{
- RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
- RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
- const auto& exclusives = taskList.GetExclusivesList();
- RayTest rayTest;
-
- Results storedResults = results;
- std::vector<std::pair<Dali::Actor, Results>> offScreenHitResults;
- // Hit test order should be reverse of draw order
- for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
+ RenderTask& renderTask = *iter->Get();
+ if(renderTask.GetFrameBuffer() && renderTask.GetScreenToFrameBufferMappingActor())
{
- RenderTask& renderTask = *iter->Get();
- if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
- {
- if(renderTask.GetFrameBuffer())
- {
- Results result = results;
- offScreenHitResults.push_back(std::make_pair(renderTask.GetScreenToFrameBufferMappingActor(), std::move(result)));
- continue;
- }
+ continue;
+ }
- if(offScreenHitResults.empty())
- {
- return true;
- }
+ // Don't need to consider a RenderTask draws on window and its source actor is inside FBO.
+ // Can't support it.
+ Viewport viewport;
+ std::vector<std::shared_ptr<HitResult>> hitResults;
+ Vector2 convertedScreenCoordinates;
+ renderTask.GetViewport(viewport);
+ if(ConvertScreenCoordinates(convertedScreenCoordinates, screenCoordinates, renderTask) &&
+ HitTestRenderTask(hitResults, renderTask, hitCommonInformation, Vector2(viewport.width, viewport.height), convertedScreenCoordinates, hitCheck))
+ {
+ results.actor = Dali::Actor(hitResults.front()->mActor);
+ results.renderTask = RenderTaskPtr(&renderTask);
+ results.actorCoordinates = hitResults.front()->mHitPosition;
+ results.rayOrigin = hitResults.front()->mRay.origin;
+ results.rayDirection = hitResults.front()->mRay.direction;
- Actor* sourceActor(renderTask.GetSourceActor());
- for(auto&& pair : offScreenHitResults)
+ if(hitCheck.GetPropagationType() == Integration::Scene::TouchPropagationType::GEOMETRY)
+ {
+ std::vector<std::shared_ptr<HitResult>>::reverse_iterator endIter = hitResults.rend();
+ for(std::vector<std::shared_ptr<HitResult>>::reverse_iterator iter = hitResults.rbegin(); endIter != iter; ++iter)
{
- Dali::Actor mappingActor = pair.first;
- if(!mappingActor || !IsWithinSourceActors(*sourceActor, GetImplementation(mappingActor)))
- {
- continue;
- }
-
- bool mappingActorInsideHitConsumingLayer = false;
- if(GetImplementation(results.actor).IsLayer())
- {
- Dali::Layer resultLayer = Dali::Layer::DownCast(results.actor);
- // Check the resultLayer is consuming hit even though the layer is not hittable.
- // And check the resultLayer is the layer of mappingActor too.
- if(hitCheck.DoesLayerConsumeHit(&GetImplementation(resultLayer)) && !hitCheck.IsActorHittable(&GetImplementation(results.actor)) && results.actor == mappingActor.GetLayer())
- {
- mappingActorInsideHitConsumingLayer = true;
- }
- }
- if(mappingActorInsideHitConsumingLayer || mappingActor == FindPriorActorInLayers(layers, Dali::Actor(sourceActor), mappingActor, results.actor))
- {
- results = pair.second;
- break;
- }
+ results.actorLists.push_back(iter->get()->mActor);
}
- // Return true when an actor is hit (or layer in our render-task consumes the hit)
- return true;
}
+ isHitSucceeded = true;
+ break;
}
-
- // When no OnScreen Actor is hitted but there are hit results from OffScreen RenderTasks
- // those use ScreenToFrameBufferFunction, simply returns first hitted result.
- if(!offScreenHitResults.empty())
- {
- results = offScreenHitResults.front().second;
- return true;
- }
-
- results = storedResults;
- }
- return false;
-}
-
-/**
- * Iterate through the RenderTaskList and perform hit testing for both on-screen and off-screen.
- *
- * @param[in] sceneSize The scene size the tests will be performed in
- * @param[in] layers The list of layers to test
- * @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] propagationType Whether the scene using geometry event propagation touch and hover events.
- * @return True if we have a hit, false otherwise
- */
-bool HitTestForEachRenderTask(const Vector2& sceneSize,
- LayerList& layers,
- RenderTaskList& taskList,
- const Vector2& screenCoordinates,
- Results& results,
- HitTestInterface& hitCheck,
- const Integration::Scene::TouchPropagationType propagationType)
-{
- bool result = false;
-
- if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, propagationType))
- {
- // Found hit.
- result = true;
}
-
- return result;
+ return isHitSucceeded;
}
} // unnamed namespace
HitTestInterface::~HitTestInterface() = default;
-bool HitTest(const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func, const Integration::Scene::TouchPropagationType propagationType)
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func, const Integration::Scene::TouchPropagationType propagationType)
{
bool wasHit(false);
// Hit-test the regular on-scene actors
hitTestResults.eventTime = 0u; ///< Unused
HitTestFunctionWrapper hitTestFunctionWrapper(func);
- if(HitTestForEachRenderTask(sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper, propagationType))
+ // TODO : It looks better to do this before hit test is required.
+ hitTestFunctionWrapper.SetPoint(hitTestResults.point);
+ hitTestFunctionWrapper.SetTimeStamp(hitTestResults.eventTime);
+ hitTestFunctionWrapper.SetPropagationType(propagationType);
+ if(HitTestRenderTaskList(sceneSize, renderTaskList, layerList, screenCoordinates, hitTestFunctionWrapper, propagationType, hitTestResults))
{
results.actor = hitTestResults.actor;
results.actorCoordinates = hitTestResults.actorCoordinates;
bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface, const Integration::Scene::TouchPropagationType propagationType)
{
- bool wasHit(false);
+ // TODO : It looks better to do this before hit test is required.
+ hitTestInterface.SetPoint(results.point);
+ hitTestInterface.SetTimeStamp(results.eventTime);
+ hitTestInterface.SetPropagationType(propagationType);
// Hit-test the regular on-scene actors
- if(!wasHit)
- {
- wasHit = HitTestForEachRenderTask(sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface, propagationType);
- }
- return wasHit;
+ return HitTestRenderTaskList(sceneSize, renderTaskList, layerList, screenCoordinates, hitTestInterface, propagationType, results);
}
bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor, const Integration::Scene::TouchPropagationType propagationType)