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