[dali_1.2.40] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / path-impl.cpp
index 94477f2..865c4fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
 // CLASS HEADER
 #include <dali/internal/event/animation/path-impl.h>
 
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/common/property-helper.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/type-registry.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
 namespace
 {
+
+// Properties
+
+//              Name             Type   writable animatable constraint-input  enum for index-checking
+DALI_PROPERTY_TABLE_BEGIN
+DALI_PROPERTY( "points",         ARRAY, true, false, false,   Dali::Path::Property::POINTS         )
+DALI_PROPERTY( "controlPoints",  ARRAY, true, false, false,   Dali::Path::Property::CONTROL_POINTS )
+DALI_PROPERTY_TABLE_END( DEFAULT_OBJECT_PROPERTY_START_INDEX )
+
 /**
  * These coefficient arise from the cubic polynomial equations for
  * a bezier curve.
@@ -39,30 +62,19 @@ const float BezierBasisCoeff[] = {  -1.0f,  3.0f, -3.0f, 1.0f,
 
 const Dali::Matrix BezierBasis = Dali::Matrix( BezierBasisCoeff );
 
-struct PropertyDetails
+Dali::BaseHandle Create()
 {
-  std::string name;           ///< The name of the property.
-  Dali::Property::Type type;  ///< The property type.
-  bool writable:1;            ///< Whether the property is writable
-  bool animatable:1;          ///< Whether the property is animatable.
-  bool constraintInput:1;     ///< Whether the property can be used as an input to a constraint.
-};
-
-const PropertyDetails DEFAULT_PROPERTY_DETAILS[] =  {{"points", Dali::Property::ARRAY, true, false, false },
-                                                     {"control-points", Dali::Property::ARRAY, true, false, false },
-                                                    };
-
-const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_DETAILS ) / sizeof( PropertyDetails );
+  return Dali::Path::New();
+}
 
-}//Unnamed namespace
+Dali::TypeRegistration mType( typeid(Dali::Path), typeid(Dali::Handle), Create );
 
-namespace Dali
+inline bool PathIsComplete(const Dali::Vector<Vector3>& point, const Dali::Vector<Vector3>& controlPoint)
 {
-const Property::Index Path::POINTS              = 0;
-const Property::Index Path::CONTROL_POINTS      = 1;
+  return ( point.Size() > 1 && controlPoint.Size() == (point.Size()-1)*2 );
+}
 
-namespace Internal
-{
+} //Unnamed namespace
 
 Path* Path::New()
 {
@@ -70,7 +82,7 @@ Path* Path::New()
 }
 
 Path::Path()
-:ProxyObject()
+: Object()
 {
 }
 
@@ -94,35 +106,34 @@ unsigned int Path::GetDefaultPropertyCount() const
 
 void Path::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
 {
-  indices.reserve( DEFAULT_PROPERTY_COUNT );
+  indices.Reserve( DEFAULT_PROPERTY_COUNT );
 
   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
   {
-    indices.push_back( i );
+    indices.PushBack( i );
   }
 }
 
-const std::string& Path::GetDefaultPropertyName(Property::Index index) const
+const char* Path::GetDefaultPropertyName(Property::Index index) const
 {
   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
   {
     return DEFAULT_PROPERTY_DETAILS[index].name;
   }
-  else
-  {
-    // index out of range
-    static const std::string INVALID_PROPERTY_NAME;
-    return INVALID_PROPERTY_NAME;
-  }
+
+  // index out of range
+  return NULL;
 }
 
 Property::Index Path::GetDefaultPropertyIndex(const std::string& name) const
 {
   Property::Index index = Property::INVALID_INDEX;
 
-  for( int i(0); i<DEFAULT_PROPERTY_COUNT; ++i )
+  // Look for name in default properties
+  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
   {
-    if ( name == DEFAULT_PROPERTY_DETAILS[i].name )
+    const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
+    if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
     {
       index = i;
       break;
@@ -137,80 +148,79 @@ Property::Type Path::GetDefaultPropertyType(Property::Index index) const
   {
     return DEFAULT_PROPERTY_DETAILS[index].type;
   }
-  else
-  {
-    // index out of range
-    return Property::NONE;
-  }
+
+  // index out of range
+  return Property::NONE;
 }
 
 Property::Value Path::GetDefaultProperty( Property::Index index ) const
 {
-  Property::Value value;
-  switch ( index )
+  if( index == Dali::Path::Property::POINTS )
   {
-    case Dali::Path::POINTS:
+    Property::Value value( Property::ARRAY );
+    Property::Array* array = value.GetArray();
+    Property::Array::SizeType pointCount = mPoint.Count();
+
+    if( array )
     {
-      size_t pointCount( mPoint.Size() );
-      for( size_t i(0); i!=pointCount; ++i )
+      array->Reserve( pointCount );
+      for( Property::Array::SizeType i = 0; i < pointCount; ++i )
       {
-        value.AppendItem( mPoint[i] );
+        array->PushBack( mPoint[i] );
       }
-      break;
     }
-    case Dali::Path::CONTROL_POINTS:
+    return value;
+  }
+  else if( index == Dali::Path::Property::CONTROL_POINTS )
+  {
+    Property::Value value( Property::ARRAY );
+    Property::Array* array = value.GetArray();
+    Property::Array::SizeType  controlpointCount = mControlPoint.Count();
+
+    if( array )
     {
-      size_t controlpointCount( mControlPoint.Size() );
-      for( size_t i(0); i!=controlpointCount; ++i )
+      array->Reserve( controlpointCount );
+      for( Property::Array::SizeType i = 0; i < controlpointCount; ++i )
       {
-        value.AppendItem( mControlPoint[i] );
+        array->PushBack( mControlPoint[i] );
       }
-      break;
-    }
-    default:
-    {
-      DALI_ASSERT_ALWAYS(false && "Path::Property is out of bounds");
-      break;
     }
+    return value;
   }
 
-  return value;
+  return Property::Value();
+}
+
+Property::Value Path::GetDefaultPropertyCurrentValue( Property::Index index ) const
+{
+  return GetDefaultProperty( index ); // Event-side only properties
 }
 
 void Path::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
 {
-  switch ( index )
+  const Property::Array* array = propertyValue.GetArray();
+  if( array )
   {
-    case Dali::Path::POINTS:
+    Property::Array::SizeType propertyArrayCount = array->Count();
+    if( index == Dali::Path::Property::POINTS )
     {
-      Property::Array propertyArray;
-      propertyValue.Get(propertyArray);
-
-      size_t propertyArrayCount = propertyArray.size();
-      mPoint.Resize( propertyArrayCount );
-      for( size_t i(0); i!=propertyArrayCount; ++i )
+      mPoint.Reserve( propertyArrayCount );
+      for( Property::Array::SizeType i = 0; i < propertyArrayCount; ++i )
       {
-        propertyArray[i].Get( mPoint[i]);
+        Vector3 point;
+        array->GetElementAt( i ).Get( point );
+        mPoint.PushBack( point );
       }
-      break;
     }
-    case Dali::Path::CONTROL_POINTS:
+    else if( index == Dali::Path::Property::CONTROL_POINTS )
     {
-      Property::Array propertyArray;
-      propertyValue.Get(propertyArray);
-
-      size_t propertyArrayCount = propertyArray.size();
-      mControlPoint.Resize( propertyArrayCount );
-      for( size_t i(0); i!=propertyArrayCount; ++i )
+      mControlPoint.Reserve( propertyArrayCount );
+      for( Property::Array::SizeType i = 0; i < propertyArrayCount; ++i )
       {
-        propertyArray[i].Get( mControlPoint[i]);
+        Vector3 point;
+        array->GetElementAt( i ).Get( point );
+        mControlPoint.PushBack( point );
       }
-      break;
-    }
-    default:
-    {
-      DALI_ASSERT_ALWAYS(false && "Path::Property is out of bounds");
-      break;
     }
   }
 }
@@ -221,10 +231,8 @@ bool Path::IsDefaultPropertyWritable(Property::Index index) const
   {
     return DEFAULT_PROPERTY_DETAILS[index].writable;
   }
-  else
-  {
-    return false;
-  }
+
+  return false;
 }
 
 bool Path::IsDefaultPropertyAnimatable(Property::Index index) const
@@ -233,10 +241,8 @@ bool Path::IsDefaultPropertyAnimatable(Property::Index index) const
   {
     return DEFAULT_PROPERTY_DETAILS[index].animatable;
   }
-  else
-  {
-    return false;
-  }
+
+  return false;
 }
 
 bool Path::IsDefaultPropertyAConstraintInput( Property::Index index ) const
@@ -245,10 +251,8 @@ bool Path::IsDefaultPropertyAConstraintInput( Property::Index index ) const
   {
     return DEFAULT_PROPERTY_DETAILS[index].constraintInput;
   }
-  else
-  {
-    return false;
-  }
+
+  return false;
 }
 
 void Path::AddPoint(const Vector3& point )
@@ -330,7 +334,7 @@ void Path::FindSegmentAndProgress( float t, unsigned int& segment, float& tLocal
   //Find segment and local progress
   unsigned int numSegs = GetNumberOfSegments();
 
-  if( t <= 0.0f )
+  if( t <= 0.0f || numSegs == 0 )
   {
     segment = 0;
     tLocal = 0.0f;
@@ -344,168 +348,191 @@ void Path::FindSegmentAndProgress( float t, unsigned int& segment, float& tLocal
   {
     segment = t * numSegs;
     float segLength = 1.0f / numSegs;
-    float segStart  = (float)segment * segLength;
+    float segStart  = static_cast<float>( segment ) * segLength;
     tLocal = (t - segStart) * numSegs;
   }
 }
 
 void Path::Sample( float t, Vector3& position, Vector3& tangent ) const
 {
-  DALI_ASSERT_ALWAYS(mPoint.Size() > 1 && mControlPoint.Size() == (mPoint.Size()-1)*2 && "Spline not fully initialized" );
-
-  unsigned int segment;
-  float tLocal;
-  FindSegmentAndProgress( t, segment, tLocal );
-
-  //Get points and control points in the segment
-  const Vector3& controlPoint0 = mControlPoint[2*segment];
-  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
-  const Vector3& point0 = mPoint[segment];
-  const Vector3& point1 = mPoint[segment+1];
-
-  if(tLocal < Math::MACHINE_EPSILON_1)
+  if( !SampleAt(t, position, tangent) )
   {
-    position = point0;
-    tangent = ( controlPoint0 - point0 ) * 3.0f;
-    tangent.Normalize();
-  }
-  else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
-  {
-    position = point1;
-    tangent = ( point1 - controlPoint1 ) * 3.0f;
-    tangent.Normalize();
+    DALI_ASSERT_ALWAYS(!"Spline not fully initialized" );
   }
-  else
+}
+
+bool Path::SampleAt( float t, Vector3& position, Vector3& tangent ) const
+{
+  bool done = false;
+
+  if( PathIsComplete(mPoint, mControlPoint) )
   {
-    const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
-    const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
+    unsigned int segment;
+    float tLocal;
+    FindSegmentAndProgress( t, segment, tLocal );
+
+    //Get points and control points in the segment
+    const Vector3& controlPoint0 = mControlPoint[2*segment];
+    const Vector3& controlPoint1 = mControlPoint[2*segment+1];
+    const Vector3& point0 = mPoint[segment];
+    const Vector3& point1 = mPoint[segment+1];
+
+    if(tLocal < Math::MACHINE_EPSILON_1)
+    {
+      position = point0;
+      tangent = ( controlPoint0 - point0 ) * 3.0f;
+      tangent.Normalize();
+    }
+    else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
+    {
+      position = point1;
+      tangent = ( point1 - controlPoint1 ) * 3.0f;
+      tangent.Normalize();
+    }
+    else
+    {
+      const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
+      const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
 
-    //X
-    Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
+      //X
+      Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
 
-    Vector4 A = BezierBasis * cVect;
-    position.x = sVect.Dot4(A);
-    tangent.x  = sVectDerivative.Dot(Vector3(A));
+      Vector4 A = BezierBasis * cVect;
+      position.x = sVect.Dot4(A);
+      tangent.x  = sVectDerivative.Dot(Vector3(A));
 
-    //Y
-    cVect.x  = point0.y;
-    cVect.y  = controlPoint0.y;
-    cVect.z  = controlPoint1.y;
-    cVect.w  = point1.y;
+      //Y
+      cVect.x  = point0.y;
+      cVect.y  = controlPoint0.y;
+      cVect.z  = controlPoint1.y;
+      cVect.w  = point1.y;
 
-    A = BezierBasis * cVect;
-    position.y = sVect.Dot4(A);
-    tangent.y  = sVectDerivative.Dot(Vector3(A));
+      A = BezierBasis * cVect;
+      position.y = sVect.Dot4(A);
+      tangent.y  = sVectDerivative.Dot(Vector3(A));
 
-    //Z
-    cVect.x  = point0.z;
-    cVect.y  = controlPoint0.z;
-    cVect.z  = controlPoint1.z;
-    cVect.w  = point1.z;
+      //Z
+      cVect.x  = point0.z;
+      cVect.y  = controlPoint0.z;
+      cVect.z  = controlPoint1.z;
+      cVect.w  = point1.z;
 
-    A = BezierBasis * cVect;
-    position.z = sVect.Dot4(A);
-    tangent.z  = sVectDerivative.Dot(Vector3(A));
+      A = BezierBasis * cVect;
+      position.z = sVect.Dot4(A);
+      tangent.z  = sVectDerivative.Dot(Vector3(A));
 
-    tangent.Normalize();
+      tangent.Normalize();
+    }
+
+    done = true;
   }
+
+  return done;
 }
 
-Vector3 Path::SamplePosition( float t ) const
+bool Path::SamplePosition( float t, Vector3& position ) const
 {
-  DALI_ASSERT_ALWAYS(mPoint.Size() > 1 && mControlPoint.Size() == (mPoint.Size()-1)*2 && "Spline not fully initialized" );
+  bool done = false;
 
-  unsigned int segment;
-  float tLocal;
-  FindSegmentAndProgress( t, segment, tLocal );
+  if( PathIsComplete(mPoint, mControlPoint) )
+  {
+    unsigned int segment;
+    float tLocal;
+    FindSegmentAndProgress( t, segment, tLocal );
 
-  const Vector3& controlPoint0 = mControlPoint[2*segment];
-  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
-  const Vector3& point0 = mPoint[segment];
-  const Vector3& point1 = mPoint[segment+1];
+    const Vector3& controlPoint0 = mControlPoint[2*segment];
+    const Vector3& controlPoint1 = mControlPoint[2*segment+1];
+    const Vector3& point0 = mPoint[segment];
+    const Vector3& point1 = mPoint[segment+1];
 
-  Vector3 position;
-  if(tLocal < Math::MACHINE_EPSILON_1)
-  {
-    position = point0;
-  }
-  else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
-  {
-    position = point1;
-  }
-  else
-  {
-    const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
-
-    //X
-    Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
-    position.x = sVect.Dot4(BezierBasis * cVect);
-
-    //Y
-    cVect.x  = point0.y;
-    cVect.y  = controlPoint0.y;
-    cVect.z  = controlPoint1.y;
-    cVect.w  = point1.y;
-    position.y = sVect.Dot4(BezierBasis * cVect);
-
-    //Z
-    cVect.x  = point0.z;
-    cVect.y  = controlPoint0.z;
-    cVect.z  = controlPoint1.z;
-    cVect.w  = point1.z;
-    position.z = sVect.Dot4(BezierBasis * cVect);
+    if(tLocal < Math::MACHINE_EPSILON_1)
+    {
+      position = point0;
+    }
+    else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
+    {
+      position = point1;
+    }
+    else
+    {
+      const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
+
+      //X
+      Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
+      position.x = sVect.Dot4(BezierBasis * cVect);
+
+      //Y
+      cVect.x  = point0.y;
+      cVect.y  = controlPoint0.y;
+      cVect.z  = controlPoint1.y;
+      cVect.w  = point1.y;
+      position.y = sVect.Dot4(BezierBasis * cVect);
+
+      //Z
+      cVect.x  = point0.z;
+      cVect.y  = controlPoint0.z;
+      cVect.z  = controlPoint1.z;
+      cVect.w  = point1.z;
+      position.z = sVect.Dot4(BezierBasis * cVect);
+    }
+
+    done = true;
   }
 
-  return position;
+  return done;
 }
 
-Vector3 Path::SampleTangent( float t ) const
+bool Path::SampleTangent( float t, Vector3& tangent ) const
 {
-  DALI_ASSERT_ALWAYS(mPoint.Size() > 1 && mControlPoint.Size() == (mPoint.Size()-1)*2 && "Spline not fully initialized" );
+  bool done = false;
 
-  unsigned int segment;
-  float tLocal;
-  FindSegmentAndProgress( t, segment, tLocal );
+  if( PathIsComplete(mPoint, mControlPoint) )
+  {
+    unsigned int segment;
+    float tLocal;
+    FindSegmentAndProgress( t, segment, tLocal );
 
-  const Vector3& controlPoint0 = mControlPoint[2*segment];
-  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
-  const Vector3& point0 = mPoint[segment];
-  const Vector3& point1 = mPoint[segment+1];
+    const Vector3& controlPoint0 = mControlPoint[2*segment];
+    const Vector3& controlPoint1 = mControlPoint[2*segment+1];
+    const Vector3& point0 = mPoint[segment];
+    const Vector3& point1 = mPoint[segment+1];
 
-  Vector3 tangent;
-  if(tLocal < Math::MACHINE_EPSILON_1)
-  {
-    tangent = ( controlPoint0 - point0 ) * 3.0f;
-  }
-  else if( (1.0f - tLocal) < Math::MACHINE_EPSILON_1)
-  {
-    tangent = ( point1 - controlPoint1 ) * 3.0f;
-  }
-  else
-  {
-    const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
-
-    //X
-    Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
-    tangent.x  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
-
-    //Y
-    cVect.x  = point0.y;
-    cVect.y  = controlPoint0.y;
-    cVect.z  = controlPoint1.y;
-    cVect.w  = point1.y;
-    tangent.y  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
-
-    //Z
-    cVect.x  = point0.z;
-    cVect.y  = controlPoint0.z;
-    cVect.z  = controlPoint1.z;
-    cVect.w  = point1.z;
-    tangent.z  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
+    if(tLocal < Math::MACHINE_EPSILON_1)
+    {
+      tangent = ( controlPoint0 - point0 ) * 3.0f;
+    }
+    else if( (1.0f - tLocal) < Math::MACHINE_EPSILON_1)
+    {
+      tangent = ( point1 - controlPoint1 ) * 3.0f;
+    }
+    else
+    {
+      const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
+
+      //X
+      Vector4  cVect( point0.x, controlPoint0.x, controlPoint1.x,  point1.x);
+      tangent.x  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
+
+      //Y
+      cVect.x  = point0.y;
+      cVect.y  = controlPoint0.y;
+      cVect.z  = controlPoint1.y;
+      cVect.w  = point1.y;
+      tangent.y  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
+
+      //Z
+      cVect.x  = point0.z;
+      cVect.y  = controlPoint0.z;
+      cVect.z  = controlPoint1.z;
+      cVect.w  = point1.z;
+      tangent.z  = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
+    }
+
+    tangent.Normalize();
+    done = true;
   }
 
-  tangent.Normalize();
-  return tangent;
+  return done;
 }
 
 Vector3& Path::GetPoint( size_t index )
@@ -527,7 +554,15 @@ size_t Path::GetPointCount() const
   return mPoint.Size();
 }
 
-} // Internal
-} // Dali
+void Path::ClearPoints()
+{
+  mPoint.Clear();
+}
 
+void Path::ClearControlPoints()
+{
+  mControlPoint.Clear();
+}
 
+} // Internal
+} // Dali