Merge "Added ASTC Native file format loader" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/system-overlay.h>
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/math/vector4.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/event/actors/actor-impl.h>
28 #include <dali/internal/event/actors/camera-actor-impl.h>
29 #include <dali/internal/event/actors/image-actor-impl.h>
30 #include <dali/internal/event/actors/layer-impl.h>
31 #include <dali/internal/event/actors/layer-list.h>
32 #include <dali/internal/event/common/system-overlay-impl.h>
33 #include <dali/internal/event/common/stage-impl.h>
34 #include <dali/internal/event/common/projection.h>
35 #include <dali/internal/event/images/frame-buffer-image-impl.h>
36 #include <dali/internal/event/render-tasks/render-task-impl.h>
37 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
38
39 namespace Dali
40 {
41
42 namespace Internal
43 {
44
45 namespace HitTestAlgorithm
46 {
47
48 namespace
49 {
50
51 struct HitActor
52 {
53   HitActor()
54   : actor( NULL ),
55     x( 0 ),
56     y( 0 ),
57     distance( std::numeric_limits<float>::max() ),
58     depth( std::numeric_limits<int>::min() )
59   {
60   }
61
62   Actor *actor;                         ///< the actor hit. (if actor hit, then initialised)
63   float x;                              ///< x position of hit (only valid if actor valid)
64   float y;                              ///< y position of hit (only valid if actor valid)
65   float distance;                       ///< distance from ray origin to hit actor
66   int depth;                            ///< depth index of this actor
67
68 };
69
70 /**
71  * Creates an Actor handle so that a HitTestFunction provided via the public API can be called.
72  */
73 struct HitTestFunctionWrapper : public HitTestInterface
74 {
75   /**
76    * Constructor
77    *
78    * @param[in] func HitTestFunction to call with an Actor handle.
79    */
80   HitTestFunctionWrapper( Dali::HitTestAlgorithm::HitTestFunction func )
81   : mFunc( func )
82   {
83   }
84
85   virtual bool IsActorHittable( Actor* actor )
86   {
87     return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::CHECK_ACTOR );
88   }
89
90   virtual bool DescendActorHierarchy( Actor* actor )
91   {
92     return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE );
93   }
94
95   virtual bool DoesLayerConsumeHit( Layer* layer )
96   {
97     // Layer::IsTouchConsumed() focuses on touch only. Here we are a wrapper for the public-api
98     // where the caller may want to check for something completely different.
99     // TODO: Should provide a means to let caller decide. For now do not allow layers to consume
100     return false;
101   }
102
103   Dali::HitTestAlgorithm::HitTestFunction mFunc;
104 };
105
106 /**
107  * Used in the hit-test algorithm to check whether the actor is touchable.
108  * It is used by the touch event processor.
109  */
110 struct ActorTouchableCheck : public HitTestInterface
111 {
112   virtual bool IsActorHittable( Actor* actor )
113   {
114     return actor->GetTouchRequired() && // Does the Application or derived actor type require a touch event?
115            actor->IsHittable();         // Is actor sensitive, visible and on the scene?
116   }
117
118   virtual bool DescendActorHierarchy( Actor* actor )
119   {
120     return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
121            actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
122   }
123
124   virtual bool DoesLayerConsumeHit( Layer* layer )
125   {
126     return layer->IsTouchConsumed();
127   }
128 };
129
130 /**
131  * Check to see if the actor we're about to hit test is exclusively owned by another rendertask?
132  */
133 bool IsActorExclusiveToAnotherRenderTask( const Actor& actor,
134                                           const RenderTask& renderTask,
135                                           const Vector< RenderTaskList::Exclusive >& exclusives )
136
137 {
138   if ( exclusives.Size() )
139   {
140     for ( Vector< RenderTaskList::Exclusive >::Iterator exclusiveIt = exclusives.Begin(); exclusives.End() != exclusiveIt; ++exclusiveIt )
141     {
142       if ( exclusiveIt->renderTaskPtr != &renderTask )
143       {
144         if ( exclusiveIt->actorPtr == &actor )
145         {
146           return true;
147         }
148       }
149     }
150   }
151   return false;
152 }
153
154 /**
155  * Recursively hit test all the actors, without crossing into other layers.
156  * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
157  * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
158  * of touch vector). The closest Hit-Tested Actor is that which is returned.
159  * Exceptions to this rule are:
160  * - When comparing against renderable parents, if Actor is the same distance
161  * or closer than it's renderable parent, then it takes priority.
162  */
163 HitActor HitTestWithinLayer( Actor& actor,
164                              const RenderTask& renderTask,
165                              const Vector< RenderTaskList::Exclusive >& exclusives,
166                              const Vector4& rayOrigin,
167                              const Vector4& rayDir,
168                              float& nearClippingPlane,
169                              float& farClippingPlane,
170                              HitTestInterface& hitCheck,
171                              bool& stencilOnLayer,
172                              bool& stencilHit,
173                              bool& overlayHit,
174                              bool parentIsStencil,
175                              bool layerIs3d )
176 {
177   HitActor hit;
178
179   if ( IsActorExclusiveToAnotherRenderTask( actor, renderTask, exclusives ) )
180   {
181     return hit;
182   }
183
184   // Children should inherit the stencil draw mode
185   bool isStencil = parentIsStencil;
186
187   if ( actor.GetDrawMode() == DrawMode::STENCIL && actor.IsVisible() )
188   {
189     isStencil = true;
190     stencilOnLayer = true;
191   }
192
193   // If we are a stencil or hittable...
194   if ( isStencil || hitCheck.IsActorHittable( &actor ) )
195   {
196     Vector3 size( actor.GetCurrentSize() );
197
198     if ( size.x > 0.0f && size.y > 0.0f &&          // Ensure the actor has a valid size.
199          actor.RaySphereTest( rayOrigin, rayDir ) ) // Perform quicker ray sphere test to see if our ray is close to the actor.
200     {
201       Vector4 hitPointLocal;
202       float distance;
203
204       // Finally, perform a more accurate ray test to see if our ray actually hits the actor.
205       if( actor.RayActorTest( rayOrigin, rayDir, hitPointLocal, distance ) )
206       {
207         if( distance >= nearClippingPlane && distance <= farClippingPlane )
208         {
209           // If the hit has happened on a stencil then register, but don't record as hit result
210           if ( isStencil )
211           {
212             stencilHit = true;
213           }
214           else
215           {
216             if( overlayHit && !actor.IsOverlay() )
217             {
218               //If we have already hit an overlay and current actor is not an overlay
219               //ignore current actor
220             }
221             else
222             {
223               if( actor.IsOverlay() )
224               {
225                 overlayHit = true;
226               }
227
228               hit.actor = &actor;
229               hit.x = hitPointLocal.x;
230               hit.y = hitPointLocal.y;
231               hit.distance = distance;
232               hit.depth = actor.GetHierarchyDepth() * Dali::Layer::TREE_DEPTH_MULTIPLIER;
233
234               if ( actor.GetRendererCount() > 0 )
235               {
236                 //Get renderer with maximum depth
237                 int rendererMaxDepth(actor.GetRendererAt( 0 ).Get()->GetDepthIndex());
238                 for( unsigned int i(1); i<actor.GetRendererCount(); ++i)
239                 {
240                   int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex();
241                   if( depth > rendererMaxDepth )
242                   {
243                     rendererMaxDepth = depth;
244                   }
245                 }
246                 hit.depth += rendererMaxDepth;
247               }
248             }
249           }
250         }
251       }
252     }
253   }
254
255   // If we are a stencil (or a child of a stencil) and we have already ascertained that the stencil has been hit then there is no need to hit-test the children of this stencil-actor
256   if ( isStencil && stencilHit  )
257   {
258     return hit;
259   }
260
261   // Find a child hit, until we run out of actors in the current layer.
262   HitActor childHit;
263   if( actor.GetChildCount() > 0 )
264   {
265     childHit.distance = std::numeric_limits<float>::max();
266     childHit.depth = std::numeric_limits<int>::min();
267     ActorContainer& children = actor.GetChildrenInternal();
268
269     // Hit test ALL children and calculate their distance.
270     bool parentIsRenderable = actor.IsRenderable();
271
272     for( ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter )
273     {
274       // Descend tree only if...
275       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
276            ( isStencil || hitCheck.DescendActorHierarchy( ( *iter ).Get() ) ) ) // We are a stencil OR we can descend into child hierarchy
277       {
278         HitActor currentHit( HitTestWithinLayer(  (*iter->Get()),
279                                                   renderTask,
280                                                   exclusives,
281                                                   rayOrigin,
282                                                   rayDir,
283                                                   nearClippingPlane,
284                                                   farClippingPlane,
285                                                   hitCheck,
286                                                   stencilOnLayer,
287                                                   stencilHit,
288                                                   overlayHit,
289                                                   isStencil,
290                                                   layerIs3d) );
291
292         bool updateChildHit = false;
293         if ( currentHit.distance >= 0.0f )
294         {
295           if( layerIs3d )
296           {
297             updateChildHit = ( ( currentHit.depth > childHit.depth ) ||
298                 ( ( currentHit.depth == childHit.depth ) && ( currentHit.distance < childHit.distance ) ) );
299           }
300           else
301           {
302             updateChildHit = currentHit.depth >= childHit.depth;
303           }
304         }
305
306         if ( updateChildHit )
307         {
308           if( !parentIsRenderable || currentHit.depth > hit.depth ||
309             ( layerIs3d && ( currentHit.depth == hit.depth && currentHit.distance < hit.distance )) )
310             {
311               childHit = currentHit;
312             }
313         }
314       }
315     }
316   }
317   return ( childHit.actor ) ? childHit : hit;
318 }
319
320 /**
321  * Return true if actor is sourceActor or a descendent of sourceActor
322  */
323 bool IsWithinSourceActors( const Actor& sourceActor, const Actor& actor )
324 {
325   if ( &sourceActor == &actor )
326   {
327     return true;
328   }
329   else
330   {
331     Actor* parent = actor.GetParent();
332     if ( parent )
333     {
334       return IsWithinSourceActors( sourceActor, *parent );
335     }
336   }
337
338   // Not within source actors
339   return false;
340 }
341
342 /**
343  * Returns true if the layer and all of the layer's parents are visible and sensitive.
344  */
345 inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck )
346 {
347   bool hittable( true );
348
349   if(layer.IsClipping())
350   {
351     ClippingBox box = layer.GetClippingBox();
352
353     if( screenCoordinates.x < box.x ||
354         screenCoordinates.x > box.x + box.width ||
355         screenCoordinates.y < stageSize.y - (box.y + box.height) ||
356         screenCoordinates.y > stageSize.y - box.y)
357     {
358       // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
359       hittable = false;
360     }
361   }
362
363   if(hittable)
364   {
365     Actor* actor( &layer );
366
367     // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
368     while ( actor && hittable )
369     {
370       if ( ! hitCheck.DescendActorHierarchy( actor ) )
371       {
372         hittable = false;
373         break;
374       }
375       actor = actor->GetParent();
376     }
377   }
378
379   return hittable;
380 }
381
382 /**
383  * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task.
384  */
385 void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane )
386 {
387   CameraActor* cameraActor = renderTask.GetCameraActor();
388   nearClippingPlane = cameraActor->GetNearClippingPlane();
389   farClippingPlane = cameraActor->GetFarClippingPlane();
390 }
391
392 /**
393  * Hit test a RenderTask
394  */
395 bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
396                         Stage& stage,
397                         LayerList& layers,
398                         RenderTask& renderTask,
399                         Vector2 screenCoordinates,
400                         Results& results,
401                         HitTestInterface& hitCheck )
402 {
403   if ( renderTask.IsHittable( screenCoordinates ) )
404   {
405     Viewport viewport;
406     renderTask.GetViewport( viewport );
407     if( screenCoordinates.x < viewport.x ||
408         screenCoordinates.x > viewport.x + viewport.width ||
409         screenCoordinates.y < viewport.y ||
410         screenCoordinates.y > viewport.y + viewport.height )
411     {
412       // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
413       return false;
414     }
415
416     float nearClippingPlane, farClippingPlane;
417     GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
418
419     // Determine the layer depth of the source actor
420     Actor* sourceActor( renderTask.GetSourceActor() );
421     if ( sourceActor )
422     {
423       Dali::Layer layer( sourceActor->GetLayer() );
424       if ( layer )
425       {
426         const unsigned int sourceActorDepth( layer.GetDepth() );
427
428         CameraActor* cameraActor = renderTask.GetCameraActor();
429         bool pickingPossible = cameraActor->BuildPickingRay(
430             screenCoordinates,
431             viewport,
432             results.rayOrigin,
433             results.rayDirection );
434         if( !pickingPossible )
435         {
436           return false;
437         }
438
439         // Hit test starting with the top layer, working towards the bottom layer.
440         HitActor hit;
441         bool stencilOnLayer = false;
442         bool stencilHit = false;
443         bool overlayHit = false;
444         bool layerConsumesHit = false;
445
446         const Vector2& stageSize = stage.GetSize();
447
448         for (int i=layers.GetLayerCount()-1; i>=0 && !(hit.actor); --i)
449         {
450           Layer* layer( layers.GetLayer(i) );
451           HitActor previousHit = hit;
452           stencilOnLayer = false;
453           stencilHit = false;
454           overlayHit = false;
455
456           // Ensure layer is touchable (also checks whether ancestors are also touchable)
457           if ( IsActuallyHittable ( *layer, screenCoordinates, stageSize, hitCheck ) )
458           {
459             // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
460             if ( sourceActorDepth == static_cast<unsigned int>(i) )
461             {
462               // Recursively hit test the source actor & children, without crossing into other layers.
463               hit = HitTestWithinLayer( *sourceActor,
464                                         renderTask,
465                                         exclusives,
466                                         results.rayOrigin,
467                                         results.rayDirection,
468                                         nearClippingPlane,
469                                         farClippingPlane,
470                                         hitCheck,
471                                         stencilOnLayer,
472                                         stencilHit,
473                                         overlayHit,
474                                         false,
475                                         layer->GetBehavior() == Dali::Layer::LAYER_3D);
476             }
477             else if ( IsWithinSourceActors( *sourceActor, *layer ) )
478             {
479               // Recursively hit test all the actors, without crossing into other layers.
480               hit = HitTestWithinLayer( *layer,
481                                         renderTask,
482                                         exclusives,
483                                         results.rayOrigin,
484                                         results.rayDirection,
485                                         nearClippingPlane,
486                                         farClippingPlane,
487                                         hitCheck,
488                                         stencilOnLayer,
489                                         stencilHit,
490                                         overlayHit,
491                                         false,
492                                         layer->GetBehavior() == Dali::Layer::LAYER_3D);
493             }
494
495             // If a stencil on this layer hasn't been hit, then discard hit results for this layer if our current hit actor is renderable
496             if ( stencilOnLayer && !stencilHit &&
497                  hit.actor && hit.actor->IsRenderable() )
498             {
499               hit = previousHit;
500             }
501
502             // If this layer is set to consume the hit, then do not check any layers behind it
503             if ( hitCheck.DoesLayerConsumeHit( layer ) )
504             {
505               layerConsumesHit = true;
506               break;
507             }
508           }
509         }
510         if ( hit.actor )
511         {
512           results.renderTask = Dali::RenderTask(&renderTask);
513           results.actor = Dali::Actor(hit.actor);
514           results.actorCoordinates.x = hit.x;
515           results.actorCoordinates.y = hit.y;
516           return true; // Success
517         }
518         else if ( layerConsumesHit )
519         {
520           return true; // Also success if layer is consuming the hit
521         }
522       }
523     }
524   }
525   return false;
526 }
527
528 /**
529  * Iterate through RenderTaskList and perform hit test.
530  *
531  * @return true if we have a hit, false otherwise
532  */
533 bool HitTestForEachRenderTask( Stage& stage,
534                                LayerList& layers,
535                                RenderTaskList& taskList,
536                                const Vector2& screenCoordinates,
537                                Results& results,
538                                HitTestInterface& hitCheck )
539 {
540   RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
541   RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
542
543   const Vector< RenderTaskList::Exclusive >& exclusives = taskList.GetExclusivesList();
544
545   // Check onscreen tasks before offscreen ones, hit test order should be reverse of draw order (see ProcessRenderTasks() where offscreen tasks are drawn first).
546
547   // on screen
548   for ( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
549   {
550     RenderTask& renderTask = GetImplementation( *iter );
551     Dali::FrameBufferImage frameBufferImage = renderTask.GetTargetFrameBuffer();
552
553     // Note that if frameBufferImage is NULL we are using the default (on screen) render target
554     if(frameBufferImage)
555     {
556       ResourceId id = GetImplementation(frameBufferImage).GetResourceId();
557
558       // on screen only
559       if(0 != id)
560       {
561         // Skip to next task
562         continue;
563       }
564     }
565
566     if ( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) )
567     {
568       // Return true when an actor is hit (or layer in our render-task consumes the hit)
569       return true; // don't bother checking off screen tasks
570     }
571   }
572
573   // off screen
574   for ( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
575   {
576     RenderTask& renderTask = GetImplementation( *iter );
577     Dali::FrameBufferImage frameBufferImage = renderTask.GetTargetFrameBuffer();
578
579     // Note that if frameBufferImage is NULL we are using the default (on screen) render target
580     if(frameBufferImage)
581     {
582       ResourceId id = GetImplementation(frameBufferImage).GetResourceId();
583
584       // off screen only
585       if(0 == id)
586       {
587         // Skip to next task
588         continue;
589       }
590
591       if ( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) )
592       {
593         // Return true when an actor is hit (or a layer in our render-task consumes the hit)
594         return true;
595       }
596     }
597   }
598   return false;
599 }
600
601 } // unnamed namespace
602
603 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
604 {
605   bool wasHit( false );
606   // Hit-test the regular on-stage actors
607   RenderTaskList& taskList = stage.GetRenderTaskList();
608   LayerList& layerList = stage.GetLayerList();
609
610   Results hitTestResults;
611   HitTestFunctionWrapper hitTestFunctionWrapper( func );
612   if (  HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
613   {
614     results.actor = hitTestResults.actor;
615     results.actorCoordinates = hitTestResults.actorCoordinates;
616     wasHit = true;
617   }
618   return wasHit;
619 }
620
621 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
622 {
623   bool wasHit( false );
624
625   // Hit-test the system-overlay actors first
626   SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
627
628   if ( systemOverlay )
629   {
630     RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
631     LayerList& overlayLayerList = systemOverlay->GetLayerList();
632
633     wasHit = HitTestForEachRenderTask( stage, overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
634   }
635
636   // Hit-test the regular on-stage actors
637   if ( !wasHit )
638   {
639     RenderTaskList& taskList = stage.GetRenderTaskList();
640     LayerList& layerList = stage.GetLayerList();
641
642     wasHit = HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, results, hitTestInterface );
643   }
644   return wasHit;
645 }
646
647 bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
648 {
649   ActorTouchableCheck actorTouchableCheck;
650   return HitTest( stage, screenCoordinates, results, actorTouchableCheck );
651 }
652
653 bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
654               Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
655 {
656   bool wasHit( false );
657   Results hitTestResults;
658
659   const Vector< RenderTaskList::Exclusive >& exclusives = stage.GetRenderTaskList().GetExclusivesList();
660   HitTestFunctionWrapper hitTestFunctionWrapper( func );
661   if ( HitTestRenderTask( exclusives, stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
662   {
663     results.actor = hitTestResults.actor;
664     results.actorCoordinates = hitTestResults.actorCoordinates;
665     wasHit = true;
666   }
667   return wasHit;
668 }
669
670 } // namespace HitTestAlgorithm
671
672 } // namespace Internal
673
674 } // namespace Dali