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