Merge "Removed some junk from Makefile.am" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index c5d3753..604f71e 100644 (file)
 
 // 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/integration-api/debug.h>
 #include <dali/internal/event/actors/actor-impl.h>
 #include <dali/internal/event/actors/camera-actor-impl.h>
+#include <dali/internal/event/actors/image-actor-impl.h>
 #include <dali/internal/event/actors/layer-impl.h>
 #include <dali/internal/event/actors/layer-list.h>
-#include <dali/internal/event/actors/renderable-actor-impl.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>
@@ -54,16 +55,15 @@ struct HitActor
     x( 0 ),
     y( 0 ),
     distance( std::numeric_limits<float>::max() ),
-    overlay( false )
+    depth( std::numeric_limits<int>::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,31 +128,58 @@ 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,
                              bool& stencilOnLayer,
                              bool& stencilHit,
-                             bool parentIsStencil )
+                             bool parentIsStencil,
+                             bool layerIs3d )
 {
-  worldOverlay |= actor.IsOverlay();
-
   HitActor hit;
 
+  if ( IsActorExclusiveToAnotherRenderTask( actor, renderTask, exclusives ) )
+  {
+    return hit;
+  }
+
   // Children should inherit the stencil draw mode
   bool isStencil = parentIsStencil;
 
@@ -189,7 +216,22 @@ HitActor HitTestWithinLayer( Actor& actor,
             hit.x = hitPointLocal.x;
             hit.y = hitPointLocal.y;
             hit.distance = distance;
-            hit.overlay = worldOverlay;
+            hit.depth = actor.GetHierarchyDepth() * Dali::Layer::TREE_DEPTH_MULTIPLIER;
+
+            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)
+              {
+                int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex();
+                if( depth > rendererMaxDepth )
+                {
+                  rendererMaxDepth = depth;
+                }
+              }
+              hit.depth += rendererMaxDepth;
+            }
           }
         }
       }
@@ -207,6 +249,7 @@ HitActor HitTestWithinLayer( Actor& actor,
   if( actor.GetChildCount() > 0 )
   {
     childHit.distance = std::numeric_limits<float>::max();
+    childHit.depth = std::numeric_limits<int>::min();
     ActorContainer& children = actor.GetChildrenInternal();
 
     // Hit test ALL children and calculate their distance.
@@ -215,28 +258,44 @@ HitActor HitTestWithinLayer( Actor& actor,
     for( ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter )
     {
       // Descend tree only if...
-      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
+      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( ( *iter ).Get() ) ) ) // 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(  (*iter->Get()),
+                                                  renderTask,
+                                                  exclusives,
+                                                  rayOrigin,
+                                                  rayDir,
+                                                  nearClippingPlane,
+                                                  farClippingPlane,
+                                                  hitCheck,
+                                                  stencilOnLayer,
+                                                  stencilHit,
+                                                  isStencil,
+                                                  layerIs3d) );
+
+        bool updateChildHit = false;
+        if ( currentHit.distance >= 0.0f )
         {
-          if ( !parentIsRenderable )
+          if( layerIs3d )
           {
-            // If our parent is not renderable, then child should be hit regardless of distance.
-            childHit = currentHit;
+            updateChildHit = ( ( currentHit.depth > childHit.depth ) ||
+                ( ( currentHit.depth == childHit.depth ) && ( currentHit.distance < childHit.distance ) ) );
           }
-          else if ( currentHit.overlay || (!hit.overlay && currentHit.distance <= hit.distance) )
+          else
           {
-            // 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;
+            updateChildHit = currentHit.depth >= childHit.depth;
           }
         }
+
+        if ( updateChildHit )
+        {
+          if( !parentIsRenderable || currentHit.depth > hit.depth ||
+            ( layerIs3d && ( currentHit.depth == hit.depth && currentHit.distance < hit.distance )) )
+            {
+              childHit = currentHit;
+            }
+        }
       }
     }
   }
@@ -318,7 +377,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 +432,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 +443,34 @@ bool HitTestRenderTask( Stage& stage,
             if ( sourceActorDepth == static_cast<unsigned int>(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,
+                                        layer->GetBehavior() == Dali::Layer::LAYER_3D);
             }
             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,
+                                        layer->GetBehavior() == Dali::Layer::LAYER_3D);
             }
 
             // 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 +521,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 +544,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 +569,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 +637,9 @@ bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordin
   bool wasHit( false );
   Results hitTestResults;
 
+  const Vector< RenderTaskList::Exclusive >& exclusives = stage.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;