Revert "[Tizen] Add screen and client rotation itself function"
[platform/core/uifw/dali-core.git] / dali / internal / update / render-tasks / scene-graph-camera.cpp
1 /*
2  * Copyright (c) 2018 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/update/render-tasks/scene-graph-camera.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/math/math-utils.h>
28 #include <dali/internal/update/nodes/node.h>
29
30 namespace // unnamed namespace
31 {
32 const uint32_t UPDATE_COUNT        = 2u;  // Update projection or view matrix this many frames after a change
33 const uint32_t COPY_PREVIOUS_MATRIX = 1u; // Copy view or projection matrix from previous frame
34 }
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace SceneGraph
43 {
44
45 namespace
46 {
47
48 template< typename T >
49 T Sign( T value )
50 {
51   return T( T(0) < value ) - T( value < T(0) );
52 }
53
54 void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
55 {
56   Vector3 vZ = target - eye;
57   vZ.Normalize();
58
59   Vector3 vX = up.Cross(vZ);
60   vX.Normalize();
61
62   Vector3 vY = vZ.Cross(vX);
63   vY.Normalize();
64
65   result.SetInverseTransformComponents(vX, vY, vZ, eye);
66 }
67
68 void Frustum(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
69 {
70   float deltaZ = far - near;
71   if ((near <= 0.0f) || (far <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
72   {
73     DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
74     DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
75     return;
76   }
77
78   float deltaX = right - left;
79   float deltaY = invertYAxis ? bottom - top : top - bottom;
80
81   result.SetIdentity();
82
83   float* m = result.AsFloat();
84   m[0] = -2.0f * near / deltaX;
85   m[1] = m[2] = m[3] = 0.0f;
86
87   m[5] = -2.0f * near / deltaY;
88   m[4] = m[6] = m[7] = 0.0f;
89
90   m[8] = (right + left) / deltaX;
91   m[9] = (top + bottom) / deltaY;
92   m[10] = (near + far) / deltaZ;
93   m[11] = 1.0f;
94
95   m[14] = -2.0f * near * far / deltaZ;
96   m[12] = m[13] = m[15] = 0.0f;
97 }
98
99 void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis )
100 {
101   float frustumH = tanf( fovy * 0.5f ) * near;
102   float frustumW = frustumH * aspect;
103
104   Frustum(result, -frustumW, frustumW, -frustumH, frustumH, near, far, invertYAxis);
105 }
106
107 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
108 {
109   if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) )
110   {
111     DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension.\n" );
112     DALI_ASSERT_DEBUG( "Cannot create orthographic projection matrix with a zero dimension." );
113     return;
114   }
115
116   float deltaX = right - left;
117   float deltaY = invertYAxis ? bottom - top : top - bottom;
118   float deltaZ = far - near;
119
120   float *m = result.AsFloat();
121   m[0] = -2.0f / deltaX;
122   m[1] = 0.0f;
123   m[2] = 0.0f;
124   m[3] = 0.0f;
125
126   m[4] = 0.0f;
127   m[5] = -2.0f / deltaY;
128   m[6] = 0.0f;
129   m[7] = 0.0f;
130
131   m[8] = 0.0f;
132   m[9] = 0.0f;
133   m[10] = 2.0f / deltaZ;
134   m[11] = 0.0f;
135   m[12] = -(right + left) / deltaX;
136   m[13] = -(top + bottom) / deltaY;
137   m[14] = -(near + far)   / deltaZ;
138   m[15] = 1.0f;
139 }
140
141 } // unnamed namespace
142
143 const Dali::Camera::Type Camera::DEFAULT_TYPE( Dali::Camera::FREE_LOOK );
144 const Dali::Camera::ProjectionMode Camera::DEFAULT_MODE( Dali::Camera::PERSPECTIVE_PROJECTION );
145 const bool  Camera::DEFAULT_INVERT_Y_AXIS( false );
146 const float Camera::DEFAULT_FIELD_OF_VIEW( 45.0f*(Math::PI/180.0f) );
147 const float Camera::DEFAULT_ASPECT_RATIO( 4.0f/3.0f );
148 const float Camera::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
149 const float Camera::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
150 const float Camera::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
151 const float Camera::DEFAULT_BOTTOM_CLIPPING_PLANE(400.0f);
152 const float Camera::DEFAULT_NEAR_CLIPPING_PLANE( 800.0f ); // default height of the screen
153 const float Camera::DEFAULT_FAR_CLIPPING_PLANE( DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE );
154 const Vector3 Camera::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f );
155
156
157 Camera::Camera()
158 : mUpdateViewFlag( UPDATE_COUNT ),
159   mUpdateProjectionFlag( UPDATE_COUNT ),
160   mNode( NULL ),
161   mType( DEFAULT_TYPE ),
162   mProjectionMode( DEFAULT_MODE ),
163   mInvertYAxis( DEFAULT_INVERT_Y_AXIS ),
164   mFieldOfView( DEFAULT_FIELD_OF_VIEW ),
165   mAspectRatio( DEFAULT_ASPECT_RATIO ),
166   mLeftClippingPlane( DEFAULT_LEFT_CLIPPING_PLANE ),
167   mRightClippingPlane( DEFAULT_RIGHT_CLIPPING_PLANE ),
168   mTopClippingPlane( DEFAULT_TOP_CLIPPING_PLANE ),
169   mBottomClippingPlane( DEFAULT_BOTTOM_CLIPPING_PLANE ),
170   mNearClippingPlane( DEFAULT_NEAR_CLIPPING_PLANE ),
171   mFarClippingPlane( DEFAULT_FAR_CLIPPING_PLANE ),
172   mTargetPosition( DEFAULT_TARGET_POSITION ),
173   mViewMatrix(),
174   mProjectionMatrix(),
175   mInverseViewProjection( Matrix::IDENTITY )
176 {
177 }
178
179 Camera* Camera::New()
180 {
181   return new Camera();
182 }
183
184 Camera::~Camera()
185 {
186 }
187
188 void Camera::SetNode( const Node* node )
189 {
190   mNode = node;
191 }
192
193 void Camera::SetType( Dali::Camera::Type type )
194 {
195   mType = type;
196 }
197
198 void Camera::SetProjectionMode( Dali::Camera::ProjectionMode mode )
199 {
200   mProjectionMode = mode;
201   mUpdateProjectionFlag = UPDATE_COUNT;
202 }
203
204 void Camera::SetInvertYAxis( bool invertYAxis )
205 {
206   mInvertYAxis = invertYAxis;
207   mUpdateProjectionFlag = UPDATE_COUNT;
208 }
209
210 void Camera::SetFieldOfView( float fieldOfView )
211 {
212   mFieldOfView = fieldOfView;
213   mUpdateProjectionFlag = UPDATE_COUNT;
214 }
215
216 void Camera::SetAspectRatio( float aspectRatio )
217 {
218   mAspectRatio = aspectRatio;
219   mUpdateProjectionFlag = UPDATE_COUNT;
220 }
221
222 void Camera::SetLeftClippingPlane( float leftClippingPlane )
223 {
224   mLeftClippingPlane = leftClippingPlane;
225   mUpdateProjectionFlag = UPDATE_COUNT;
226 }
227
228 void Camera::SetRightClippingPlane( float rightClippingPlane )
229 {
230   mRightClippingPlane = rightClippingPlane;
231   mUpdateProjectionFlag = UPDATE_COUNT;
232 }
233
234 void Camera::SetTopClippingPlane( float topClippingPlane )
235 {
236   mTopClippingPlane = topClippingPlane;
237   mUpdateProjectionFlag = UPDATE_COUNT;
238 }
239
240 void Camera::SetBottomClippingPlane( float bottomClippingPlane )
241 {
242   mBottomClippingPlane = bottomClippingPlane;
243   mUpdateProjectionFlag = UPDATE_COUNT;
244 }
245
246 void Camera::SetNearClippingPlane( float nearClippingPlane )
247 {
248   mNearClippingPlane = nearClippingPlane;
249   mUpdateProjectionFlag = UPDATE_COUNT;
250 }
251
252 void Camera::SetFarClippingPlane( float farClippingPlane )
253 {
254   mFarClippingPlane = farClippingPlane;
255   mUpdateProjectionFlag = UPDATE_COUNT;
256 }
257
258 void Camera::SetTargetPosition( const Vector3& targetPosition )
259 {
260   mTargetPosition = targetPosition;
261   mUpdateViewFlag = UPDATE_COUNT;
262 }
263
264 const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const
265 {
266   return mProjectionMatrix[ bufferIndex ];
267 }
268
269 const Matrix& Camera::GetViewMatrix( BufferIndex bufferIndex ) const
270 {
271   return mViewMatrix[ bufferIndex ];
272 }
273
274 const Matrix& Camera::GetInverseViewProjectionMatrix( BufferIndex bufferIndex ) const
275 {
276   return mInverseViewProjection[ bufferIndex ];
277 }
278
279 const PropertyInputImpl* Camera::GetProjectionMatrix() const
280 {
281   return &mProjectionMatrix;
282 }
283
284 const PropertyInputImpl* Camera::GetViewMatrix() const
285 {
286   return &mViewMatrix;
287 }
288
289 void Camera::Update( BufferIndex updateBufferIndex )
290 {
291   // if owning node has changes in world position we need to update camera for next 2 frames
292   if( mNode->IsLocalMatrixDirty() )
293   {
294     mUpdateViewFlag = UPDATE_COUNT;
295   }
296   if( mNode->GetDirtyFlags() & NodePropertyFlags::VISIBLE )
297   {
298     // If the visibility changes, the projection matrix needs to be re-calculated.
299     // It may happen the first time an actor is rendered it's rendered only once and becomes invisible,
300     // in the following update the node will be skipped leaving the projection matrix (double buffered)
301     // with the Identity.
302     mUpdateProjectionFlag = UPDATE_COUNT;
303   }
304
305   // if either matrix changed, we need to recalculate the inverse matrix for hit testing to work
306   uint32_t viewUpdateCount = UpdateViewMatrix( updateBufferIndex );
307   uint32_t projectionUpdateCount = UpdateProjection( updateBufferIndex );
308
309   // if model or view matrix changed we need to either recalculate the inverse VP or copy previous
310   if( viewUpdateCount > COPY_PREVIOUS_MATRIX || projectionUpdateCount > COPY_PREVIOUS_MATRIX )
311   {
312     // either has actually changed so recalculate
313     Matrix::Multiply( mInverseViewProjection[ updateBufferIndex ], mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
314     UpdateFrustum( updateBufferIndex );
315
316     // ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
317     static_cast< void >( mInverseViewProjection[ updateBufferIndex ].Invert() );
318   }
319   else if( viewUpdateCount == COPY_PREVIOUS_MATRIX || projectionUpdateCount == COPY_PREVIOUS_MATRIX )
320   {
321     // neither has actually changed, but we might copied previous frames value so need to
322     // copy the previous inverse and frustum as well
323     mInverseViewProjection[updateBufferIndex] = mInverseViewProjection[updateBufferIndex ? 0 : 1];
324     mFrustum[ updateBufferIndex ] = mFrustum[ updateBufferIndex ? 0 : 1 ];
325   }
326 }
327
328 bool Camera::ViewMatrixUpdated()
329 {
330   return 0u != mUpdateViewFlag;
331 }
332
333 uint32_t Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
334 {
335   uint32_t retval( mUpdateViewFlag );
336   if( 0u != mUpdateViewFlag )
337   {
338     if( COPY_PREVIOUS_MATRIX == mUpdateViewFlag )
339     {
340       // The projection matrix was updated in the previous frame; copy it
341       mViewMatrix.CopyPrevious( updateBufferIndex );
342     }
343     else // UPDATE_COUNT == mUpdateViewFlag
344     {
345       switch( mType )
346       {
347         // camera orientation taken from node - i.e. look in abitrary, unconstrained direction
348         case Dali::Camera::FREE_LOOK:
349         {
350           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
351           viewMatrix = mNode->GetWorldMatrix( updateBufferIndex );
352           viewMatrix.Invert();
353           mViewMatrix.SetDirty( updateBufferIndex );
354           break;
355         }
356           // camera orientation constrained to look at a target
357         case Dali::Camera::LOOK_AT_TARGET:
358         {
359           const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
360           Vector3 position, scale;
361           Quaternion orientation;
362           owningNodeMatrix.GetTransformComponents( position, orientation, scale );
363           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
364           LookAt( viewMatrix, position, mTargetPosition, orientation.Rotate( Vector3::YAXIS ) );
365           mViewMatrix.SetDirty( updateBufferIndex );
366           break;
367         }
368       }
369     }
370     --mUpdateViewFlag;
371   }
372   return retval;
373 }
374
375 void Camera::UpdateFrustum( BufferIndex updateBufferIndex, bool normalize )
376 {
377
378   // Extract the clip matrix planes
379   Matrix clipMatrix;
380   Matrix::Multiply( clipMatrix, mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
381
382   const float* cm = clipMatrix.AsFloat();
383   FrustumPlanes& planes = mFrustum[ updateBufferIndex ];
384
385   // Left
386   planes.mPlanes[ 0 ].mNormal.x = cm[ 3 ]  + cm[ 0 ]; // column 4 + column 1
387   planes.mPlanes[ 0 ].mNormal.y = cm[ 7 ]  + cm[ 4 ];
388   planes.mPlanes[ 0 ].mNormal.z = cm[ 11 ] + cm[ 8 ];
389   planes.mPlanes[ 0 ].mDistance = cm[ 15 ] + cm[ 12 ];
390
391   // Right
392   planes.mPlanes[ 1 ].mNormal.x = cm[ 3 ]  - cm[ 0 ]; // column 4 - column 1
393   planes.mPlanes[ 1 ].mNormal.y = cm[ 7 ]  - cm[ 4 ];
394   planes.mPlanes[ 1 ].mNormal.z = cm[ 11 ] - cm[ 8 ];
395   planes.mPlanes[ 1 ].mDistance = cm[ 15 ] - cm[ 12 ];
396
397   // Bottom
398   planes.mPlanes[ 2 ].mNormal.x = cm[ 3 ]  + cm[ 1 ]; // column 4 + column 2
399   planes.mPlanes[ 2 ].mNormal.y = cm[ 7 ]  + cm[ 5 ];
400   planes.mPlanes[ 2 ].mNormal.z = cm[ 11 ] + cm[ 9 ];
401   planes.mPlanes[ 2 ].mDistance = cm[ 15 ] + cm[ 13 ];
402
403   // Top
404   planes.mPlanes[ 3 ].mNormal.x = cm[ 3 ]  - cm[ 1 ]; // column 4 - column 2
405   planes.mPlanes[ 3 ].mNormal.y = cm[ 7 ]  - cm[ 5 ];
406   planes.mPlanes[ 3 ].mNormal.z = cm[ 11 ] - cm[ 9 ];
407   planes.mPlanes[ 3 ].mDistance = cm[ 15 ] - cm[ 13 ];
408
409   // Near
410   planes.mPlanes[ 4 ].mNormal.x = cm[ 3 ]  + cm[ 2 ]; // column 4 + column 3
411   planes.mPlanes[ 4 ].mNormal.y = cm[ 7 ]  + cm[ 6 ];
412   planes.mPlanes[ 4 ].mNormal.z = cm[ 11 ] + cm[ 10 ];
413   planes.mPlanes[ 4 ].mDistance = cm[ 15 ] + cm[ 14 ];
414
415   // Far
416   planes.mPlanes[ 5 ].mNormal.x = cm[ 3 ]  - cm[ 2 ]; // column 4 - column 3
417   planes.mPlanes[ 5 ].mNormal.y = cm[ 7 ]  - cm[ 6 ];
418   planes.mPlanes[ 5 ].mNormal.z = cm[ 11 ] - cm[ 10 ];
419   planes.mPlanes[ 5 ].mDistance = cm[ 15 ] - cm[ 14 ];
420
421   if ( normalize )
422   {
423     for ( uint32_t i = 0; i < 6; ++i )
424     {
425       // Normalize planes to ensure correct bounding distance checking
426       Plane& plane = planes.mPlanes[ i ];
427       float l = 1.0f / plane.mNormal.Length();
428       plane.mNormal *= l;
429       plane.mDistance *= l;
430
431       planes.mSign[i] = Vector3( Sign(plane.mNormal.x), Sign(plane.mNormal.y), Sign(plane.mNormal.z) );
432     }
433   }
434   else
435   {
436     for ( uint32_t i = 0; i < 6; ++i )
437     {
438       planes.mSign[i] = Vector3( Sign(planes.mPlanes[ i ].mNormal.x), Sign(planes.mPlanes[ i ].mNormal.y), Sign(planes.mPlanes[ i ].mNormal.z) );
439     }
440   }
441   mFrustum[ updateBufferIndex ? 0 : 1 ] = planes;
442 }
443
444 bool Camera::CheckSphereInFrustum( BufferIndex bufferIndex, const Vector3& origin, float radius )
445 {
446   const FrustumPlanes& planes = mFrustum[ bufferIndex ];
447   for ( uint32_t i = 0; i < 6; ++i )
448   {
449     if ( ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( origin ) ) < -radius )
450     {
451       return false;
452     }
453   }
454   return true;
455 }
456
457 bool Camera::CheckAABBInFrustum( BufferIndex bufferIndex, const Vector3& origin, const Vector3& halfExtents )
458 {
459   const FrustumPlanes& planes = mFrustum[ bufferIndex ];
460   for ( uint32_t i = 0; i < 6; ++i )
461   {
462     if( planes.mPlanes[ i ].mNormal.Dot( origin + (halfExtents * planes.mSign[i]) ) > -(planes.mPlanes[ i ].mDistance) )
463     {
464       continue;
465     }
466
467     return false;
468   }
469   return true;
470 }
471
472 uint32_t Camera::UpdateProjection( BufferIndex updateBufferIndex )
473 {
474   uint32_t retval( mUpdateProjectionFlag );
475   // Early-exit if no update required
476   if ( 0u != mUpdateProjectionFlag )
477   {
478     if ( COPY_PREVIOUS_MATRIX == mUpdateProjectionFlag )
479     {
480       // The projection matrix was updated in the previous frame; copy it
481       mProjectionMatrix.CopyPrevious( updateBufferIndex );
482     }
483     else // UPDATE_COUNT == mUpdateProjectionFlag
484     {
485       switch( mProjectionMode )
486       {
487         case Dali::Camera::PERSPECTIVE_PROJECTION:
488         {
489           Matrix &projectionMatrix = mProjectionMatrix.Get( updateBufferIndex );
490           Perspective( projectionMatrix,
491                        mFieldOfView,
492                        mAspectRatio,
493                        mNearClippingPlane,
494                        mFarClippingPlane,
495                        mInvertYAxis );
496           break;
497         }
498         case Dali::Camera::ORTHOGRAPHIC_PROJECTION:
499         {
500           Matrix &projectionMatrix = mProjectionMatrix.Get( updateBufferIndex );
501           Orthographic( projectionMatrix,
502                         mLeftClippingPlane,   mRightClippingPlane,
503                         mBottomClippingPlane, mTopClippingPlane,
504                         mNearClippingPlane,   mFarClippingPlane,
505                         mInvertYAxis );
506           break;
507         }
508       }
509
510       mProjectionMatrix.SetDirty( updateBufferIndex );
511     }
512     --mUpdateProjectionFlag;
513   }
514   return retval;
515 }
516
517 } // namespace SceneGraph
518
519 } // namespace Internal
520
521 } // namespace Dali