/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace // unnamed namespace
{
-const unsigned int UPDATE_COUNT = 2u; // Update projection or view matrix this many frames after a change
-const unsigned int COPY_PREVIOUS_MATRIX = 1u; // Copy view or projection matrix from previous frame
+const uint32_t UPDATE_COUNT = 2u; // Update projection or view matrix this many frames after a change
+const uint32_t COPY_PREVIOUS_MATRIX = 1u; // Copy view or projection matrix from previous frame
}
namespace Dali
namespace
{
+template< typename T >
+T Sign( T value )
+{
+ return T( T(0) < value ) - T( value < T(0) );
+}
+
void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
{
Vector3 vZ = target - eye;
result.SetInverseTransformComponents(vX, vY, vZ, eye);
}
-
void Frustum(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
{
float deltaZ = far - near;
if ((near <= 0.0f) || (far <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
{
- DALI_LOG_ERROR("Invalid parameters passed into Frustum!");
+ DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
return;
}
m[12] = m[13] = m[15] = 0.0f;
}
-void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis, const Vector2& stereoBias )
+void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis )
{
float frustumH = tanf( fovy * 0.5f ) * near;
float frustumW = frustumH * aspect;
- Vector2 bias = stereoBias * 0.5f;
- Frustum(result, -(frustumW + bias.x), frustumW - bias.x, -(frustumH + bias.y), frustumH - bias.y, near, far, invertYAxis);
+ 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)
{
if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) )
{
- DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension." );
+ 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;
}
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*(M_PI/180.0f) );
+const float Camera::DEFAULT_FIELD_OF_VIEW( 45.0f*(Math::PI/180.0f) );
const float Camera::DEFAULT_ASPECT_RATIO( 4.0f/3.0f );
const float Camera::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
const float Camera::DEFAULT_RIGHT_CLIPPING_PLANE(240.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 Vector2 Camera::DEFAULT_STEREO_BIAS( 0.0f, 0.0f );
const Vector3 Camera::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f );
Camera::Camera()
: mUpdateViewFlag( UPDATE_COUNT ),
mUpdateProjectionFlag( UPDATE_COUNT ),
+ mProjectionRotation( 0 ),
+ mNode( NULL ),
mType( DEFAULT_TYPE ),
mProjectionMode( DEFAULT_MODE ),
mInvertYAxis( DEFAULT_INVERT_Y_AXIS ),
mBottomClippingPlane( DEFAULT_BOTTOM_CLIPPING_PLANE ),
mNearClippingPlane( DEFAULT_NEAR_CLIPPING_PLANE ),
mFarClippingPlane( DEFAULT_FAR_CLIPPING_PLANE ),
- mStereoBias( DEFAULT_STEREO_BIAS ),
mTargetPosition( DEFAULT_TARGET_POSITION ),
mViewMatrix(),
mProjectionMatrix(),
- mInverseViewProjection( Matrix::IDENTITY )
+ mInverseViewProjection( Matrix::IDENTITY ),
+ mFinalProjection( Matrix::IDENTITY )
{
}
{
}
+void Camera::SetNode( const Node* node )
+{
+ mNode = node;
+}
+
void Camera::SetType( Dali::Camera::Type type )
{
mType = type;
mUpdateProjectionFlag = UPDATE_COUNT;
}
-void Camera::SetStereoBias( const Vector2& stereoBias )
-{
- mStereoBias = stereoBias;
- mUpdateProjectionFlag = UPDATE_COUNT;
-}
-
void Camera::SetLeftClippingPlane( float leftClippingPlane )
{
mLeftClippingPlane = leftClippingPlane;
mUpdateViewFlag = UPDATE_COUNT;
}
+void Camera::RotateProjection( int rotationAngle )
+{
+ mProjectionRotation = rotationAngle;
+ mUpdateViewFlag = UPDATE_COUNT;
+}
+
const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const
{
return mProjectionMatrix[ bufferIndex ];
return mInverseViewProjection[ bufferIndex ];
}
+const Matrix& Camera::GetFinalProjectionMatrix( BufferIndex bufferIndex ) const
+{
+ return mFinalProjection[ bufferIndex ];
+}
+
const PropertyInputImpl* Camera::GetProjectionMatrix() const
{
return &mProjectionMatrix;
return &mViewMatrix;
}
-void Camera::Update( BufferIndex updateBufferIndex, const Node& owningNode )
+void Camera::Update( BufferIndex updateBufferIndex )
{
// if owning node has changes in world position we need to update camera for next 2 frames
- if( owningNode.IsLocalMatrixDirty() )
+ if( mNode->IsLocalMatrixDirty() )
{
mUpdateViewFlag = UPDATE_COUNT;
}
- if( owningNode.GetDirtyFlags() & VisibleFlag )
+ if( mNode->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,
}
// if either matrix changed, we need to recalculate the inverse matrix for hit testing to work
- unsigned int viewUpdateCount = UpdateViewMatrix( updateBufferIndex, owningNode );
- unsigned int projectionUpdateCount = UpdateProjection( updateBufferIndex );
+ uint32_t viewUpdateCount = UpdateViewMatrix( updateBufferIndex );
+ uint32_t projectionUpdateCount = UpdateProjection( updateBufferIndex );
// if model or view matrix changed we need to either recalculate the inverse VP or copy previous
if( viewUpdateCount > COPY_PREVIOUS_MATRIX || projectionUpdateCount > COPY_PREVIOUS_MATRIX )
return 0u != mUpdateViewFlag;
}
-unsigned int Camera::UpdateViewMatrix( BufferIndex updateBufferIndex, const Node& owningNode )
+uint32_t Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
{
- unsigned int retval( mUpdateViewFlag );
+ uint32_t retval( mUpdateViewFlag );
if( 0u != mUpdateViewFlag )
{
if( COPY_PREVIOUS_MATRIX == mUpdateViewFlag )
case Dali::Camera::FREE_LOOK:
{
Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
- viewMatrix = owningNode.GetWorldMatrix( updateBufferIndex );
+ viewMatrix = mNode->GetWorldMatrix( updateBufferIndex );
viewMatrix.Invert();
mViewMatrix.SetDirty( updateBufferIndex );
break;
// camera orientation constrained to look at a target
case Dali::Camera::LOOK_AT_TARGET:
{
- const Matrix& owningNodeMatrix( owningNode.GetWorldMatrix( updateBufferIndex ) );
+ const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
Vector3 position, scale;
Quaternion orientation;
owningNodeMatrix.GetTransformComponents( position, orientation, scale );
if ( normalize )
{
- for ( unsigned int i = 0; i < 6; ++i )
+ for ( uint32_t i = 0; i < 6; ++i )
{
// Normalize planes to ensure correct bounding distance checking
Plane& plane = planes.mPlanes[ i ];
}
else
{
- for ( unsigned int i = 0; i < 6; ++i )
+ for ( uint32_t i = 0; i < 6; ++i )
{
planes.mSign[i] = Vector3( Sign(planes.mPlanes[ i ].mNormal.x), Sign(planes.mPlanes[ i ].mNormal.y), Sign(planes.mPlanes[ i ].mNormal.z) );
}
return true;
}
-unsigned int Camera::UpdateProjection( BufferIndex updateBufferIndex )
+uint32_t Camera::UpdateProjection( BufferIndex updateBufferIndex )
{
- unsigned int retval( mUpdateProjectionFlag );
+ uint32_t retval( mUpdateProjectionFlag );
// Early-exit if no update required
if ( 0u != mUpdateProjectionFlag )
{
mAspectRatio,
mNearClippingPlane,
mFarClippingPlane,
- mInvertYAxis,
- mStereoBias );
+ mInvertYAxis );
break;
}
case Dali::Camera::ORTHOGRAPHIC_PROJECTION:
}
mProjectionMatrix.SetDirty( updateBufferIndex );
+
+ Matrix &finalProjection = mFinalProjection[ updateBufferIndex ];
+ finalProjection.SetIdentity();
+
+ Quaternion rotationAngle;
+ switch( mProjectionRotation )
+ {
+ case 90:
+ {
+ rotationAngle = Quaternion( Dali::ANGLE_90, Vector3::ZAXIS );
+ break;
+ }
+ case 180:
+ {
+ rotationAngle = Quaternion( Dali::ANGLE_180, Vector3::ZAXIS );
+ break;
+ }
+ case 270:
+ {
+ rotationAngle = Quaternion( Dali::ANGLE_270, Vector3::ZAXIS );
+ break;
+ }
+ default:
+ rotationAngle = Quaternion( Dali::ANGLE_0, Vector3::ZAXIS );
+ break;
+ }
+
+ Matrix rotation;
+ 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 );
}
--mUpdateProjectionFlag;
}