return hittable;
};
+bool IsActorTouchableFunctionWithoutLayerHit(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
+{
+ bool hittable = false;
+
+ switch(type)
+ {
+ case Dali::HitTestAlgorithm::CHECK_ACTOR:
+ {
+ if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) &&
+ actor.GetProperty<bool>(Actor::Property::SENSITIVE) &&
+ actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f &&
+ actor.GetLayer() != actor)
+ {
+ hittable = true;
+ }
+ break;
+ }
+ case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+ {
+ if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && // Actor is visible, if not visible then none of its children are visible.
+ actor.GetProperty<bool>(Actor::Property::SENSITIVE)) // Actor is sensitive, if insensitive none of its children should be hittable either.
+ {
+ hittable = true;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return hittable;
+};
+
} // anonymous namespace
// Positive test case for a method
END_TEST;
}
-int UtcDaliHitTestAlgorithmOrder(void)
+int UtcDaliHitTestAlgorithmOrder1(void)
{
TestApplication application;
tet_infoline("Testing Dali::HitTestAlgorithm between On/Off render task");
END_TEST;
}
+int UtcDaliHitTestAlgorithmOrder2(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::HitTestAlgorithm in for the mapping actor and its child");
+
+ Stage stage = Stage::GetCurrent();
+ Vector2 stageSize(stage.GetSize());
+
+ Actor blue = Actor::New();
+ blue[Dali::Actor::Property::NAME] = "Blue";
+ blue[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor green = Actor::New();
+ green[Dali::Actor::Property::NAME] = "Green";
+ green[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ green[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor red = Actor::New();
+ red[Dali::Actor::Property::NAME] = "Red";
+ red[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ red[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ red[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor yellow = Actor::New();
+ yellow[Dali::Actor::Property::NAME] = "Yellow";
+ yellow[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ yellow[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ yellow[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ yellow[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ stage.Add(blue);
+ stage.Add(green);
+ stage.Add(yellow);
+
+ RenderTaskList renderTaskList = stage.GetRenderTaskList();
+ RenderTask offRenderTask = renderTaskList.CreateTask();
+
+ Dali::CameraActor cameraActor = Dali::CameraActor::New(stageSize);
+ cameraActor[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ stage.Add(cameraActor);
+
+ offRenderTask.SetExclusive(true);
+ offRenderTask.SetInputEnabled(true);
+ offRenderTask.SetCameraActor(cameraActor);
+ offRenderTask.SetSourceActor(yellow);
+ offRenderTask.SetScreenToFrameBufferMappingActor(green);
+
+ Dali::Texture texture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+ FrameBuffer renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+ renderTarget.AttachColorTexture(texture);
+ offRenderTask.SetFrameBuffer(renderTarget);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ HitTestAlgorithm::Results results;
+ HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+ DALI_TEST_CHECK(results.actor == yellow);
+
+ green.Add(red);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ results = HitTestAlgorithm::Results();
+ HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+ DALI_TEST_CHECK(results.actor == red);
+
+ END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmInMultipleLayer(void)
+{
+ TestApplication application;
+ tet_infoline("Testing UtcDaliHitTestAlgorithmInMultipleLayer");
+
+ Stage stage = Stage::GetCurrent();
+ Vector2 stageSize(stage.GetSize());
+
+ Actor blue = Actor::New();
+ blue[Dali::Actor::Property::NAME] = "Blue";
+ blue[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Layer layer = Layer::New();
+ layer[Dali::Actor::Property::NAME] = "Layer";
+ layer[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ layer[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ layer[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ layer[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor green = Actor::New();
+ green[Dali::Actor::Property::NAME] = "Green";
+ green[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ green[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor red = Actor::New();
+ red[Dali::Actor::Property::NAME] = "Red";
+ red[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ red[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ red[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ stage.Add(blue);
+ stage.Add(layer);
+ layer.Add(green);
+ stage.Add(red);
+
+ RenderTaskList renderTaskList = stage.GetRenderTaskList();
+ RenderTask offRenderTask = renderTaskList.CreateTask();
+
+ Dali::CameraActor cameraActor = Dali::CameraActor::New(stageSize);
+ cameraActor[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ stage.Add(cameraActor);
+
+ offRenderTask.SetExclusive(true);
+ offRenderTask.SetInputEnabled(true);
+ offRenderTask.SetCameraActor(cameraActor);
+ offRenderTask.SetSourceActor(layer);
+ offRenderTask.SetScreenToFrameBufferMappingActor(red);
+
+ Dali::Texture texture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+ FrameBuffer renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+ renderTarget.AttachColorTexture(texture);
+ offRenderTask.SetFrameBuffer(renderTarget);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ HitTestAlgorithm::Results results;
+ HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+ DALI_TEST_CHECK(results.actor == green);
+
+ END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmOffSceneMappingActor(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::HitTestAlgorithm with OffSceneMappingActor");
+
+ Stage stage = Stage::GetCurrent();
+ Vector2 stageSize(stage.GetSize());
+
+ Actor blue = Actor::New();
+ blue[Dali::Actor::Property::NAME] = "Blue";
+ blue[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ blue[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor green = Actor::New();
+ green[Dali::Actor::Property::NAME] = "Green";
+ green[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ green[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ Actor red = Actor::New();
+ red[Dali::Actor::Property::NAME] = "Red";
+ red[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ red[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ red[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ stage.Add(blue);
+ stage.Add(green);
+
+ RenderTaskList renderTaskList = stage.GetRenderTaskList();
+ RenderTask offRenderTask = renderTaskList.CreateTask();
+
+ Dali::CameraActor cameraActor = Dali::CameraActor::New(stageSize);
+ cameraActor[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ stage.Add(cameraActor);
+
+ offRenderTask.SetExclusive(true);
+ offRenderTask.SetInputEnabled(true);
+ offRenderTask.SetCameraActor(cameraActor);
+ offRenderTask.SetSourceActor(green);
+ offRenderTask.SetScreenToFrameBufferMappingActor(red);
+
+ Dali::Texture texture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+ FrameBuffer renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+ renderTarget.AttachColorTexture(texture);
+ offRenderTask.SetFrameBuffer(renderTarget);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ HitTestAlgorithm::Results results;
+ HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+ DALI_TEST_CHECK(results.actor == blue);
+
+ stage.Add(red);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+ DALI_TEST_CHECK(results.actor == green);
+
+ END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmScreenToFrameBufferFunction(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::HitTestAlgorithm using ScreenToFrameBufferFunction");
+
+ Stage stage = Stage::GetCurrent();
+ Vector2 stageSize(stage.GetSize());
+
+ Actor green = Actor::New();
+ green[Dali::Actor::Property::NAME] = "Green";
+ green[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ green[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ green[Dali::Actor::Property::WIDTH_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+ green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+ stage.Add(green);
+
+ RenderTaskList renderTaskList = stage.GetRenderTaskList();
+ RenderTask offRenderTask = renderTaskList.CreateTask();
+
+ Dali::CameraActor cameraActor = Dali::CameraActor::New(stageSize);
+ cameraActor[Dali::Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER;
+ cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+ stage.Add(cameraActor);
+
+ offRenderTask.SetExclusive(true);
+ offRenderTask.SetInputEnabled(true);
+ offRenderTask.SetCameraActor(cameraActor);
+ offRenderTask.SetSourceActor(green);
+ offRenderTask.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+ offRenderTask.SetViewport(Viewport(Vector4(0, 0, 480, 800)));
+
+ Dali::Texture texture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+ FrameBuffer renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+ renderTarget.AttachColorTexture(texture);
+ offRenderTask.SetFrameBuffer(renderTarget);
+
+ // Render and notify
+ application.SendNotification();
+ application.Render(10);
+
+ HitTestAlgorithm::Results results;
+ HitTest(stage, stageSize / 2.0f, results, &IsActorTouchableFunctionWithoutLayerHit);
+ DALI_TEST_CHECK(results.actor == green);
+
+ END_TEST;
+}
+
int UtcDaliHitTestAlgorithmExclusiveMultiple(void)
{
TestApplication application;
}
/**
- * Returns true if the layer and all of the layer's parents are visible and sensitive.
+ * 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(!hitCheck.DescendActorHierarchy(currentActor))
+ {
+ return false;
+ }
+ currentActor = currentActor->GetParent();
+ }
+
+ 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)
{
if(hittable)
{
Actor* actor(&layer);
-
- // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
- while(actor && hittable)
- {
- if(!hitCheck.DescendActorHierarchy(actor))
- {
- hittable = false;
- break;
- }
- actor = actor->GetParent();
- }
+ hittable = IsActorActuallyHittable(actor, hitCheck);
}
return hittable;
// Determine the layer depth of the source actor
Actor* sourceActor(renderTask.GetSourceActor());
- if(sourceActor)
+
+ // Check the source actor is actually hittable or not.
+ if(sourceActor && IsActorActuallyHittable(sourceActor, hitCheck))
{
Dali::Layer sourceLayer(sourceActor->GetLayer());
if(sourceLayer)
}
/**
+ * 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)
+{
+ Dali::Actor priorActor;
+ Dali::Layer layer = rootActor.GetLayer();
+ bool firstActorIncluded = firstActor.GetLayer() == layer;
+ bool secondActorIncluded = secondActor.GetLayer() == layer;
+
+ if(firstActorIncluded && !secondActorIncluded)
+ {
+ priorActor = firstActor;
+ }
+ else if(!firstActorIncluded && secondActorIncluded)
+ {
+ priorActor = secondActor;
+ }
+ else if(firstActorIncluded && secondActorIncluded)
+ {
+ priorActor = (GetImplementation(firstActor).GetSortingDepth() < GetImplementation(secondActor).GetSortingDepth()) ? secondActor : firstActor;
+ }
+
+ return priorActor;
+}
+
+/**
+ * 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)
+{
+ 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)
+ {
+ for(int32_t i = layerCount - 1; i >= 0; --i)
+ {
+ 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;
+ }
+ }
+ }
+ return priorActor;
+}
+
+/**
* Iterate through the RenderTaskList and perform hit testing.
*
* @param[in] sceneSize The scene size the tests will be performed in
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(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;
+ }
+
+ if(offScreenHitResults.empty())
+ {
+ return true;
+ }
+
+ Actor* sourceActor(renderTask.GetSourceActor());
+ for(auto&& pair : offScreenHitResults)
+ {
+ 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;
+ }
+ }
// Return true when an actor is hit (or layer in our render-task consumes the hit)
return true;
}
}
- return false;
+
+ // 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;
}
/**