Merge "Print line numbers with shader source."
[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 Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/integration-api/system-overlay.h>
22 #include <dali/public-api/math/vector2.h>
23 #include <dali/public-api/math/vector4.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/actors/actor-impl.h>
26 #include <dali/internal/event/actors/camera-actor-impl.h>
27 #include <dali/internal/event/actors/layer-impl.h>
28 #include <dali/internal/event/actors/layer-list.h>
29 #include <dali/internal/event/actors/renderable-actor-impl.h>
30 #include <dali/internal/event/common/system-overlay-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/projection.h>
33 #include <dali/internal/event/render-tasks/render-task-impl.h>
34 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace HitTestAlgorithm
43 {
44
45 namespace
46 {
47
48 struct HitActor
49 {
50   HitActor()
51   : x( 0 ),
52     y( 0 ),
53     distance( std::numeric_limits<float>::max() ),
54     overlay( false )
55   {
56
57   }
58
59   Dali::Actor actor;                    ///< the actor hit. (if actor hit, then initialised)
60   float x;                              ///< x position of hit (only valid if actor valid)
61   float y;                              ///< y position of hit (only valid if actor valid)
62   float distance;                       ///< distance from ray origin to hit actor
63   bool overlay;                         ///< true if the hit actor is an overlay
64
65 };
66
67 /**
68  * The function to be used in the hit-test algorithm to check whether the actor is touchable.
69  * It is used by the touch event and gesture processor.
70  */
71 bool IsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
72 {
73   bool hittable = false;
74
75   switch (type)
76   {
77     case Dali::HitTestAlgorithm::CHECK_ACTOR:
78     {
79       if( GetImplementation(actor).GetTouchRequired() && // Does the Application or derived actor type require a touch event?
80           GetImplementation(actor).IsHittable() ) // Is actor sensitive, visible and on the scene?
81       {
82         hittable = true;
83       }
84       break;
85     }
86     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
87     {
88       if( actor.IsVisible() &&     // Actor is visible, if not visible then none of its children are visible.
89           actor.IsSensitive() )    // Actor is sensitive, if insensitive none of its children should be hittable either.
90       {
91         hittable = true;
92       }
93       break;
94     }
95     default:
96     {
97       break;
98     }
99   }
100
101   return hittable;
102 }
103
104 /**
105  * Recursively hit test all the actors, without crossing into other layers.
106  * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
107  * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
108  * of touch vector). The closest Hit-Tested Actor is that which is returned.
109  * Exceptions to this rule are:
110  * - If the Actor is an overlay then it is considered closer than all previous
111  * overlays encountered in the hit test traversal.
112  * - When comparing against renderable parents, if Actor is the same distance
113  * or closer than it's renderable parent, then it takes priority.
114  */
115 HitActor HitTestWithinLayer( Actor& actor,
116                              const Vector4& rayOrigin,
117                              const Vector4& rayDir,
118                              bool worldOverlay,
119                              float& nearClippingPlane,
120                              float& farClippingPlane,
121                              Dali::HitTestAlgorithm::HitTestFunction func,
122                              bool& stencilOnLayer,
123                              bool& stencilHit,
124                              bool parentIsStencil )
125 {
126   worldOverlay |= actor.IsOverlay();
127
128   HitActor hit;
129
130   // Children should inherit the stencil draw mode
131   bool isStencil = parentIsStencil;
132
133   if ( actor.GetDrawMode() == DrawMode::STENCIL && actor.IsVisible() )
134   {
135     isStencil = true;
136     stencilOnLayer = true;
137   }
138
139   // If we are a stencil or hittable...
140   if ( isStencil || func(Dali::Actor(&actor), Dali::HitTestAlgorithm::CHECK_ACTOR) ) // Is actor hittable
141   {
142     Vector3 size( actor.GetCurrentSize() );
143
144     if ( size.x > 0.0f && size.y > 0.0f &&              // Ensure the actor has a valid size.
145          actor.RaySphereTest( rayOrigin, rayDir ) ) // Perform quicker ray sphere test to see if our ray is close to the actor.
146     {
147       Vector4 hitPointLocal;
148       float distance;
149
150       // Finally, perform a more accurate ray test to see if our ray actually hits the actor.
151       if( actor.RayActorTest( rayOrigin, rayDir, hitPointLocal, distance ) )
152       {
153         if( distance >= nearClippingPlane && distance <= farClippingPlane )
154         {
155           // If the hit has happened on a stencil then register, but don't record as hit result
156           if ( isStencil )
157           {
158             stencilHit = true;
159           }
160           else
161           {
162             hit.actor = Dali::Actor(&actor);
163             hit.x = hitPointLocal.x;
164             hit.y = hitPointLocal.y;
165             hit.distance = distance;
166             hit.overlay = worldOverlay;
167           }
168         }
169       }
170     }
171   }
172
173   // If there is a stencil on this layer and we've also registered a hit, then don't both searching any children
174   if ( stencilHit && hit.actor )
175   {
176     return hit;
177   }
178
179   // Find a child hit, until we run out of actors in the current layer.
180   HitActor childHit;
181   if( actor.GetChildCount() > 0 )
182   {
183     childHit.distance = std::numeric_limits<float>::max();
184     Dali::ActorContainer& children = actor.GetChildrenInternal();
185
186     // Hit test ALL children and calculate their distance.
187     bool parentIsRenderable = actor.IsRenderable();
188
189     for (Dali::ActorIter iter = children.begin(), endIter = children.end(); iter != endIter; ++iter)
190     {
191       // Descend tree only if...
192       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
193            ( isStencil || func(*iter, Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE ) ) ) // Child is visible and sensitive, otherwise none of its children should be hittable.
194       {
195         HitActor currentHit( HitTestWithinLayer( GetImplementation(*iter), rayOrigin, rayDir, worldOverlay, nearClippingPlane, farClippingPlane, func, stencilOnLayer, stencilHit, isStencil ) );
196
197         // If Current child is an overlay, then it takes priority.
198         // If it is not an overlay, and the previously hit sibling is also not an overlay, then closest takes priority.
199         // (last overlay sibling has priority as is rendered on top)
200         if ( currentHit.distance >= 0.f && (currentHit.overlay || (!childHit.overlay && currentHit.distance < childHit.distance) ) )
201         {
202           if ( !parentIsRenderable )
203           {
204             // If our parent is not renderable, then child should be hit regardless of distance.
205             childHit = currentHit;
206           }
207           else if ( currentHit.overlay || (!hit.overlay && currentHit.distance <= hit.distance) )
208           {
209             // 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.
210             // (child overlay has priority as is rendered on top of it's parent)
211             childHit = currentHit;
212           }
213         }
214       }
215     }
216   }
217   return ( childHit.actor ) ? childHit : hit;
218 }
219
220 /**
221  * Return true if actor is sourceActor or a descendent of sourceActor
222  */
223 bool IsWithinSourceActors( const Actor& sourceActor, const Actor& actor )
224 {
225   if ( &sourceActor == &actor )
226   {
227     return true;
228   }
229   else
230   {
231     Actor* parent = actor.GetParent();
232     if ( parent )
233     {
234       return IsWithinSourceActors( sourceActor, *parent );
235     }
236   }
237
238   // Not within source actors
239   return false;
240 }
241
242 /**
243  * Returns true if the layer and all of the layer's parents are visible and sensitive.
244  */
245 inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, Dali::HitTestAlgorithm::HitTestFunction func )
246 {
247   bool hittable( true );
248
249   if(layer.IsClipping())
250   {
251     ClippingBox box = layer.GetClippingBox();
252
253     if( screenCoordinates.x < box.x ||
254         screenCoordinates.x > box.x + box.width ||
255         screenCoordinates.y < stageSize.y - (box.y + box.height) ||
256         screenCoordinates.y > stageSize.y - box.y)
257     {
258       // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
259       hittable = false;
260     }
261   }
262
263   if(hittable)
264   {
265     Actor* actor( &layer );
266     while ( actor && hittable )
267     {
268       if ( !(func(Dali::Actor(actor), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE)) ) // Layer (or its Parent) is NOT visible and sensitive, so our layer is not either.
269       {
270         hittable = false;
271         break;
272       }
273       actor = actor->GetParent();
274     }
275   }
276
277   return hittable;
278 }
279
280 /**
281  * Gets the near and far clipping planes of the camera from which the scene is viewed in the render task.
282  */
283 void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, float& farClippingPlane )
284 {
285   CameraActor* cameraActor = renderTask.GetCameraActor();
286   nearClippingPlane = cameraActor->GetNearClippingPlane();
287   farClippingPlane = cameraActor->GetFarClippingPlane();
288 }
289
290 /**
291  * Hit test a RenderTask
292  */
293 bool HitTestRenderTask( LayerList& layers,
294                         RenderTask& renderTask,
295                         Vector2 screenCoordinates,
296                         Results& results,
297                         Dali::HitTestAlgorithm::HitTestFunction func )
298 {
299   if ( renderTask.IsHittable( screenCoordinates ) )
300   {
301     Viewport viewport;
302     renderTask.GetViewport( viewport );
303     if( screenCoordinates.x < viewport.x ||
304         screenCoordinates.x > viewport.x + viewport.width ||
305         screenCoordinates.y < viewport.y ||
306         screenCoordinates.y > viewport.y + viewport.height )
307     {
308       // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
309       return false;
310     }
311
312     float nearClippingPlane, farClippingPlane;
313     GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
314
315     // Determine the layer depth of the source actor
316     Actor* sourceActor( renderTask.GetSourceActor() );
317     if ( sourceActor )
318     {
319       Dali::Layer layer( sourceActor->GetLayer() );
320       if ( layer )
321       {
322         const unsigned int sourceActorDepth( layer.GetDepth() );
323
324         CameraActor* cameraActor = renderTask.GetCameraActor();
325         bool pickingPossible = cameraActor->BuildPickingRay(
326             screenCoordinates,
327             viewport,
328             results.rayOrigin,
329             results.rayDirection );
330         if( !pickingPossible )
331         {
332           return false;
333         }
334
335         // Hit test starting with the top layer, working towards the bottom layer.
336         HitActor hit;
337         bool stencilOnLayer = false;
338         bool stencilHit = false;
339         const Vector2& stageSize = Stage::GetCurrent()->GetSize();
340
341         for (int i=layers.GetLayerCount()-1; i>=0 && !(hit.actor); --i)
342         {
343           Layer* layer( layers.GetLayer(i) );
344
345           HitActor previousHit = hit;
346           stencilOnLayer = false;
347           stencilHit = false;
348
349           // Ensure layer is touchable (also checks whether ancestors are also touchable)
350           if ( IsActuallyHittable ( *layer, screenCoordinates, stageSize, func ) )
351           {
352             // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
353             if ( sourceActorDepth == static_cast<unsigned int>(i) )
354             {
355               // Recursively hit test the source actor & children, without crossing into other layers.
356               hit = HitTestWithinLayer( *sourceActor, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, func, stencilOnLayer, stencilHit, false );
357             }
358             else if ( IsWithinSourceActors( *sourceActor, *layer ) )
359             {
360               // Recursively hit test all the actors, without crossing into other layers.
361               hit = HitTestWithinLayer( *layer, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, func, stencilOnLayer, stencilHit, false );
362             }
363             // If a stencil on this layer hasn't been hit, then discard hit results for this layer
364             if ( stencilOnLayer && !stencilHit )
365             {
366              hit = previousHit;
367             }
368           }
369         }
370         if ( hit.actor )
371         {
372           results.renderTask = Dali::RenderTask(&renderTask);
373           results.actor = hit.actor;
374           results.actorCoordinates.x = hit.x;
375           results.actorCoordinates.y = hit.y;
376           return true; // Success
377         }
378       }
379     }
380   }
381   return false;
382 }
383
384 /**
385  * Iterate through RenderTaskList and perform hit test.
386  */
387
388 void HitTestForEachRenderTask( LayerList& layers,
389                                RenderTaskList& taskList,
390                                const Vector2& screenCoordinates,
391                                Results& results,
392                                Dali::HitTestAlgorithm::HitTestFunction func )
393 {
394   RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
395   RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
396
397   // Check onscreen tasks before offscreen ones, hit test order should be reverse of draw order (see ProcessRenderTasks() where offscreen tasks are drawn first).
398
399   // on screen
400   for ( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
401   {
402     RenderTask& renderTask = GetImplementation( *iter );
403     Dali::FrameBufferImage frameBufferImage = renderTask.GetTargetFrameBuffer();
404
405     // Note that if frameBufferImage is NULL we are using the default (on screen) render target
406     if(frameBufferImage)
407     {
408       ResourceId id = GetImplementation(frameBufferImage).GetResourceId();
409
410       // on screen only
411       if(0 != id)
412       {
413         // Skip to next task
414         continue;
415       }
416     }
417
418     if ( HitTestRenderTask( layers, renderTask, screenCoordinates, results, func ) )
419     {
420       // Exit when an actor is hit
421       return; // don't bother checking off screen tasks
422     }
423   }
424
425   // off screen
426   for ( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
427   {
428     RenderTask& renderTask = GetImplementation( *iter );
429     Dali::FrameBufferImage frameBufferImage = renderTask.GetTargetFrameBuffer();
430
431     // Note that if frameBufferImage is NULL we are using the default (on screen) render target
432     if(frameBufferImage)
433     {
434       ResourceId id = GetImplementation(frameBufferImage).GetResourceId();
435
436       // off screen only
437       if(0 == id)
438       {
439         // Skip to next task
440         continue;
441       }
442
443       if ( HitTestRenderTask( layers, renderTask, screenCoordinates, results, func ) )
444       {
445         // Exit when an actor is hit
446         break;
447       }
448     }
449   }
450 }
451
452 } // unnamed namespace
453
454 void HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
455 {
456   // Hit-test the regular on-stage actors
457   RenderTaskList& taskList = stage.GetRenderTaskList();
458   LayerList& layerList = stage.GetLayerList();
459
460   Results hitTestResults;
461   HitTestForEachRenderTask( layerList, taskList, screenCoordinates, hitTestResults, func );
462
463   results.actor = hitTestResults.actor;
464   results.actorCoordinates = hitTestResults.actorCoordinates;
465 }
466
467 void HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
468 {
469   // Hit-test the system-overlay actors first
470   SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
471
472   if ( systemOverlay )
473   {
474     RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
475     LayerList& overlayLayerList = systemOverlay->GetLayerList();
476
477     HitTestForEachRenderTask( overlayLayerList, overlayTaskList, screenCoordinates, results, IsActorTouchableFunction );
478   }
479
480   // Hit-test the regular on-stage actors
481   if ( !results.actor )
482   {
483     RenderTaskList& taskList = stage.GetRenderTaskList();
484     LayerList& layerList = stage.GetLayerList();
485
486     HitTestForEachRenderTask( layerList, taskList, screenCoordinates, results, IsActorTouchableFunction );
487   }
488 }
489
490 void HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
491               Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
492 {
493   Results hitTestResults;
494   HitTestRenderTask( stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, func );
495   results.actor = hitTestResults.actor;
496   results.actorCoordinates = hitTestResults.actorCoordinates;
497 }
498
499 } // namespace HitTestAlgorithm
500
501 } // namespace Internal
502
503 } // namespace Dali