X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fevent%2Fevents%2Fhit-test-algorithm-impl.cpp;h=67b5ed65c5ed267d57950e296cd736cc77038da0;hb=9d825be196fa6565a6dabc8647fe4867f5e9a89a;hp=c5d3753f96047b13d91203e8668eba8338abfd99;hpb=a3157a0ec440d4771bbac4b3aefbc77d8007af1d;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/event/events/hit-test-algorithm-impl.cpp b/dali/internal/event/events/hit-test-algorithm-impl.cpp index c5d3753..67b5ed6 100644 --- a/dali/internal/event/events/hit-test-algorithm-impl.cpp +++ b/dali/internal/event/events/hit-test-algorithm-impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -54,16 +55,15 @@ struct HitActor x( 0 ), y( 0 ), distance( std::numeric_limits::max() ), - overlay( false ) + depth( std::numeric_limits::min() ) { - } Actor *actor; ///< the actor hit. (if actor hit, then initialised) float x; ///< x position of hit (only valid if actor valid) float y; ///< y position of hit (only valid if actor valid) float distance; ///< distance from ray origin to hit actor - bool overlay; ///< true if the hit actor is an overlay + int depth; ///< depth index of this actor }; @@ -128,20 +128,43 @@ struct ActorTouchableCheck : public HitTestInterface }; /** + * Check to see if the actor we're about to hit test is exclusively owned by another rendertask? + */ +bool IsActorExclusiveToAnotherRenderTask( const Actor& actor, + const RenderTask& renderTask, + const Vector< RenderTaskList::Exclusive >& exclusives ) + +{ + if ( exclusives.Size() ) + { + for ( Vector< RenderTaskList::Exclusive >::Iterator exclusiveIt = exclusives.Begin(); exclusives.End() != exclusiveIt; ++exclusiveIt ) + { + if ( exclusiveIt->renderTaskPtr != &renderTask ) + { + if ( exclusiveIt->actorPtr == &actor ) + { + return true; + } + } + } + } + return false; +} + +/** * 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: - * - If the Actor is an overlay then it is considered closer than all previous - * overlays encountered in the hit test traversal. * - 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 Vector< RenderTaskList::Exclusive >& exclusives, const Vector4& rayOrigin, const Vector4& rayDir, - bool worldOverlay, float& nearClippingPlane, float& farClippingPlane, HitTestInterface& hitCheck, @@ -149,10 +172,13 @@ HitActor HitTestWithinLayer( Actor& actor, bool& stencilHit, bool parentIsStencil ) { - worldOverlay |= actor.IsOverlay(); - HitActor hit; + if ( IsActorExclusiveToAnotherRenderTask( actor, renderTask, exclusives ) ) + { + return hit; + } + // Children should inherit the stencil draw mode bool isStencil = parentIsStencil; @@ -189,7 +215,23 @@ HitActor HitTestWithinLayer( Actor& actor, hit.x = hitPointLocal.x; hit.y = hitPointLocal.y; hit.distance = distance; - hit.overlay = worldOverlay; + + // Is this actor an Image Actor or contains a renderer? + if ( ImageActor* imageActor = dynamic_cast< ImageActor* >( &actor ) ) + { + hit.depth = imageActor->GetDepthIndex(); + } + else + { + if ( actor.GetRendererCount() ) + { + hit.depth = actor.GetRendererAt( 0 ).GetDepthIndex(); + } + else + { + hit.depth = 0; + } + } } } } @@ -207,6 +249,7 @@ HitActor HitTestWithinLayer( Actor& actor, if( actor.GetChildCount() > 0 ) { childHit.distance = std::numeric_limits::max(); + childHit.depth = std::numeric_limits::min(); ActorContainer& children = actor.GetChildrenInternal(); // Hit test ALL children and calculate their distance. @@ -218,25 +261,45 @@ HitActor HitTestWithinLayer( Actor& actor, if ( !iter->IsLayer() && // Child is NOT a layer, hit testing current layer only or Child is not a layer and we've inherited the stencil draw mode ( isStencil || hitCheck.DescendActorHierarchy( &GetImplementation( *iter ) ) ) ) // We are a stencil OR we can descend into child hierarchy { - HitActor currentHit( HitTestWithinLayer( GetImplementation(*iter), rayOrigin, rayDir, worldOverlay, nearClippingPlane, farClippingPlane, hitCheck, stencilOnLayer, stencilHit, isStencil ) ); - - // If Current child is an overlay, then it takes priority. - // If it is not an overlay, and the previously hit sibling is also not an overlay, then closest takes priority. - // (last overlay sibling has priority as is rendered on top) - if ( currentHit.distance >= 0.f && (currentHit.overlay || (!childHit.overlay && currentHit.distance < childHit.distance) ) ) + HitActor currentHit( HitTestWithinLayer( GetImplementation(*iter), + renderTask, + exclusives, + rayOrigin, + rayDir, + nearClippingPlane, + farClippingPlane, + hitCheck, + stencilOnLayer, + stencilHit, + isStencil ) ); + + bool updateChildHit = false; + // If our ray casting hit, then check then if the hit actor's depth is greater that the favorite, it will be preferred + if ( currentHit.distance >= 0.0f ) { - if ( !parentIsRenderable ) + if ( currentHit.depth > childHit.depth ) { - // If our parent is not renderable, then child should be hit regardless of distance. - childHit = currentHit; + updateChildHit = true; } - else if ( currentHit.overlay || (!hit.overlay && currentHit.distance <= hit.distance) ) + + // If the hit actor's depth is equal to current favorite, then we check the distance and prefer the closer + else if ( currentHit.depth == childHit.depth ) { - // If our parent is renderable, then child should only be hit if it is an overlay, or if it is closer than a non-overlay. - // (child overlay has priority as is rendered on top of it's parent) - childHit = currentHit; + if ( currentHit.distance < childHit.distance ) + { + updateChildHit = true; + } } } + + if ( updateChildHit ) + { + if( !parentIsRenderable || currentHit.depth > hit.depth || + ( currentHit.depth == hit.depth && currentHit.distance < hit.distance ) ) + { + childHit = currentHit; + } + } } } } @@ -318,7 +381,8 @@ void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, f /** * Hit test a RenderTask */ -bool HitTestRenderTask( Stage& stage, +bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives, + Stage& stage, LayerList& layers, RenderTask& renderTask, Vector2 screenCoordinates, @@ -372,7 +436,6 @@ bool HitTestRenderTask( Stage& stage, for (int i=layers.GetLayerCount()-1; i>=0 && !(hit.actor); --i) { Layer* layer( layers.GetLayer(i) ); - HitActor previousHit = hit; stencilOnLayer = false; stencilHit = false; @@ -384,12 +447,32 @@ bool HitTestRenderTask( Stage& stage, if ( sourceActorDepth == static_cast(i) ) { // Recursively hit test the source actor & children, without crossing into other layers. - hit = HitTestWithinLayer( *sourceActor, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, hitCheck, stencilOnLayer, stencilHit, false ); + hit = HitTestWithinLayer( *sourceActor, + renderTask, + exclusives, + results.rayOrigin, + results.rayDirection, + nearClippingPlane, + farClippingPlane, + hitCheck, + stencilOnLayer, + stencilHit, + false ); } else if ( IsWithinSourceActors( *sourceActor, *layer ) ) { // Recursively hit test all the actors, without crossing into other layers. - hit = HitTestWithinLayer( *layer, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, hitCheck, stencilOnLayer, stencilHit, false ); + hit = HitTestWithinLayer( *layer, + renderTask, + exclusives, + results.rayOrigin, + results.rayDirection, + nearClippingPlane, + farClippingPlane, + hitCheck, + stencilOnLayer, + stencilHit, + false ); } // If a stencil on this layer hasn't been hit, then discard hit results for this layer if our current hit actor is renderable @@ -440,6 +523,8 @@ bool HitTestForEachRenderTask( Stage& stage, RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks(); RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend(); + const Vector< RenderTaskList::Exclusive >& exclusives = taskList.GetExclusivesList(); + // Check onscreen tasks before offscreen ones, hit test order should be reverse of draw order (see ProcessRenderTasks() where offscreen tasks are drawn first). // on screen @@ -461,7 +546,7 @@ bool HitTestForEachRenderTask( Stage& stage, } } - if ( HitTestRenderTask( stage, layers, renderTask, screenCoordinates, results, hitCheck ) ) + if ( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) ) { // 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 @@ -486,7 +571,7 @@ bool HitTestForEachRenderTask( Stage& stage, continue; } - if ( HitTestRenderTask( stage, layers, renderTask, screenCoordinates, results, hitCheck ) ) + if ( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) ) { // Return true when an actor is hit (or a layer in our render-task consumes the hit) return true; @@ -554,8 +639,9 @@ bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordin bool wasHit( false ); Results hitTestResults; + const Vector< RenderTaskList::Exclusive >& exclusives = Stage::GetCurrent()->GetRenderTaskList().GetExclusivesList(); HitTestFunctionWrapper hitTestFunctionWrapper( func ); - if ( HitTestRenderTask( stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) ) + if ( HitTestRenderTask( exclusives, stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) ) { results.actor = hitTestResults.actor; results.actorCoordinates = hitTestResults.actorCoordinates;