Compute min/max value if min/max is not defined.
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / camera-parameters.cpp
1 /*
2  * Copyright (c) 2022 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 #include "dali-scene3d/public-api/loader/camera-parameters.h"
18 #include "dali-scene3d/public-api/loader/utils.h"
19 #include "dali/integration-api/debug.h"
20 #include "dali/public-api/actors/camera-actor.h"
21 #include "dali/public-api/math/quaternion.h"
22
23 namespace Dali
24 {
25 namespace Scene3D
26 {
27 namespace Loader
28 {
29 namespace
30 {
31 /**
32  * @brief Creates a perspective matrix.
33  *
34  * @param[out] result The perspective matrix.
35  * @param[in] left The coordinate for the left vertical clipping plane.
36  * @param[in] right The coordinate for the right vertical clipping plane.
37  * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
38  * @param[in] top The coordinate for the top horizontal clipping plane.
39  * @param[in] near The distance to the near depth clipping plane.
40  * @param[in] far The distance to the far depth clipping plane.
41  * @param[in] invertYAxis Whether to invert the 'Y' axis.
42  */
43 void Frustum(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
44 {
45   float deltaZ = farPlane - nearPlane;
46   if((nearPlane <= 0.0f) || (farPlane <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
47   {
48     DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
49     DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
50     return;
51   }
52
53   float deltaX = right - left;
54   float deltaY = invertYAxis ? bottom - top : top - bottom;
55
56   result.SetIdentity();
57
58   float* m = result.AsFloat();
59   m[0]     = -2.0f * nearPlane / deltaX;
60   m[1] = m[2] = m[3] = 0.0f;
61
62   m[5] = -2.0f * nearPlane / deltaY;
63   m[4] = m[6] = m[7] = 0.0f;
64
65   m[8]  = (right + left) / deltaX;
66   m[9]  = (top + bottom) / deltaY;
67   m[10] = (nearPlane + farPlane) / deltaZ;
68   m[11] = 1.0f;
69
70   m[14] = -2.0f * nearPlane * farPlane / deltaZ;
71   m[12] = m[13] = m[15] = 0.0f;
72 }
73
74 /**
75  * @brief Creates a perspective projection matrix.
76  *
77  * It calls Frustum()
78  *
79  * @param[out] result The perspective projection matrix.
80  * @param[in] fovy The vertical field of view.
81  * @param[in] aspect The aspect ratio.
82  * @param[in] nearPlane The distance to the near depth clipping plane.
83  * @param[in] farPlane The distance to the far depth clipping plane.
84  * @param[in] invertYAxis Whether to invert the 'Y' axis.
85  */
86 void Perspective(Matrix& result, float fovy, float aspect, float nearPlane, float farPlane, bool invertYAxis)
87 {
88   float frustumH = tanf(fovy * 0.5f) * nearPlane;
89   float frustumW = frustumH * aspect;
90
91   Frustum(result, -frustumW, frustumW, -frustumH, frustumH, nearPlane, farPlane, invertYAxis);
92 }
93
94 /**
95 * @brief Creates an orthographic projection matrix.
96 *
97 * @param[out] result The orthographic projection matrix.
98 * @param[in] left The coordinate for the left vertical clipping plane.
99 * @param[in] right The coordinate for the right vertical clipping plane.
100 * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
101 * @param[in] top The coordinate for the top horizontal clipping plane.
102 * @param[in] nearPlane The distance to the near depth clipping plane.
103 * @param[in] farPlane The distance to the far depth clipping plane.
104 * @param[in] invertYAxis Whether to invert the 'Y' axis.
105 */
106 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
107 {
108   if(Equals(right, left) || Equals(top, bottom) || Equals(farPlane, nearPlane))
109   {
110     DALI_LOG_ERROR("Cannot create orthographic projection matrix with a zero dimension.\n");
111     DALI_ASSERT_DEBUG("Cannot create orthographic projection matrix with a zero dimension.");
112     return;
113   }
114
115   float deltaX = right - left;
116   float deltaY = invertYAxis ? bottom - top : top - bottom;
117   float deltaZ = farPlane - nearPlane;
118
119   float* m = result.AsFloat();
120   m[0]     = -2.0f / deltaX;
121   m[1]     = 0.0f;
122   m[2]     = 0.0f;
123   m[3]     = 0.0f;
124
125   m[4] = 0.0f;
126   m[5] = -2.0f / deltaY;
127   m[6] = 0.0f;
128   m[7] = 0.0f;
129
130   m[8]  = 0.0f;
131   m[9]  = 0.0f;
132   m[10] = 2.0f / deltaZ;
133   m[11] = 0.0f;
134   m[12] = -(right + left) / deltaX;
135   m[13] = -(top + bottom) / deltaY;
136   m[14] = -(nearPlane + farPlane) / deltaZ;
137   m[15] = 1.0f;
138 }
139
140 } // namespace
141
142 ViewProjection CameraParameters::GetViewProjection() const
143 {
144   ViewProjection viewProjection;
145   // The projection matrix.
146   if(isPerspective)
147   {
148     Perspective(viewProjection.GetProjection(),
149                 Radian(Degree(yFov)),
150                 1.f,
151                 zNear,
152                 zFar,
153                 true);
154   }
155   else
156   {
157     Orthographic(viewProjection.GetProjection(),
158                  orthographicSize.x,
159                  orthographicSize.y,
160                  orthographicSize.z,
161                  orthographicSize.w,
162                  zNear,
163                  zFar,
164                  true);
165   }
166
167   // The view matrix.
168   const Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
169   Vector3          translation;
170   Quaternion       cameraOrientation;
171   Vector3          scale;
172   matrix.GetTransformComponents(translation, cameraOrientation, scale);
173   cameraOrientation *= viewQuaternion;
174
175   viewProjection.GetView().SetInverseTransformComponents(scale,
176                                                          cameraOrientation,
177                                                          translation);
178
179   viewProjection.Update();
180   return viewProjection;
181 }
182
183 void CameraParameters::CalculateTransformComponents(Vector3& position, Quaternion& orientation, Vector3& scale) const
184 {
185   matrix.GetTransformComponents(position, orientation, scale);
186
187   // The CameraActor is expected to look down the negative Z axis, towards the scene.
188   // Here we emulate the default direction of the camera in DALi.
189   Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
190   orientation *= viewQuaternion;
191 }
192
193 void CameraParameters::ConfigureCamera(CameraActor& camera) const
194 {
195   SetActorCentered(camera);
196
197   if(isPerspective)
198   {
199     camera.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION);
200     camera.SetNearClippingPlane(zNear);
201     camera.SetFarClippingPlane(zFar);
202     camera.SetFieldOfView(Radian(Degree(yFov)));
203   }
204   else
205   {
206     camera.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION);
207     camera.SetOrthographicProjection(orthographicSize.x,
208                                      orthographicSize.y,
209                                      orthographicSize.z,
210                                      orthographicSize.w,
211                                      zNear,
212                                      zFar);
213   }
214
215   // model
216   Vector3    camTranslation;
217   Vector3    camScale;
218   Quaternion camOrientation;
219   CalculateTransformComponents(camTranslation, camOrientation, camScale);
220
221   camera.SetInvertYAxis(true);
222   camera.SetProperty(Actor::Property::POSITION, camTranslation);
223   camera.SetProperty(Actor::Property::ORIENTATION, camOrientation);
224   camera.SetProperty(Actor::Property::SCALE, camScale);
225 }
226
227 } // namespace Loader
228 } // namespace Scene3D
229 } // namespace Dali