/*
- * Copyright (c) 2016 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/events/hit-test-algorithm-impl.h>
// INTERNAL INCLUDES
-#include <dali/integration-api/system-overlay.h>
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/math/vector2.h>
#include <dali/public-api/math/vector4.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/system-overlay-impl.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() )
{
}
- 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.
- int depth; ///< Depth index of this actor.
+ 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.
};
/**
{
}
- 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,
HitTestInterface& hitCheck,
bool& overlayHit,
bool layerIs3d,
- unsigned int clippingDepth,
- unsigned int clippingBitPlaneMask )
+ uint32_t clippingDepth,
+ uint32_t clippingBitPlaneMask,
+ const RayTest& rayTest )
{
HitActor hit;
// we increase the clipping depth if we have hit a clipping actor.
// This is used later to ensure all nested clipped children have hit
// all clipping actors also for them to be counted as hit.
- unsigned int newClippingDepth = clippingDepth;
+ uint32_t newClippingDepth = clippingDepth;
bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED;
if( clippingActor )
{
// 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 )
{
// EG. a depth of 4 (10000 binary) = a mask of 1111 binary.
// This allows us a fast way of comparing all bits are set up to this depth.
// Note: If the current Actor has clipping, that is included in the depth mask too.
- unsigned int clippingDepthMask = ( 1u << newClippingDepth ) - 1u;
+ uint32_t clippingDepthMask = ( 1u << newClippingDepth ) - 1u;
// The two masks must be equal to be a hit, as we are already assuming a hit
// (for non-clipping mode) then they must be not-equal to disqualify the hit.
hit.actor = &actor;
hit.hitPosition = hitPointLocal;
hit.distance = distance;
- hit.depth = actor.GetHierarchyDepth() * Dali::Layer::TREE_DEPTH_MULTIPLIER;
+ hit.depth = actor.GetSortingDepth() ;
if( actor.GetRendererCount() > 0 )
{
//Get renderer with maximum depth
int rendererMaxDepth(actor.GetRendererAt( 0 ).Get()->GetDepthIndex());
- for( unsigned int i(1); i < actor.GetRendererCount(); ++i )
+ for( uint32_t i(1); i < actor.GetRendererCount(); ++i )
{
int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex();
if( depth > rendererMaxDepth )
if( actor.GetChildCount() > 0 )
{
childHit.distance = std::numeric_limits<float>::max();
- childHit.depth = std::numeric_limits<int>::min();
+ childHit.depth = std::numeric_limits<int32_t>::min();
ActorContainer& children = actor.GetChildrenInternal();
// Hit test ALL children and calculate their distance.
overlayHit,
layerIs3d,
newClippingDepth,
- clippingBitPlaneMask ) );
+ clippingBitPlaneMask,
+ rayTest ) );
bool updateChildHit = false;
if( currentHit.distance >= 0.0f )
{
ClippingBox box = layer.GetClippingBox();
- if( screenCoordinates.x < box.x ||
- screenCoordinates.x > box.x + box.width ||
- screenCoordinates.y < stageSize.y - (box.y + box.height) ||
- screenCoordinates.y > stageSize.y - box.y)
+ 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 ) )
{
// Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
hittable = false;
/**
* 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 ) )
{
Viewport viewport;
renderTask.GetViewport( viewport );
- if( screenCoordinates.x < viewport.x ||
- screenCoordinates.x > viewport.x + viewport.width ||
- screenCoordinates.y < viewport.y ||
- screenCoordinates.y > viewport.y + viewport.height )
+ 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;
Dali::Layer layer( sourceActor->GetLayer() );
if( layer )
{
- const unsigned int 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( int i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
+ for( int32_t i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
{
Layer* layer( layers.GetLayer( 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<unsigned int>( i ) )
+ if( sourceActorDepth == static_cast<uint32_t>( i ) )
{
// Recursively hit test the source actor & children, without crossing into other layers.
hit = HitTestWithinLayer( *sourceActor,
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
if( hit.actor )
{
- results.renderTask = Dali::RenderTask( &renderTask );
+ results.renderTask = RenderTaskPtr( &renderTask );
results.actor = Dali::Actor( hit.actor );
results.actorCoordinates = hit.hitPosition;
/**
* 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 = GetImplementation( *iter );
- bool isOffscreenRenderTask = ( iter->GetTargetFrameBuffer() || iter->GetFrameBuffer() );
+ RenderTask& renderTask = *iter->Get();
+ 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
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
+HitTestInterface::~HitTestInterface()
{
- bool wasHit( false );
- // Hit-test the regular on-stage actors
- RenderTaskList& taskList = stage.GetRenderTaskList();
- LayerList& layerList = stage.GetLayerList();
+}
+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-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 system-overlay actors first
- SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
-
- if( systemOverlay )
- {
- RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
- LayerList& overlayLayerList = systemOverlay->GetLayerList();
-
- wasHit = HitTestForEachRenderTask( stage, overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
- }
-
- // 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 );
-}
-
-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;
+ return HitTest( sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck );
}
-
} // namespace HitTestAlgorithm
} // namespace Internal