Deprecate Plane Distance setter + Implement OrthographicSize + Animatable AspectRatio
[platform/core/uifw/dali-core.git] / dali / internal / update / render-tasks / scene-graph-camera.cpp
index c6e9973..586d7cc 100644 (file)
@@ -23,6 +23,8 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/internal/common/matrix-utils.h>
+#include <dali/internal/common/memory-pool-object-allocator.h>
 #include <dali/internal/update/nodes/node.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/math/math-utils.h>
@@ -45,6 +47,9 @@ namespace SceneGraph
 {
 namespace
 {
+//Memory pool used to allocate new camera. Memory used by this pool will be released when shutting down DALi
+MemoryPoolObjectAllocator<Camera> gCameraMemoryPool;
+
 template<typename T>
 T Sign(T value)
 {
@@ -96,35 +101,57 @@ void Frustum(Matrix& result, float left, float right, float bottom, float top, f
   m[12] = m[13] = m[15] = 0.0f;
 }
 
-void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis)
+void Perspective(Matrix& result, Dali::DevelCameraActor::ProjectionDirection fovDir, float fov, float aspect, float near, float far, bool invertYAxis)
 {
-  float frustumH = tanf(fovy * 0.5f) * near;
-  float frustumW = frustumH * aspect;
+  float frustumH;
+  float frustumW;
+  if(fovDir == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+  {
+    frustumH = tanf(fov * 0.5f) * near;
+    frustumW = frustumH * aspect;
+  }
+  else
+  {
+    frustumW = tanf(fov * 0.5f) * near;
+    frustumH = frustumW / aspect;
+  }
 
   Frustum(result, -frustumW, frustumW, -frustumH, frustumH, near, far, invertYAxis);
 }
 
-void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
+void Orthographic(Matrix& result, Dali::DevelCameraActor::ProjectionDirection orthographicDir, float orthographicSize, float aspect, float near, float far, bool invertYAxis)
 {
-  if(Equals(right, left) || Equals(top, bottom) || Equals(far, near))
+  if(EqualsZero(orthographicSize) || EqualsZero(aspect) || Equals(far, near))
   {
     DALI_LOG_ERROR("Cannot create orthographic projection matrix with a zero dimension.\n");
     DALI_ASSERT_DEBUG("Cannot create orthographic projection matrix with a zero dimension.");
     return;
   }
 
-  float deltaX = right - left;
-  float deltaY = invertYAxis ? bottom - top : top - bottom;
+  float halfDeltaX;
+  float halfDeltaY;
+  if(orthographicDir == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+  {
+    halfDeltaY = orthographicSize;
+    halfDeltaX = halfDeltaY * aspect;
+  }
+  else
+  {
+    halfDeltaX = orthographicSize;
+    halfDeltaY = halfDeltaX / aspect;
+  }
+
   float deltaZ = far - near;
 
   float* m = result.AsFloat();
-  m[0]     = -2.0f / deltaX;
-  m[1]     = 0.0f;
-  m[2]     = 0.0f;
-  m[3]     = 0.0f;
+
+  m[0] = -1.0f / halfDeltaX;
+  m[1] = 0.0f;
+  m[2] = 0.0f;
+  m[3] = 0.0f;
 
   m[4] = 0.0f;
-  m[5] = -2.0f / deltaY;
+  m[5] = (invertYAxis ? 1.0f : -1.0f) / halfDeltaY;
   m[6] = 0.0f;
   m[7] = 0.0f;
 
@@ -132,41 +159,38 @@ void Orthographic(Matrix& result, float left, float right, float bottom, float t
   m[9]  = 0.0f;
   m[10] = 2.0f / deltaZ;
   m[11] = 0.0f;
-  m[12] = -(right + left) / deltaX;
-  m[13] = -(top + bottom) / deltaY;
+
+  m[12] = 0.0f;
+  m[13] = 0.0f;
   m[14] = -(near + far) / deltaZ;
   m[15] = 1.0f;
 }
 
 } // unnamed namespace
 
-const Dali::Camera::Type           Camera::DEFAULT_TYPE(Dali::Camera::FREE_LOOK);
-const Dali::Camera::ProjectionMode Camera::DEFAULT_MODE(Dali::Camera::PERSPECTIVE_PROJECTION);
-const bool                         Camera::DEFAULT_INVERT_Y_AXIS(false);
-const float                        Camera::DEFAULT_FIELD_OF_VIEW(45.0f * (Math::PI / 180.0f));
-const float                        Camera::DEFAULT_ASPECT_RATIO(800.0f / 480.0f);
-const float                        Camera::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
-const float                        Camera::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
-const float                        Camera::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
-const float                        Camera::DEFAULT_BOTTOM_CLIPPING_PLANE(400.0f);
-const float                        Camera::DEFAULT_NEAR_CLIPPING_PLANE(800.0f); // default height of the screen
-const float                        Camera::DEFAULT_FAR_CLIPPING_PLANE(DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE);
-const Vector3                      Camera::DEFAULT_TARGET_POSITION(0.0f, 0.0f, 0.0f);
+const Dali::Camera::Type                          Camera::DEFAULT_TYPE(Dali::Camera::FREE_LOOK);
+const Dali::Camera::ProjectionMode                Camera::DEFAULT_MODE(Dali::Camera::PERSPECTIVE_PROJECTION);
+const Dali::DevelCameraActor::ProjectionDirection Camera::DEFAULT_PROJECTION_DIRECTION(Dali::DevelCameraActor::VERTICAL);
+const bool                                        Camera::DEFAULT_INVERT_Y_AXIS(false);
+const float                                       Camera::DEFAULT_FIELD_OF_VIEW(45.0f * (Math::PI / 180.0f));
+const float                                       Camera::DEFAULT_ORTHOGRAPHIC_SIZE(400.0f);     // half of default height of the screen
+const float                                       Camera::DEFAULT_ASPECT_RATIO(480.0f / 800.0f); // default width / default height of the screen
+const float                                       Camera::DEFAULT_NEAR_CLIPPING_PLANE(800.0f);   // default height of the screen
+const float                                       Camera::DEFAULT_FAR_CLIPPING_PLANE(DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE);
+const Vector3                                     Camera::DEFAULT_TARGET_POSITION(0.0f, 0.0f, 0.0f);
 
 Camera::Camera()
-: mUpdateViewFlag(UPDATE_COUNT),
+: Node(),
+  mUpdateViewFlag(UPDATE_COUNT),
   mUpdateProjectionFlag(UPDATE_COUNT),
   mProjectionRotation(0),
-  mNode(nullptr),
   mType(DEFAULT_TYPE),
   mProjectionMode(DEFAULT_MODE),
+  mProjectionDirection(DEFAULT_PROJECTION_DIRECTION),
   mInvertYAxis(DEFAULT_INVERT_Y_AXIS),
   mFieldOfView(DEFAULT_FIELD_OF_VIEW),
+  mOrthographicSize(DEFAULT_ORTHOGRAPHIC_SIZE),
   mAspectRatio(DEFAULT_ASPECT_RATIO),
-  mLeftClippingPlane(DEFAULT_LEFT_CLIPPING_PLANE),
-  mRightClippingPlane(DEFAULT_RIGHT_CLIPPING_PLANE),
-  mTopClippingPlane(DEFAULT_TOP_CLIPPING_PLANE),
-  mBottomClippingPlane(DEFAULT_BOTTOM_CLIPPING_PLANE),
   mNearClippingPlane(DEFAULT_NEAR_CLIPPING_PLANE),
   mFarClippingPlane(DEFAULT_FAR_CLIPPING_PLANE),
   mTargetPosition(DEFAULT_TARGET_POSITION),
@@ -175,23 +199,20 @@ Camera::Camera()
   mInverseViewProjection(Matrix::IDENTITY),
   mFinalProjection(Matrix::IDENTITY)
 {
+  // set a flag the node to say this is a camera
+  mIsCamera = true;
 }
 
 Camera* Camera::New()
 {
-  return new Camera();
+  return new(gCameraMemoryPool.AllocateRawThreadSafe()) Camera();
 }
 
 Camera::~Camera() = default;
 
-void Camera::SetNode(const Node* node)
+void Camera::operator delete(void* ptr)
 {
-  mNode = node;
-}
-
-const Node* Camera::GetNode() const
-{
-  return mNode;
+  gCameraMemoryPool.FreeThreadSafe(static_cast<Camera*>(ptr));
 }
 
 void Camera::SetType(Dali::Camera::Type type)
@@ -205,45 +226,33 @@ void Camera::SetProjectionMode(Dali::Camera::ProjectionMode mode)
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void Camera::SetInvertYAxis(bool invertYAxis)
+void Camera::SetProjectionDirection(Dali::DevelCameraActor::ProjectionDirection direction)
 {
-  mInvertYAxis          = invertYAxis;
-  mUpdateProjectionFlag = UPDATE_COUNT;
-}
-
-void Camera::SetFieldOfView(float fieldOfView)
-{
-  mFieldOfView          = fieldOfView;
+  mProjectionDirection  = direction;
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void Camera::SetAspectRatio(float aspectRatio)
-{
-  mAspectRatio          = aspectRatio;
-  mUpdateProjectionFlag = UPDATE_COUNT;
-}
-
-void Camera::SetLeftClippingPlane(float leftClippingPlane)
+void Camera::SetInvertYAxis(bool invertYAxis)
 {
-  mLeftClippingPlane    = leftClippingPlane;
+  mInvertYAxis          = invertYAxis;
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void Camera::SetRightClippingPlane(float rightClippingPlane)
+void Camera::BakeFieldOfView(BufferIndex updateBufferIndex, float fieldOfView)
 {
-  mRightClippingPlane   = rightClippingPlane;
+  mFieldOfView.Bake(updateBufferIndex, fieldOfView);
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void Camera::SetTopClippingPlane(float topClippingPlane)
+void Camera::BakeOrthographicSize(BufferIndex updateBufferIndex, float orthographicSize)
 {
-  mTopClippingPlane     = topClippingPlane;
+  mOrthographicSize.Bake(updateBufferIndex, orthographicSize);
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void Camera::SetBottomClippingPlane(float bottomClippingPlane)
+void Camera::BakeAspectRatio(BufferIndex updateBufferIndex, float aspectRatio)
 {
-  mBottomClippingPlane  = bottomClippingPlane;
+  mAspectRatio.Bake(updateBufferIndex, aspectRatio);
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
@@ -352,6 +361,21 @@ const Matrix& Camera::GetFinalProjectionMatrix(BufferIndex bufferIndex) const
   return mFinalProjection[bufferIndex];
 }
 
+const PropertyBase* Camera::GetFieldOfView() const
+{
+  return &mFieldOfView;
+}
+
+const PropertyBase* Camera::GetOrthographicSize() const
+{
+  return &mOrthographicSize;
+}
+
+const PropertyBase* Camera::GetAspectRatio() const
+{
+  return &mAspectRatio;
+}
+
 const PropertyInputImpl* Camera::GetProjectionMatrix() const
 {
   return &mProjectionMatrix;
@@ -364,12 +388,12 @@ const PropertyInputImpl* Camera::GetViewMatrix() const
 
 void Camera::Update(BufferIndex updateBufferIndex)
 {
-  // if owning node has changes in world position we need to update camera for next 2 frames
-  if(mNode->IsLocalMatrixDirty())
+  // if this has changes in world position we need to update camera for next 2 frames
+  if(IsLocalMatrixDirty())
   {
     mUpdateViewFlag = UPDATE_COUNT;
   }
-  if(mNode->GetDirtyFlags() & NodePropertyFlags::VISIBLE)
+  if(GetDirtyFlags() & NodePropertyFlags::VISIBLE)
   {
     // If the visibility changes, the projection matrix needs to be re-calculated.
     // It may happen the first time an actor is rendered it's rendered only once and becomes invisible,
@@ -378,6 +402,12 @@ void Camera::Update(BufferIndex updateBufferIndex)
     mUpdateProjectionFlag = UPDATE_COUNT;
   }
 
+  // If projection matrix relative properties are animated now, flag change.
+  if(IsProjectionMatrixAnimated())
+  {
+    mUpdateProjectionFlag = UPDATE_COUNT;
+  }
+
   // if either matrix changed, we need to recalculate the inverse matrix for hit testing to work
   uint32_t viewUpdateCount       = UpdateViewMatrix(updateBufferIndex);
   uint32_t projectionUpdateCount = UpdateProjection(updateBufferIndex);
@@ -386,7 +416,7 @@ void Camera::Update(BufferIndex updateBufferIndex)
   if(viewUpdateCount > COPY_PREVIOUS_MATRIX || projectionUpdateCount > COPY_PREVIOUS_MATRIX)
   {
     // either has actually changed so recalculate
-    Matrix::Multiply(mInverseViewProjection[updateBufferIndex], mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
+    MatrixUtils::Multiply(mInverseViewProjection[updateBufferIndex], mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
     UpdateFrustum(updateBufferIndex);
 
     // ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
@@ -401,11 +431,18 @@ void Camera::Update(BufferIndex updateBufferIndex)
   }
 }
 
-bool Camera::ViewMatrixUpdated()
+bool Camera::ViewMatrixUpdated() const
 {
   return 0u != mUpdateViewFlag;
 }
 
+bool Camera::IsProjectionMatrixAnimated() const
+{
+  return !mFieldOfView.IsClean() ||
+         !mOrthographicSize.IsClean() ||
+         !mAspectRatio.IsClean();
+}
+
 uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
 {
   uint32_t retval(mUpdateViewFlag);
@@ -424,11 +461,11 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
         case Dali::Camera::FREE_LOOK:
         {
           Matrix& viewMatrix = mViewMatrix.Get(updateBufferIndex);
-          viewMatrix         = mNode->GetWorldMatrix(updateBufferIndex);
+          viewMatrix         = GetWorldMatrix(updateBufferIndex);
 
           if(mUseReflection)
           {
-            const Matrix& owningNodeMatrix(mNode->GetWorldMatrix(updateBufferIndex));
+            const Matrix& owningNodeMatrix(GetWorldMatrix(updateBufferIndex));
             Vector3       position{}, scale{};
             Quaternion    orientation{};
             owningNodeMatrix.GetTransformComponents(position, orientation, scale);
@@ -437,7 +474,7 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
 
             Matrix& viewMatrix = mViewMatrix.Get(updateBufferIndex);
             Matrix  oldViewMatrix(viewMatrix);
-            Matrix::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
+            MatrixUtils::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
           }
 
           viewMatrix.Invert();
@@ -448,7 +485,7 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
         // camera orientation constrained to look at a target
         case Dali::Camera::LOOK_AT_TARGET:
         {
-          const Matrix& owningNodeMatrix(mNode->GetWorldMatrix(updateBufferIndex));
+          const Matrix& owningNodeMatrix(GetWorldMatrix(updateBufferIndex));
           Vector3       position, scale;
           Quaternion    orientation;
           owningNodeMatrix.GetTransformComponents(position, orientation, scale);
@@ -480,7 +517,7 @@ uint32_t Camera::UpdateViewMatrix(BufferIndex updateBufferIndex)
             Matrix oldViewMatrix(viewMatrix);
             Matrix tmp;
             tmp.SetIdentityAndScale(Vector3(-1.0, 1.0, 1.0));
-            Matrix::Multiply(viewMatrix, oldViewMatrix, tmp);
+            MatrixUtils::Multiply(viewMatrix, oldViewMatrix, tmp);
 
             mReflectionEye     = positionNew;
             mUseReflectionClip = true;
@@ -503,7 +540,7 @@ void Camera::UpdateFrustum(BufferIndex updateBufferIndex, bool normalize)
 {
   // Extract the clip matrix planes
   Matrix clipMatrix;
-  Matrix::Multiply(clipMatrix, mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
+  MatrixUtils::Multiply(clipMatrix, mViewMatrix[updateBufferIndex], mProjectionMatrix[updateBufferIndex]);
 
   const float*   cm     = clipMatrix.AsFloat();
   FrustumPlanes& planes = mFrustum[updateBufferIndex];
@@ -567,7 +604,7 @@ void Camera::UpdateFrustum(BufferIndex updateBufferIndex, bool normalize)
   mFrustum[updateBufferIndex ? 0 : 1] = planes;
 }
 
-bool Camera::CheckSphereInFrustum(BufferIndex bufferIndex, const Vector3& origin, float radius)
+bool Camera::CheckSphereInFrustum(BufferIndex bufferIndex, const Vector3& origin, float radius) const
 {
   const FrustumPlanes& planes = mFrustum[bufferIndex];
   for(uint32_t i = 0; i < 6; ++i)
@@ -580,7 +617,7 @@ bool Camera::CheckSphereInFrustum(BufferIndex bufferIndex, const Vector3& origin
   return true;
 }
 
-bool Camera::CheckAABBInFrustum(BufferIndex bufferIndex, const Vector3& origin, const Vector3& halfExtents)
+bool Camera::CheckAABBInFrustum(BufferIndex bufferIndex, const Vector3& origin, const Vector3& halfExtents) const
 {
   const FrustumPlanes& planes = mFrustum[bufferIndex];
   for(uint32_t i = 0; i < 6; ++i)
@@ -594,6 +631,16 @@ bool Camera::CheckAABBInFrustum(BufferIndex bufferIndex, const Vector3& origin,
   }
   return true;
 }
+Dali::Rect<int32_t> Camera::GetOrthographicClippingBox(BufferIndex bufferIndex) const
+{
+  const float orthographicSize = mOrthographicSize[bufferIndex];
+  const float aspect           = mAspectRatio[bufferIndex];
+
+  const float halfWidth  = mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? orthographicSize * aspect : orthographicSize;
+  const float halfHeight = mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? orthographicSize : orthographicSize / aspect;
+
+  return Dali::Rect<int32_t>(-halfWidth, -halfHeight, halfWidth * 2.0f, halfHeight * 2.0f);
+}
 
 uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
 {
@@ -619,8 +666,9 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
         {
           Matrix& projectionMatrix = mProjectionMatrix.Get(updateBufferIndex);
           Perspective(projectionMatrix,
-                      mFieldOfView,
-                      mAspectRatio,
+                      mProjectionDirection,
+                      mFieldOfView[updateBufferIndex],
+                      mAspectRatio[updateBufferIndex],
                       mNearClippingPlane,
                       mFarClippingPlane,
                       mInvertYAxis);
@@ -648,7 +696,7 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
             matZ.SetIdentity();
             float* vZ = matZ.AsFloat();
             vZ[10]    = -vZ[10];
-            Matrix::Multiply(projectionMatrix, projectionMatrix, matZ);
+            MatrixUtils::Multiply(projectionMatrix, projectionMatrix, matZ);
           }
           break;
         }
@@ -656,10 +704,9 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
         {
           Matrix& projectionMatrix = mProjectionMatrix.Get(updateBufferIndex);
           Orthographic(projectionMatrix,
-                       mLeftClippingPlane,
-                       mRightClippingPlane,
-                       mBottomClippingPlane,
-                       mTopClippingPlane,
+                       mProjectionDirection,
+                       mOrthographicSize[updateBufferIndex],
+                       mAspectRatio[updateBufferIndex],
                        mNearClippingPlane,
                        mFarClippingPlane,
                        mInvertYAxis);
@@ -696,7 +743,7 @@ uint32_t Camera::UpdateProjection(BufferIndex updateBufferIndex)
       rotation.SetIdentity();
       rotation.SetTransformComponents(Vector3(1.0f, 1.0f, 1.0f), rotationAngle, Vector3(0.0f, 0.0f, 0.0f));
 
-      Matrix::Multiply(finalProjection, mProjectionMatrix.Get(updateBufferIndex), rotation);
+      MatrixUtils::Multiply(finalProjection, mProjectionMatrix.Get(updateBufferIndex), rotation);
     }
     --mUpdateProjectionFlag;
   }