/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
#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/stage-impl.h>
#include <dali/internal/event/common/projection.h>
-#include <dali/internal/event/images/frame-buffer-image-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>
struct HitActor
{
HitActor()
- : actor( NULL ),
+ : actor( nullptr ),
distance( std::numeric_limits<float>::max() ),
depth( std::numeric_limits<int>::min() )
{
{
}
- virtual bool IsActorHittable( Actor* actor )
+ bool IsActorHittable( Actor* actor ) override
{
return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::CHECK_ACTOR );
}
- virtual bool DescendActorHierarchy( Actor* actor )
+ bool DescendActorHierarchy( Actor* actor ) override
{
return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE );
}
- virtual bool DoesLayerConsumeHit( Layer* layer )
+ bool DoesLayerConsumeHit( Layer* layer ) override
{
// Layer::IsTouchConsumed() focuses on touch only. Here we are a wrapper for the public-api
// where the caller may want to check for something completely different.
*/
struct ActorTouchableCheck : public HitTestInterface
{
- virtual bool IsActorHittable( Actor* actor )
+ bool IsActorHittable( Actor* actor ) override
{
return actor->GetTouchRequired() && // Does the Application or derived actor type require a touch event?
actor->IsHittable(); // Is actor sensitive, visible and on the scene?
}
- virtual bool DescendActorHierarchy( Actor* actor )
+ bool DescendActorHierarchy( Actor* actor ) override
{
return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
}
- virtual bool DoesLayerConsumeHit( Layer* layer )
+ bool DoesLayerConsumeHit( Layer* layer ) override
{
return layer->IsTouchConsumed();
}
*/
bool IsActorExclusiveToAnotherRenderTask( const Actor& actor,
const RenderTask& renderTask,
- const Vector< RenderTaskList::Exclusive >& exclusives )
+ const RenderTaskList::ExclusivesContainer& exclusives )
{
- if( exclusives.Size() )
+ if( exclusives.size() )
{
- for( Vector< RenderTaskList::Exclusive >::Iterator exclusiveIt = exclusives.Begin(); exclusives.End() != exclusiveIt; ++exclusiveIt )
+ for( const auto& exclusive : exclusives )
{
- if( ( exclusiveIt->renderTaskPtr != &renderTask ) && ( exclusiveIt->actorPtr == &actor ) )
+ if( ( exclusive.renderTaskPtr != &renderTask ) && ( exclusive.actor.GetActor() == &actor ) )
{
return true;
}
*/
HitActor HitTestWithinLayer( Actor& actor,
const RenderTask& renderTask,
- const Vector< RenderTaskList::Exclusive >& exclusives,
+ const RenderTaskList::ExclusivesContainer& exclusives,
const Vector4& rayOrigin,
const Vector4& rayDir,
float& nearClippingPlane,
bool& overlayHit,
bool layerIs3d,
uint32_t clippingDepth,
- uint32_t clippingBitPlaneMask )
+ uint32_t clippingBitPlaneMask,
+ const RayTest& rayTest )
{
HitActor hit;
// 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 && actor.RaySphereTest( rayOrigin, rayDir ) )
+ if( size.x > 0.0f && size.y > 0.0f && rayTest.SphereTest( actor, rayOrigin, rayDir ) )
{
Vector2 hitPointLocal;
float distance;
// Finally, perform a more accurate ray test to see if our ray actually hits the actor.
- if( actor.RayActorTest( rayOrigin, rayDir, hitPointLocal, distance ) )
+ if( rayTest.ActorTest( actor, rayOrigin, rayDir, hitPointLocal, distance ) )
{
if( distance >= nearClippingPlane && distance <= farClippingPlane )
{
overlayHit,
layerIs3d,
newClippingDepth,
- clippingBitPlaneMask ) );
+ clippingBitPlaneMask,
+ rayTest ) );
+
+ // 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;
+ }
bool updateChildHit = false;
if( currentHit.distance >= 0.0f )
/**
* Hit test a RenderTask
*/
-bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
- Stage& stage,
+bool HitTestRenderTask( const RenderTaskList::ExclusivesContainer& exclusives,
+ const Vector2& sceneSize,
LayerList& layers,
RenderTask& renderTask,
Vector2 screenCoordinates,
Results& results,
- HitTestInterface& hitCheck )
+ HitTestInterface& hitCheck,
+ const RayTest& rayTest )
{
if ( renderTask.IsHittable( screenCoordinates ) )
{
Dali::Layer layer( sourceActor->GetLayer() );
if( layer )
{
- const uint32_t sourceActorDepth( layer.GetDepth() );
+ const uint32_t sourceActorDepth( layer.GetProperty< bool >( Dali::Layer::Property::DEPTH ) );
CameraActor* cameraActor = renderTask.GetCameraActor();
bool pickingPossible = cameraActor->BuildPickingRay(
HitActor hit;
bool overlayHit = false;
bool layerConsumesHit = false;
- const Vector2& stageSize = stage.GetSize();
for( int32_t i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
{
overlayHit = false;
// Ensure layer is touchable (also checks whether ancestors are also touchable)
- if( IsActuallyHittable( *layer, screenCoordinates, stageSize, hitCheck ) )
+ 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 ) )
overlayHit,
layer->GetBehavior() == Dali::Layer::LAYER_3D,
0u,
- 0u );
+ 0u,
+ rayTest );
}
else if( IsWithinSourceActors( *sourceActor, *layer ) )
{
overlayHit,
layer->GetBehavior() == Dali::Layer::LAYER_3D,
0u,
- 0u );
+ 0u,
+ rayTest );
}
// If this layer is set to consume the hit, then do not check any layers behind it
/**
* Iterate through the RenderTaskList and perform hit testing.
*
- * @param[in] stage The stage the tests will be performed in
+ * @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] onScreen True to test on-screen, false to test off-screen
* @return True if we have a hit, false otherwise
*/
-bool HitTestRenderTaskList( Stage& stage,
+bool HitTestRenderTaskList( const Vector2& sceneSize,
LayerList& layers,
RenderTaskList& taskList,
const Vector2& screenCoordinates,
{
RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
- const Vector< RenderTaskList::Exclusive >& exclusives = taskList.GetExclusivesList();
+ const auto& exclusives = taskList.GetExclusivesList();
+ RayTest rayTest;
for( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
{
RenderTask& renderTask = *iter->Get();
- bool isOffscreenRenderTask = ( renderTask.GetTargetFrameBuffer() || renderTask.GetFrameBuffer() );
+ const bool isOffscreenRenderTask = renderTask.GetFrameBuffer();
if( (onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask) )
{
// Skip to next task
continue;
}
- if( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) )
+ 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
/**
* Iterate through the RenderTaskList and perform hit testing for both on-screen and off-screen.
*
- * @param[in] stage The stage the tests will be performed in
+ * @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] onScreen True to test on-screen, false to test off-screen
* @return True if we have a hit, false otherwise
*/
-bool HitTestForEachRenderTask( Stage& stage,
+bool HitTestForEachRenderTask( const Vector2& sceneSize,
LayerList& layers,
RenderTaskList& taskList,
const Vector2& screenCoordinates,
// 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( stage, layers, taskList, screenCoordinates, results, hitCheck, true ) ||
- HitTestRenderTaskList( stage, layers, taskList, screenCoordinates, results, hitCheck, false ) )
+ if( HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true ) ||
+ HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false ) )
{
// Found hit.
result = true;
} // unnamed namespace
-HitTestInterface::~HitTestInterface()
-{
-}
+HitTestInterface::~HitTestInterface() = default;
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
{
bool wasHit( false );
- // Hit-test the regular on-stage actors
- RenderTaskList& taskList = stage.GetRenderTaskList();
- LayerList& layerList = stage.GetLayerList();
-
+ // Hit-test the regular on-scene actors
Results hitTestResults;
HitTestFunctionWrapper hitTestFunctionWrapper( func );
- if( HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
+ if( HitTestForEachRenderTask( sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
{
results.actor = hitTestResults.actor;
results.actorCoordinates = hitTestResults.actorCoordinates;
return wasHit;
}
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
{
bool wasHit( false );
- // Hit-test the regular on-stage actors
+ // Hit-test the regular on-scene actors
if( !wasHit )
{
- RenderTaskList& taskList = stage.GetRenderTaskList();
- LayerList& layerList = stage.GetLayerList();
-
- wasHit = HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, results, hitTestInterface );
+ wasHit = HitTestForEachRenderTask( sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface );
}
return wasHit;
}
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results )
{
ActorTouchableCheck actorTouchableCheck;
- return HitTest( stage, screenCoordinates, results, actorTouchableCheck );
+ return HitTest( sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck );
}
-bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
- Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
-{
- bool wasHit( false );
- Results hitTestResults;
-
- const Vector< RenderTaskList::Exclusive >& exclusives = stage.GetRenderTaskList().GetExclusivesList();
- HitTestFunctionWrapper hitTestFunctionWrapper( func );
- if( HitTestRenderTask( exclusives, stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
- {
- results.actor = hitTestResults.actor;
- results.actorCoordinates = hitTestResults.actorCoordinates;
- wasHit = true;
- }
- return wasHit;
-}
-
-
} // namespace HitTestAlgorithm
} // namespace Internal