[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 //For reflection and clipping plane
36 const float REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_A = 2.0f;
37 const float REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_D = 1.0f;
38 }
39
40 namespace Dali
41 {
42
43 namespace Internal
44 {
45
46 namespace SceneGraph
47 {
48
49 namespace
50 {
51
52 template< typename T >
53 T Sign( T value )
54 {
55   return T( T(0) < value ) - T( value < T(0) );
56 }
57
58 void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
59 {
60   Vector3 vZ = target - eye;
61   vZ.Normalize();
62
63   Vector3 vX = up.Cross(vZ);
64   vX.Normalize();
65
66   Vector3 vY = vZ.Cross(vX);
67   vY.Normalize();
68
69   result.SetInverseTransformComponents(vX, vY, vZ, eye);
70 }
71
72 void Frustum(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
73 {
74   float deltaZ = far - near;
75   if ((near <= 0.0f) || (far <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
76   {
77     DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
78     DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
79     return;
80   }
81
82   float deltaX = right - left;
83   float deltaY = invertYAxis ? bottom - top : top - bottom;
84
85   result.SetIdentity();
86
87   float* m = result.AsFloat();
88   m[0] = -2.0f * near / deltaX;
89   m[1] = m[2] = m[3] = 0.0f;
90
91   m[5] = -2.0f * near / deltaY;
92   m[4] = m[6] = m[7] = 0.0f;
93
94   m[8] = (right + left) / deltaX;
95   m[9] = (top + bottom) / deltaY;
96   m[10] = (near + far) / deltaZ;
97   m[11] = 1.0f;
98
99   m[14] = -2.0f * near * far / deltaZ;
100   m[12] = m[13] = m[15] = 0.0f;
101 }
102
103 void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis )
104 {
105   float frustumH = tanf( fovy * 0.5f ) * near;
106   float frustumW = frustumH * aspect;
107
108   Frustum(result, -frustumW, frustumW, -frustumH, frustumH, near, far, invertYAxis);
109 }
110
111 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
112 {
113   if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) )
114   {
115     DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension.\n" );
116     DALI_ASSERT_DEBUG( "Cannot create orthographic projection matrix with a zero dimension." );
117     return;
118   }
119
120   float deltaX = right - left;
121   float deltaY = invertYAxis ? bottom - top : top - bottom;
122   float deltaZ = far - near;
123
124   float *m = result.AsFloat();
125   m[0] = -2.0f / deltaX;
126   m[1] = 0.0f;
127   m[2] = 0.0f;
128   m[3] = 0.0f;
129
130   m[4] = 0.0f;
131   m[5] = -2.0f / deltaY;
132   m[6] = 0.0f;
133   m[7] = 0.0f;
134
135   m[8] = 0.0f;
136   m[9] = 0.0f;
137   m[10] = 2.0f / deltaZ;
138   m[11] = 0.0f;
139   m[12] = -(right + left) / deltaX;
140   m[13] = -(top + bottom) / deltaY;
141   m[14] = -(near + far)   / deltaZ;
142   m[15] = 1.0f;
143 }
144
145 } // unnamed namespace
146
147 const Dali::Camera::Type Camera::DEFAULT_TYPE( Dali::Camera::FREE_LOOK );
148 const Dali::Camera::ProjectionMode Camera::DEFAULT_MODE( Dali::Camera::PERSPECTIVE_PROJECTION );
149 const bool  Camera::DEFAULT_INVERT_Y_AXIS( false );
150 const float Camera::DEFAULT_FIELD_OF_VIEW( 45.0f*(Math::PI/180.0f) );
151 const float Camera::DEFAULT_ASPECT_RATIO( 4.0f/3.0f );
152 const float Camera::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
153 const float Camera::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
154 const float Camera::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
155 const float Camera::DEFAULT_BOTTOM_CLIPPING_PLANE(400.0f);
156 const float Camera::DEFAULT_NEAR_CLIPPING_PLANE( 800.0f ); // default height of the screen
157 const float Camera::DEFAULT_FAR_CLIPPING_PLANE( DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE );
158 const Vector3 Camera::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f );
159
160
161 Camera::Camera()
162 : mUpdateViewFlag( UPDATE_COUNT ),
163   mUpdateProjectionFlag( UPDATE_COUNT ),
164   mProjectionRotation( 0 ),
165   mNode( nullptr ),
166   mType( DEFAULT_TYPE ),
167   mProjectionMode( DEFAULT_MODE ),
168   mInvertYAxis( DEFAULT_INVERT_Y_AXIS ),
169   mFieldOfView( DEFAULT_FIELD_OF_VIEW ),
170   mAspectRatio( DEFAULT_ASPECT_RATIO ),
171   mLeftClippingPlane( DEFAULT_LEFT_CLIPPING_PLANE ),
172   mRightClippingPlane( DEFAULT_RIGHT_CLIPPING_PLANE ),
173   mTopClippingPlane( DEFAULT_TOP_CLIPPING_PLANE ),
174   mBottomClippingPlane( DEFAULT_BOTTOM_CLIPPING_PLANE ),
175   mNearClippingPlane( DEFAULT_NEAR_CLIPPING_PLANE ),
176   mFarClippingPlane( DEFAULT_FAR_CLIPPING_PLANE ),
177   mTargetPosition( DEFAULT_TARGET_POSITION ),
178   mViewMatrix(),
179   mProjectionMatrix(),
180   mInverseViewProjection( Matrix::IDENTITY ),
181   mFinalProjection( Matrix::IDENTITY )
182 {
183 }
184
185 Camera* Camera::New()
186 {
187   return new Camera();
188 }
189
190 Camera::~Camera()
191 {
192 }
193
194 void Camera::SetNode( const Node* node )
195 {
196   mNode = node;
197 }
198
199 const Node* Camera::GetNode() const
200 {
201   return mNode;
202 }
203
204 void Camera::SetType( Dali::Camera::Type type )
205 {
206   mType = type;
207 }
208
209 void Camera::SetProjectionMode( Dali::Camera::ProjectionMode mode )
210 {
211   mProjectionMode = mode;
212   mUpdateProjectionFlag = UPDATE_COUNT;
213 }
214
215 void Camera::SetInvertYAxis( bool invertYAxis )
216 {
217   mInvertYAxis = invertYAxis;
218   mUpdateProjectionFlag = UPDATE_COUNT;
219 }
220
221 void Camera::SetFieldOfView( float fieldOfView )
222 {
223   mFieldOfView = fieldOfView;
224   mUpdateProjectionFlag = UPDATE_COUNT;
225 }
226
227 void Camera::SetAspectRatio( float aspectRatio )
228 {
229   mAspectRatio = aspectRatio;
230   mUpdateProjectionFlag = UPDATE_COUNT;
231 }
232
233 void Camera::SetLeftClippingPlane( float leftClippingPlane )
234 {
235   mLeftClippingPlane = leftClippingPlane;
236   mUpdateProjectionFlag = UPDATE_COUNT;
237 }
238
239 void Camera::SetRightClippingPlane( float rightClippingPlane )
240 {
241   mRightClippingPlane = rightClippingPlane;
242   mUpdateProjectionFlag = UPDATE_COUNT;
243 }
244
245 void Camera::SetTopClippingPlane( float topClippingPlane )
246 {
247   mTopClippingPlane = topClippingPlane;
248   mUpdateProjectionFlag = UPDATE_COUNT;
249 }
250
251 void Camera::SetBottomClippingPlane( float bottomClippingPlane )
252 {
253   mBottomClippingPlane = bottomClippingPlane;
254   mUpdateProjectionFlag = UPDATE_COUNT;
255 }
256
257 void Camera::SetNearClippingPlane( float nearClippingPlane )
258 {
259   mNearClippingPlane = nearClippingPlane;
260   mUpdateProjectionFlag = UPDATE_COUNT;
261 }
262
263 void Camera::SetFarClippingPlane( float farClippingPlane )
264 {
265   mFarClippingPlane = farClippingPlane;
266   mUpdateProjectionFlag = UPDATE_COUNT;
267 }
268
269 void Camera::SetTargetPosition( const Vector3& targetPosition )
270 {
271   mTargetPosition = targetPosition;
272   mUpdateViewFlag = UPDATE_COUNT;
273 }
274
275 void VectorReflectedByPlane(Vector4 &out, Vector4 &in, Vector4 &plane)
276 {
277   float d = float(2.0) * plane.Dot(in);
278   out.x = static_cast<float>(in.x - plane.x*d);
279   out.y = static_cast<float>(in.y - plane.y*d);
280   out.z = static_cast<float>(in.z - plane.z*d);
281   out.w = static_cast<float>(in.w - plane.w*d);
282 }
283
284 void Camera::AdjustNearPlaneForPerspective( Matrix& perspective, const Vector4& clipPlane )
285 {
286   Vector4    q;
287   float* v = perspective.AsFloat();
288
289   q.x = (Sign(clipPlane.x) + v[8]) / v[0];
290   q.y = (Sign(clipPlane.y) + v[9]) / v[5];
291   q.z = -1.0f;
292   q.w = (1.0f + v[10]) / v[14];
293
294   // Calculate the scaled plane vector
295   Vector4 c = clipPlane * (REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_A / q.Dot( clipPlane));
296
297   // Replace the third row of the projection v
298   v[2] = c.x;
299   v[6] = c.y;
300   v[10] = c.z + REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_D;
301   v[14] = c.w;
302 }
303
304 void Camera::SetReflectByPlane( const Vector4& plane )
305 {
306   float* v = mReflectionMtx.AsFloat();
307   float _2ab = -2.0f * plane.x * plane.y;
308   float _2ac = -2.0f * plane.x * plane.z;
309   float _2bc = -2.0f * plane.y * plane.z;
310
311   v[0] = 1.0f - 2.0f * plane.x * plane.x;
312   v[1] = _2ab;
313   v[2] = _2ac;
314   v[3] = 0.0f;
315
316   v[4] = _2ab;
317   v[5] = 1.0f - 2.0f * plane.y * plane.y;
318   v[6] = _2bc;
319   v[7] = 0.0f;
320
321   v[8] = _2ac;
322   v[9] = _2bc;
323   v[10] = 1.0f - 2.0f * plane.z * plane.z;
324   v[11] = 0.0f;
325
326   v[12] =    - 2 * plane.x * plane.w;
327   v[13] =    - 2 * plane.y * plane.w;
328   v[14] =    - 2 * plane.z * plane.w;
329   v[15] = 1.0f;
330
331   mUseReflection = true;
332   mReflectionPlane = plane;
333   mUpdateViewFlag = UPDATE_COUNT;
334 }
335
336 void Camera::RotateProjection( int rotationAngle )
337 {
338   mProjectionRotation = rotationAngle;
339   mUpdateViewFlag = UPDATE_COUNT;
340 }
341
342 const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const
343 {
344   return mProjectionMatrix[ bufferIndex ];
345 }
346
347 const Matrix& Camera::GetViewMatrix( BufferIndex bufferIndex ) const
348 {
349   return mViewMatrix[ bufferIndex ];
350 }
351
352 const Matrix& Camera::GetInverseViewProjectionMatrix( BufferIndex bufferIndex ) const
353 {
354   return mInverseViewProjection[ bufferIndex ];
355 }
356
357 const Matrix& Camera::GetFinalProjectionMatrix( BufferIndex bufferIndex ) const
358 {
359   return mFinalProjection[ bufferIndex ];
360 }
361
362 const PropertyInputImpl* Camera::GetProjectionMatrix() const
363 {
364   return &mProjectionMatrix;
365 }
366
367 const PropertyInputImpl* Camera::GetViewMatrix() const
368 {
369   return &mViewMatrix;
370 }
371
372 void Camera::Update( BufferIndex updateBufferIndex )
373 {
374   // if owning node has changes in world position we need to update camera for next 2 frames
375   if( mNode->IsLocalMatrixDirty() )
376   {
377     mUpdateViewFlag = UPDATE_COUNT;
378   }
379   if( mNode->GetDirtyFlags() & NodePropertyFlags::VISIBLE )
380   {
381     // If the visibility changes, the projection matrix needs to be re-calculated.
382     // It may happen the first time an actor is rendered it's rendered only once and becomes invisible,
383     // in the following update the node will be skipped leaving the projection matrix (double buffered)
384     // with the Identity.
385     mUpdateProjectionFlag = UPDATE_COUNT;
386   }
387
388   // if either matrix changed, we need to recalculate the inverse matrix for hit testing to work
389   uint32_t viewUpdateCount = UpdateViewMatrix( updateBufferIndex );
390   uint32_t projectionUpdateCount = UpdateProjection( updateBufferIndex );
391
392   // if model or view matrix changed we need to either recalculate the inverse VP or copy previous
393   if( viewUpdateCount > COPY_PREVIOUS_MATRIX || projectionUpdateCount > COPY_PREVIOUS_MATRIX )
394   {
395     // either has actually changed so recalculate
396     Matrix::Multiply( mInverseViewProjection[ updateBufferIndex ], mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
397     UpdateFrustum( updateBufferIndex );
398
399     // ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
400     static_cast< void >( mInverseViewProjection[ updateBufferIndex ].Invert() );
401   }
402   else if( viewUpdateCount == COPY_PREVIOUS_MATRIX || projectionUpdateCount == COPY_PREVIOUS_MATRIX )
403   {
404     // neither has actually changed, but we might copied previous frames value so need to
405     // copy the previous inverse and frustum as well
406     mInverseViewProjection[updateBufferIndex] = mInverseViewProjection[updateBufferIndex ? 0 : 1];
407     mFrustum[ updateBufferIndex ] = mFrustum[ updateBufferIndex ? 0 : 1 ];
408   }
409 }
410
411 bool Camera::ViewMatrixUpdated()
412 {
413   return 0u != mUpdateViewFlag;
414 }
415
416 uint32_t Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
417 {
418   uint32_t retval( mUpdateViewFlag );
419   if( 0u != mUpdateViewFlag )
420   {
421     if( COPY_PREVIOUS_MATRIX == mUpdateViewFlag )
422     {
423       // The projection matrix was updated in the previous frame; copy it
424       mViewMatrix.CopyPrevious( updateBufferIndex );
425     }
426     else // UPDATE_COUNT == mUpdateViewFlag
427     {
428       switch( mType )
429       {
430         // camera orientation taken from node - i.e. look in abitrary, unconstrained direction
431         case Dali::Camera::FREE_LOOK:
432         {
433           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
434           viewMatrix = mNode->GetWorldMatrix( updateBufferIndex );
435
436           if (mUseReflection)
437           {
438             const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
439             Vector3 position{}, scale{};
440             Quaternion orientation{};
441             owningNodeMatrix.GetTransformComponents( position, orientation, scale );
442             mReflectionEye = position;
443             mUseReflectionClip = true;
444
445             Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
446             Matrix oldViewMatrix( viewMatrix );
447             Matrix::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
448           }
449
450           viewMatrix.Invert();
451           mViewMatrix.SetDirty( updateBufferIndex );
452           break;
453         }
454
455         // camera orientation constrained to look at a target
456         case Dali::Camera::LOOK_AT_TARGET:
457         {
458           const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
459           Vector3 position, scale;
460           Quaternion orientation;
461           owningNodeMatrix.GetTransformComponents( position, orientation, scale );
462           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
463
464           if (mUseReflection)
465           {
466             Vector3 up = orientation.Rotate( Vector3::YAXIS );
467             Vector4 position4 = Vector4(position);
468             Vector4 target4 = Vector4(mTargetPosition);
469             Vector4 up4 = Vector4(up);
470             Vector4 positionNew;
471             Vector4 targetNew;
472             Vector4 upNew;
473             Vector3 positionNew3;
474             Vector3 targetNewVector3;
475             Vector3 upNew3;
476
477             // eye
478             VectorReflectedByPlane(positionNew, position4, mReflectionPlane);
479             VectorReflectedByPlane(targetNew, target4, mReflectionPlane);
480             VectorReflectedByPlane(upNew, up4, mReflectionPlane);
481
482             positionNew3     = Vector3(positionNew);
483             targetNewVector3 = Vector3(targetNew);
484             upNew3           = Vector3(upNew);
485             LookAt(viewMatrix, positionNew3, targetNewVector3, upNew3 );
486
487             Matrix oldViewMatrix( viewMatrix );
488             Matrix tmp;
489             tmp.SetIdentityAndScale(Vector3(-1.0, 1.0,1.0));
490             Matrix::Multiply(viewMatrix, oldViewMatrix, tmp);
491
492             mReflectionEye = positionNew;
493             mUseReflectionClip = true;
494           }
495           else
496           {
497             LookAt( viewMatrix, position, mTargetPosition, orientation.Rotate( Vector3::YAXIS ) );
498           }
499           mViewMatrix.SetDirty( updateBufferIndex );
500           break;
501         }
502       }
503     }
504     --mUpdateViewFlag;
505   }
506   return retval;
507 }
508
509 void Camera::UpdateFrustum( BufferIndex updateBufferIndex, bool normalize )
510 {
511
512   // Extract the clip matrix planes
513   Matrix clipMatrix;
514   Matrix::Multiply( clipMatrix, mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
515
516   const float* cm = clipMatrix.AsFloat();
517   FrustumPlanes& planes = mFrustum[ updateBufferIndex ];
518
519   // Left
520   planes.mPlanes[ 0 ].mNormal.x = cm[ 3 ]  + cm[ 0 ]; // column 4 + column 1
521   planes.mPlanes[ 0 ].mNormal.y = cm[ 7 ]  + cm[ 4 ];
522   planes.mPlanes[ 0 ].mNormal.z = cm[ 11 ] + cm[ 8 ];
523   planes.mPlanes[ 0 ].mDistance = cm[ 15 ] + cm[ 12 ];
524
525   // Right
526   planes.mPlanes[ 1 ].mNormal.x = cm[ 3 ]  - cm[ 0 ]; // column 4 - column 1
527   planes.mPlanes[ 1 ].mNormal.y = cm[ 7 ]  - cm[ 4 ];
528   planes.mPlanes[ 1 ].mNormal.z = cm[ 11 ] - cm[ 8 ];
529   planes.mPlanes[ 1 ].mDistance = cm[ 15 ] - cm[ 12 ];
530
531   // Bottom
532   planes.mPlanes[ 2 ].mNormal.x = cm[ 3 ]  + cm[ 1 ]; // column 4 + column 2
533   planes.mPlanes[ 2 ].mNormal.y = cm[ 7 ]  + cm[ 5 ];
534   planes.mPlanes[ 2 ].mNormal.z = cm[ 11 ] + cm[ 9 ];
535   planes.mPlanes[ 2 ].mDistance = cm[ 15 ] + cm[ 13 ];
536
537   // Top
538   planes.mPlanes[ 3 ].mNormal.x = cm[ 3 ]  - cm[ 1 ]; // column 4 - column 2
539   planes.mPlanes[ 3 ].mNormal.y = cm[ 7 ]  - cm[ 5 ];
540   planes.mPlanes[ 3 ].mNormal.z = cm[ 11 ] - cm[ 9 ];
541   planes.mPlanes[ 3 ].mDistance = cm[ 15 ] - cm[ 13 ];
542
543   // Near
544   planes.mPlanes[ 4 ].mNormal.x = cm[ 3 ]  + cm[ 2 ]; // column 4 + column 3
545   planes.mPlanes[ 4 ].mNormal.y = cm[ 7 ]  + cm[ 6 ];
546   planes.mPlanes[ 4 ].mNormal.z = cm[ 11 ] + cm[ 10 ];
547   planes.mPlanes[ 4 ].mDistance = cm[ 15 ] + cm[ 14 ];
548
549   // Far
550   planes.mPlanes[ 5 ].mNormal.x = cm[ 3 ]  - cm[ 2 ]; // column 4 - column 3
551   planes.mPlanes[ 5 ].mNormal.y = cm[ 7 ]  - cm[ 6 ];
552   planes.mPlanes[ 5 ].mNormal.z = cm[ 11 ] - cm[ 10 ];
553   planes.mPlanes[ 5 ].mDistance = cm[ 15 ] - cm[ 14 ];
554
555   if ( normalize )
556   {
557     for ( uint32_t i = 0; i < 6; ++i )
558     {
559       // Normalize planes to ensure correct bounding distance checking
560       Plane& plane = planes.mPlanes[ i ];
561       float l = 1.0f / plane.mNormal.Length();
562       plane.mNormal *= l;
563       plane.mDistance *= l;
564
565       planes.mSign[i] = Vector3( Sign(plane.mNormal.x), Sign(plane.mNormal.y), Sign(plane.mNormal.z) );
566     }
567   }
568   else
569   {
570     for ( uint32_t i = 0; i < 6; ++i )
571     {
572       planes.mSign[i] = Vector3( Sign(planes.mPlanes[ i ].mNormal.x), Sign(planes.mPlanes[ i ].mNormal.y), Sign(planes.mPlanes[ i ].mNormal.z) );
573     }
574   }
575   mFrustum[ updateBufferIndex ? 0 : 1 ] = planes;
576 }
577
578 bool Camera::CheckSphereInFrustum( BufferIndex bufferIndex, const Vector3& origin, float radius )
579 {
580   const FrustumPlanes& planes = mFrustum[ bufferIndex ];
581   for ( uint32_t i = 0; i < 6; ++i )
582   {
583     if ( ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( origin ) ) < -radius )
584     {
585       return false;
586     }
587   }
588   return true;
589 }
590
591 bool Camera::CheckAABBInFrustum( BufferIndex bufferIndex, const Vector3& origin, const Vector3& halfExtents )
592 {
593   const FrustumPlanes& planes = mFrustum[ bufferIndex ];
594   for ( uint32_t i = 0; i < 6; ++i )
595   {
596     if( planes.mPlanes[ i ].mNormal.Dot( origin + (halfExtents * planes.mSign[i]) ) > -(planes.mPlanes[ i ].mDistance) )
597     {
598       continue;
599     }
600
601     return false;
602   }
603   return true;
604 }
605
606 uint32_t Camera::UpdateProjection( BufferIndex updateBufferIndex )
607 {
608   uint32_t retval( mUpdateProjectionFlag );
609   // Early-exit if no update required
610   if ( 0u != mUpdateProjectionFlag )
611   {
612     if ( COPY_PREVIOUS_MATRIX == mUpdateProjectionFlag )
613     {
614       // The projection matrix was updated in the previous frame; copy it
615       mProjectionMatrix.CopyPrevious( updateBufferIndex );
616     }
617     else // UPDATE_COUNT == mUpdateProjectionFlag
618     {
619       switch( mProjectionMode )
620       {
621         case Dali::Camera::PERSPECTIVE_PROJECTION:
622         {
623           Matrix &projectionMatrix = mProjectionMatrix.Get( updateBufferIndex );
624           Perspective( projectionMatrix,
625                        mFieldOfView,
626                        mAspectRatio,
627                        mNearClippingPlane,
628                        mFarClippingPlane,
629                        mInvertYAxis );
630
631           //need to apply custom clipping plane
632           if (mUseReflectionClip)
633           {
634             Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
635             Matrix viewInv = viewMatrix;
636             viewInv.Invert();
637             viewInv.Transpose();
638
639             Dali::Vector4 adjReflectPlane = mReflectionPlane;
640             float d = mReflectionPlane.Dot(mReflectionEye);
641             if (d < 0)
642             {
643               adjReflectPlane.w = -adjReflectPlane.w;
644             }
645
646             Vector4 customClipping = viewInv * adjReflectPlane;
647             AdjustNearPlaneForPerspective(projectionMatrix, customClipping);
648
649             // Invert Z
650             Matrix matZ;
651             matZ.SetIdentity();
652             float* vZ = matZ.AsFloat();
653             vZ[10] = -vZ[10];
654             Matrix::Multiply(projectionMatrix, projectionMatrix , matZ);
655           }
656           break;
657         }
658         case Dali::Camera::ORTHOGRAPHIC_PROJECTION:
659         {
660           Matrix &projectionMatrix = mProjectionMatrix.Get( updateBufferIndex );
661           Orthographic( projectionMatrix,
662                         mLeftClippingPlane,   mRightClippingPlane,
663                         mBottomClippingPlane, mTopClippingPlane,
664                         mNearClippingPlane,   mFarClippingPlane,
665                         mInvertYAxis );
666           break;
667         }
668       }
669
670       mProjectionMatrix.SetDirty( updateBufferIndex );
671
672       Matrix &finalProjection = mFinalProjection[ updateBufferIndex ];
673       finalProjection.SetIdentity();
674
675       Quaternion rotationAngle;
676       switch( mProjectionRotation )
677       {
678         case 90:
679         {
680           rotationAngle = Quaternion( Dali::ANGLE_90, Vector3::ZAXIS );
681           break;
682         }
683         case 180:
684         {
685           rotationAngle = Quaternion( Dali::ANGLE_180, Vector3::ZAXIS );
686           break;
687         }
688         case 270:
689         {
690           rotationAngle = Quaternion( Dali::ANGLE_270, Vector3::ZAXIS );
691           break;
692         }
693         default:
694           rotationAngle = Quaternion( Dali::ANGLE_0, Vector3::ZAXIS );
695           break;
696       }
697
698       Matrix rotation;
699       rotation.SetIdentity();
700       rotation.SetTransformComponents( Vector3( 1.0f, 1.0f, 1.0f ), rotationAngle, Vector3( 0.0f, 0.0f, 0.0f ) );
701
702       Matrix::Multiply( finalProjection, mProjectionMatrix.Get( updateBufferIndex ), rotation );
703     }
704     --mUpdateProjectionFlag;
705   }
706   return retval;
707 }
708
709 } // namespace SceneGraph
710
711 } // namespace Internal
712
713 } // namespace Dali