1 #ifndef __DALI_HIT_TEST_ALGORITHM_H__
2 #define __DALI_HIT_TEST_ALGORITHM_H__
5 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 #include <dali/devel-api/common/stage.h>
22 #include <dali/integration-api/scene.h>
23 #include <dali/public-api/actors/actor.h>
30 * @brief This namespace is provided for application developers to do hit-test for the actors.
32 * <h3>Hit Test Algorithm:</h3>
34 * Hit testing is dependent on the camera used, which is specific to each RenderTask. For each RenderTask,
35 * hit testing starts from the top-most layer and we go through all the layers until we have a hit or there
36 * are none left. Before we perform a hit test within a layer, we check if all the layer's parents meet the
37 * conditions defined by the function ((e.g. whether it is visible)). If they are not, we skip hit testing
38 * the actors in that layer altogether. Otherwise, we walk through the actor tree within a layer to check
39 * whether the actors within the actor tree should be hit-tested.
41 * The following pseudocode gives an example of what the function can typically check, which should normally
42 * be provided by the application code:
45 * HIT-TEST-FUNCTION( ACTOR, TRAVERSE-TYPE )
47 * if( TRAVERSE-TYPE == CHECK_ACTOR ) // Check whether current actor should be hit-tested
49 * if( ACTOR-IS-VISIBLE &&
50 * ACTOR-WORLD-COLOR-IS-NOT-TRANSPARENT )
55 * else if( TRAVERSE-TYPE == DESCEND_ACTOR_TREE ) ///< Check whether the actor tree should be descended to hit-test its children.
57 * if( ACTOR-IS-VISIBLE )
65 * The following pseudocode explains how the algorithm performs the hit-test with the above functor:
68 * HIT-TEST-WITHIN-LAYER( ACTOR )
70 * // Depth-first traversal within current layer, visiting parent first
72 * // Check whether current actor should be hit-tested
73 * IF ( HIT-TEST-FUNCTION( ACTOR, CHECK_ACTOR ) &&
74 * ACTOR-HAS-NON-ZERO-SIZE )
76 * // Hit-test current actor
79 * IF ( DISTANCE-TO-ACTOR < DISTANCE-TO-LAST-HIT-ACTOR )
81 * // The current actor is the closest actor that was underneath the touch
82 * LAST-HIT-ACTOR = CURRENT-ACTOR
87 * // Keep checking children, in case we hit something closer
88 * FOR-EACH CHILD (in order)
90 * IF ( HIT-TEST-FUNCTION( ACTOR, DESCEND_ACTOR_TREE ) &&
91 * ACTOR-IS-NOT-A-LAYER )
93 * // Continue traversal for this child's sub-tree
94 * HIT-TEST-WITHIN-LAYER ( CHILD )
96 * // else we skip the sub-tree with from this child
101 namespace HitTestAlgorithm
104 * @brief How the actor tree should be traversed.
108 CHECK_ACTOR, ///< Hit test the given actor.
109 DESCEND_ACTOR_TREE ///< Check whether the actor tree should be descended to hit-test its children.
113 * @brief Results structure containing the hit actor and where it was hit.
117 Actor actor; ///< The hit actor.
118 Vector2 actorCoordinates; ///< The actor coordinates.
122 * @brief Definition of a hit-test function to use in HitTest() method to check if the actor is hittable (e.g. touchable or focusable).
124 * @return true, if the actor is hittable, false otherwise.
126 using HitTestFunction = bool (*)(Actor, TraverseType);
129 * @brief Given screen coordinates, this method returns the hit actor & the local coordinates relative to
130 * the top-left (0.0f, 0.0f, 0.5f) of the actor.
132 * An actor is only hittable if the actor meets all the conditions
133 * defined by the given function (see HitTestAlgorithm).
135 * Typically, if an actor has a zero size or its world color is fully transparent, it should not be
136 * hittable; and if an actor's visibility flag is unset, its children should not be hittable either.
138 * @param[in] stage The stage.
139 * @param[in] screenCoordinates The screen coordinates.
140 * @param[out] results The results of the hit-test, only modified if something is hit
141 * @param[in] func The function to use in the hit-test algorithm.
142 * @param[in] propagationType If Integration::Scene::TouchPropagationType::GEOMETRY, hittest works in a geometry way.
143 * @return true if something was hit
145 DALI_CORE_API bool HitTest(Stage stage, const Vector2& screenCoordinates, Results& results, HitTestFunction func, const Integration::Scene::TouchPropagationType propagationType = Integration::Scene::TouchPropagationType::PARENT);
148 * @brief Given screen coordinates, this method returns the camera origin in world coordinates and the direction of the picking ray in world-space.
150 * @param[in] renderTask The render task owning a camera.
151 * @param[in] screenCoordinates The screen coordinates.
152 * @param[out] origin The camera origin in world coordinates
153 * @param[out] direction The direction of the picking ray in world-space
154 * @return true if the screen coordinates are inside the render task's viewport
156 DALI_CORE_API bool BuildPickingRay(RenderTask renderTask, const Vector2& screenCoordinates, Vector3& origin, Vector3& direction);
158 } // namespace HitTestAlgorithm
162 #endif // __DALI_HIT_TEST_ALGORITHM_H__