[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
114   // Transforms the ray to the local reference system. As the test is against a sphere, only the translation and scale are needed.
115   const Vector3 rayOriginLocal(rayOrigin.x - translation.x, rayOrigin.y - translation.y, rayOrigin.z - translation.z);
116
117   // Computing the radius is not needed, a square radius is enough so can just use size but we do need to scale the sphere
118   const float width  = size.width * scale.width;
119   const float height = size.height * scale.height;
120
121   float squareSphereRadius = 0.5f * (width * width + height * height);
122
123   float a  = rayDir.Dot(rayDir);                                      // a
124   float b2 = rayDir.Dot(rayOriginLocal);                              // b/2
125   float c  = rayOriginLocal.Dot(rayOriginLocal) - squareSphereRadius; // c
126
127   return (b2 * b2 - a * c) >= 0.0f;
128 }
129
130 bool RayTest::ActorTest(const Internal::Actor& actor, const Vector4& rayOrigin, const Vector4& rayDir, Vector2& hitPointLocal, float& distance) const
131 {
132   bool hit = false;
133
134   if(actor.OnScene())
135   {
136     const Node& node = actor.GetNode();
137
138     // Transforms the ray to the local reference system.
139     // Calculate the inverse of Model matrix
140     Matrix invModelMatrix(false /*don't init*/);
141     invModelMatrix = node.GetWorldMatrix(0);
142     invModelMatrix.Invert();
143
144     Vector4 rayOriginLocal(invModelMatrix * rayOrigin);
145     Vector4 rayDirLocal(invModelMatrix * rayDir - invModelMatrix.GetTranslation());
146
147     // Test with the actor's XY plane (Normal = 0 0 1 1).
148     float a = -rayOriginLocal.z;
149     float b = rayDirLocal.z;
150
151     if(fabsf(b) > Math::MACHINE_EPSILON_1)
152     {
153       // Ray travels distance * rayDirLocal to intersect with plane.
154       distance = a / b;
155
156       const Vector2& size = actor.GetTouchArea() == Vector2::ZERO ? Vector2(node.GetSize(EventThreadServices::Get().GetEventBufferIndex())) : actor.GetTouchArea();
157       hitPointLocal.x     = rayOriginLocal.x + rayDirLocal.x * distance + size.x * 0.5f;
158       hitPointLocal.y     = rayOriginLocal.y + rayDirLocal.y * distance + size.y * 0.5f;
159
160       // Test with the actor's geometry.
161       hit = (hitPointLocal.x >= 0.f) && (hitPointLocal.x <= size.x) && (hitPointLocal.y >= 0.f) && (hitPointLocal.y <= size.y);
162     }
163   }
164
165   return hit;
166 }
167
168 } // namespace Internal
169
170 } // namespace Dali