Revert "[Tizen] Not execute the remove callback"
[platform/core/uifw/dali-core.git] / dali / internal / event / events / ray-test.cpp
1 /*
2  * Copyright (c) 2021 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/ray-test.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/event/actors/actor-impl.h>
23 #include <dali/internal/event/common/event-thread-services.h>
24 #include <dali/internal/update/nodes/node.h>
25 #include <dali/public-api/math/vector2.h>
26 #include <dali/public-api/math/vector3.h>
27 #include <dali/public-api/math/vector4.h>
28
29 using Dali::Internal::SceneGraph::Node;
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 RayTest::RayTest()
36 : mEventThreadServices(EventThreadServices::Get())
37 {
38 }
39
40 bool RayTest::SphereTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir) const
41 {
42   /*
43    http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
44
45    Mathematical Formulation
46
47    Given the above mentioned sphere, a point 'p' lies on the surface of the sphere if
48
49    ( p - c ) dot ( p - c ) = r^2
50
51    Given a ray with a point of origin 'o', and a direction vector 'd':
52
53    ray(t) = o + td, t >= 0
54
55    we can find the t at which the ray intersects the sphere by setting ray(t) equal to 'p'
56
57    (o + td - c ) dot ( o + td - c ) = r^2
58
59    To solve for t we first expand the above into a more recognisable quadratic equation form
60
61    ( d dot d )t^2 + 2( o - c ) dot dt + ( o - c ) dot ( o - c ) - r^2 = 0
62
63    or
64
65    At2 + Bt + C = 0
66
67    where
68
69    A = d dot d
70    B = 2( o - c ) dot d
71    C = ( o - c ) dot ( o - c ) - r^2
72
73    which can be solved using a standard quadratic formula.
74
75    Note that in the absence of positive, real, roots, the ray does not intersect the sphere.
76
77    Practical Simplification
78
79    In a renderer, we often differentiate between world space and object space. In the object space
80    of a sphere it is centred at origin, meaning that if we first transform the ray from world space
81    into object space, the mathematical solution presented above can be simplified significantly.
82
83    If a sphere is centred at origin, a point 'p' lies on a sphere of radius r2 if
84
85    p dot p = r^2
86
87    and we can find the t at which the (transformed) ray intersects the sphere by
88
89    ( o + td ) dot ( o + td ) = r^2
90
91    According to the reasoning above, we expand the above quadratic equation into the general form
92
93    At2 + Bt + C = 0
94
95    which now has coefficients:
96
97    A = d dot d
98    B = 2( d dot o )
99    C = o dot o - r^2
100    */
101
102   // Early out if not on the scene
103   if(!actor.OnScene())
104   {
105     return false;
106   }
107
108   const Node&       node            = actor.GetNode();
109   const BufferIndex bufferIndex     = EventThreadServices::Get().GetEventBufferIndex();
110   const Vector3&    translation     = node.GetWorldPosition(bufferIndex);
111   const Vector3&    size            = node.GetSize(bufferIndex);
112   const Vector3&    scale           = node.GetWorldScale(bufferIndex);
113   const Rect<int>&  touchAreaOffset = actor.GetTouchAreaOffset(); // (left, right, bottom, top)
114
115   // Transforms the ray to the local reference system. As the test is against a sphere, only the translation and scale are needed.
116   const Vector3 rayOriginLocal(rayOrigin.x - translation.x - (touchAreaOffset.left + touchAreaOffset.right) * 0.5, rayOrigin.y - translation.y - (touchAreaOffset.top + touchAreaOffset.bottom) * 0.5, rayOrigin.z - translation.z);
117
118   // Computing the radius is not needed, a square radius is enough so can just use size but we do need to scale the sphere
119   const float width  = size.width * scale.width + touchAreaOffset.right - touchAreaOffset.left;
120   const float height = size.height * scale.height + touchAreaOffset.bottom - touchAreaOffset.top;
121
122   float squareSphereRadius = 0.5f * (width * width + height * height);
123
124   float a  = rayDir.Dot(rayDir);                                      // a
125   float b2 = rayDir.Dot(rayOriginLocal);                              // b/2
126   float c  = rayOriginLocal.Dot(rayOriginLocal) - squareSphereRadius; // c
127
128   return (b2 * b2 - a * c) >= 0.0f;
129 }
130
131 bool RayTest::ActorTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir, Vector2& hitPointLocal, float& distance) const
132 {
133   bool hit = false;
134
135   if(actor.OnScene())
136   {
137     const Node& node = actor.GetNode();
138
139     // Transforms the ray to the local reference system.
140     // Calculate the inverse of Model matrix
141     Matrix invModelMatrix(false /*don't init*/);
142     invModelMatrix = node.GetWorldMatrix(0);
143     invModelMatrix.Invert();
144
145     Vector4 rayOriginLocal(invModelMatrix * rayOrigin);
146     Vector4 rayDirLocal(invModelMatrix * rayDir - invModelMatrix.GetTranslation());
147
148     // Test with the actor's XY plane (Normal = 0 0 1 1).
149     float a = -rayOriginLocal.z;
150     float b = rayDirLocal.z;
151
152     if(fabsf(b) > Math::MACHINE_EPSILON_1)
153     {
154       // Ray travels distance * rayDirLocal to intersect with plane.
155       distance = a / b;
156
157       const Vector2&   size            = Vector2(node.GetSize(EventThreadServices::Get().GetEventBufferIndex()));
158       const Rect<int>& touchAreaOffset = actor.GetTouchAreaOffset(); // (left, right, bottom, top)
159       hitPointLocal.x                  = rayOriginLocal.x + rayDirLocal.x * distance + size.x * 0.5f;
160       hitPointLocal.y                  = rayOriginLocal.y + rayDirLocal.y * distance + size.y * 0.5f;
161
162       // Test with the actor's geometry.
163       hit = (hitPointLocal.x >= touchAreaOffset.left) && (hitPointLocal.x <= (size.x + touchAreaOffset.right) && (hitPointLocal.y >= touchAreaOffset.top) && (hitPointLocal.y <= (size.y + touchAreaOffset.bottom)));
164     }
165   }
166
167   return hit;
168 }
169
170 } // namespace Internal
171
172 } // namespace Dali