       

typedef struct xyz_f
{
  union
  {
    float n[3];
    struct
    {
      float x,y,z;
    };

  };
} xyz_f;


class FBXMatrix;

class FBXVector3 : public xyz_f
{
public:
  FBXVector3() {}
  //FBXVector3( CONST float * )

  FBXVector3( float a, float b, float c )
  {
    x = a;
    y = b;
    z = c;
  }

  void set( float a, float b, float c )
  {
    x = a;
    y = b;
    z = c;
  }



  // casting
  //operator float* ();
  //operator CONST float* () const;

  // assignment operators
  FBXVector3& operator += ( CONST FBXVector3& v)
  {
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
  }
  FBXVector3& operator -= ( CONST FBXVector3& v)
  {
    x -= v.x;
    y -= v.y;
    z -= v.z;
    return *this;
  }
  FBXVector3& operator *= ( float s)
  {
    x *= s;
    y *= s;
    z *= s;
    return *this;
  }
  FBXVector3& operator /= ( float s)
  {
    x /= s;
    y /= s;
    z /= s;
    return *this;
  }


  void normalize( )
  {
    double u = x * x + y * y + z * z;
    if (u == 0.0 || u == 1.0)
      return;

    u = 1.0 / sqrt(u);
    x *= u;
    y *= u;
    z *= u;
  }


  
  friend FBXVector3 operator * (const FBXMatrix& m, const FBXVector3& v);      // M * v


  // unary operators
  //FBXVector3 operator + () const
  //FBXVector3 operator - () const;

  // binary operators
  //FBXVector3 operator + ( CONST FBXVector3& ) const;
  //FBXVector3 operator - ( CONST FBXVector3& ) const;
  //FBXVector3 operator * ( float ) const;
  //FBXVector3 operator / ( float ) const;

  friend FBXVector3 operator * ( float s, CONST FBXVector3& v)
  {
    return FBXVector3(s*v.x, s*v.y, s*v.z);


  }
  friend FBXVector3 operator * ( CONST FBXVector3& v, float s)
  {
    return FBXVector3(s*v.x, s*v.y, s*v.z);


  }
  friend FBXVector3 operator / ( CONST FBXVector3& v, float s)
  {
    return FBXVector3(v.x/s, v.y/s, v.z/s);


  }

  friend FBXVector3 operator - (const FBXVector3& v1, const FBXVector3& v2)
  {
    return FBXVector3(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z);

  }

  friend FBXVector3 operator + (const FBXVector3& v1, const FBXVector3& v2)
  {
    return FBXVector3(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z);

  }
  //BOOL operator == ( CONST D3DXVECTOR3& ) const;
  //BOOL operator != ( CONST FBXVector3& ) const;

  float& operator [] ( int i) { return n[i]; };       // indexing
  const float& operator[](int i) const { return n[i];}

  friend bool operator < (const FBXVector3& v1, const FBXVector3& v2)
  {
    if (v1.x < v2.x)
      return true;
    if (v1.x > v2.x)
      return false;

    if (v1.y < v2.y)
      return true;
    if (v1.y > v2.y)
      return false;

    if (v1.z < v2.z)
      return true;
    if (v1.z > v2.z)
      return false;

    return false;
  }
  friend bool operator > (const FBXVector3& v1, const FBXVector3& v2)
  {
    if (v1.x > v2.x)
      return true;
    if (v1.x < v2.x)
      return false;

    if (v1.y > v2.y)
      return true;
    if (v1.y < v2.y)
      return false;

    if (v1.z > v2.z)
      return true;
    if (v1.z < v2.z)
      return false;

    return false;
  }


} ;

class FBXMatrix;




inline FBXVector3* FBXVec3Subtract( FBXVector3 *pOut, CONST FBXVector3 *pV1, CONST FBXVector3 *pV2 )
{
#ifdef _DEBUG
    if(!pOut || !pV1 || !pV2)
        return NULL;
#endif

    pOut->x = pV1->x - pV2->x;
    pOut->y = pV1->y - pV2->y;
    pOut->z = pV1->z - pV2->z;
    return pOut;
}          


class FBXQuaternion
{
public:
  union
  {
    float n[4];
    struct
    {
      float i,j,k,s;
    };

  };        

  FBXQuaternion & operator *= ( const double d )
  { 
    i *= d; 
    j *= d; 
    k *= d; 
    s *= d; 
    return *this; 
  }
  FBXQuaternion operator - (const FBXQuaternion& a)
  { 
    return FBXQuaternion(-a.i, -a.j, -a.k, -a.s); 
  }


  friend FBXQuaternion operator + (const FBXQuaternion& a, const FBXQuaternion& b)
  { 
    return FBXQuaternion( a.i + b.i, a.j + b.j, a.k + b.k, a.s + b.s); 
  }


  friend FBXQuaternion operator - (const FBXQuaternion& a, const FBXQuaternion& b)
  { 
    return FBXQuaternion(
      a.i - b.i, 
      a.j - b.j, 
      a.k - b.k,
      a.s - b.s); 
  }

  friend FBXQuaternion operator * (const FBXQuaternion& a, const float d)
  { 
    return FBXQuaternion(d * a.i, d * a.j, d * a.k, d* a.s ); 
  }

  
  friend FBXQuaternion operator * (const float d, const FBXQuaternion& a)
  {
    return  a * d; 
  }



  friend FBXQuaternion operator *(const FBXQuaternion &qLeft, const FBXQuaternion &qRight)
  {
    FBXQuaternion temp;

    temp.s = qLeft.s * qRight.s - qLeft.i * qRight.i -
      qLeft.j * qRight.j - qLeft.k * qRight.k;

    temp.i = qLeft.s * qRight.i + qLeft.i * qRight.s +
      qLeft.j * qRight.k - qLeft.k * qRight.j;

    temp.j = qLeft.s * qRight.j + qLeft.j * qRight.s +
      qLeft.k * qRight.i - qLeft.i * qRight.k;

    temp.k = qLeft.s * qRight.k + qLeft.k * qRight.s +
      qLeft.i * qRight.j - qLeft.j * qRight.i;

    return temp;
  } 


  FBXQuaternion()
  {
  }
  FBXQuaternion(double _i, double _j, double _k, double _s)
  {
    i = _i;
    j = _j;
    k = _k;
    s = _s;
  }

  void GetColMatrix(FBXMatrix & m) const;
  void GetRowMatrix(FBXMatrix & m) const;


  void normalize()
  {
    double u;
    u = (double)(i * i + j * j + k * k + s * s);

    if (fabs(u - 1.0) < DBL_EPSILON)
      return; // already normalized

    if (fabs(u) < DBL_EPSILON)
    {
      i = j = k = 0.0;
      s = 1;
      return;
    }

    u = 1.0 / sqrt(u);

    i *= u;
    j *= u;
    k *= u;
    s *= u;

  }

};



class FBXVector2
{
public:
  union
  {
    float n[2];
    struct
    {
      float x,y;
    };

  };
  FBXVector2(double a, double b)
  {
    x = a;
    y = b;
  }

  FBXVector2()
  {
  }
  friend FBXVector2 operator - (const FBXVector2& v1, const FBXVector2& v2);


  float& operator [] ( int i) { return n[i]; };       // indexing
  const float& operator[](int i) const { return n[i];}


  friend bool operator < (const FBXVector2& v1, const FBXVector2& v2)
  {
    if (v1.x < v2.x)
      return true;
    if (v1.x > v2.x)
      return false;

    if (v1.y < v2.y)
      return true;
    if (v1.y > v2.y)
      return false;

    return false;
  }

  friend bool operator > (const FBXVector2& v1, const FBXVector2& v2)
  {
    if (v1.x > v2.x)
      return true;
    if (v1.x < v2.x)
      return false;

    if (v1.y > v2.y)
      return true;
    if (v1.y < v2.y)
      return false;

    return false;
  }
};


class FBXVector4
{
public:
  union
  {
    float n[4];
    struct
    {
      float x,y,z,w;
    };

  };
  FBXVector4(double a, double b, double c, double d)
  {
    x = a;
    y = b;
    z = c;
    w = d;
  }

  void Homogenize( void )
  {
    double u = 1.0 / w;
    x *= u;
    y *= u;
    z *= u;
  }
  void set(float a, float b, float c, float d)
  {
    x = a;
    y = b;
    z = c;
    w = d;
  }


  FBXVector4()
  {
  }
  friend FBXVector4 operator - (const FBXVector4& v1, const FBXVector4& v2);
  friend FBXVector4 operator * (const FBXMatrix& m, const FBXVector4& v);      // M * v
  friend FBXVector4 operator * (const FBXVector4& v, const FBXMatrix& m);      // (M * v)T


  float& operator [] ( int i) { return n[i]; };       // indexing
  const float& operator[](int i) const { return n[i];}

  friend bool operator < (const FBXVector4 & v1, const FBXVector4& v2)
  {
    if (v1.x < v2.x)
      return true;
    if (v1.x > v2.x)
      return false;

    if (v1.y < v2.y)
      return true;
    if (v1.y > v2.y)
      return false;

    if (v1.z < v2.z)
      return true;
    if (v1.z > v2.z)
      return false;

    if (v1.w < v2.w)
      return true;
    if (v1.w > v2.w)
      return false;

    return false;
  }


  friend bool operator > (const FBXVector4 & v1, const FBXVector4& v2)
  {
    if (v1.x > v2.x)
      return true;
    if (v1.x < v2.x)
      return false;

    if (v1.y > v2.y)
      return true;
    if (v1.y < v2.y)
      return false;

    if (v1.z > v2.z)
      return true;
    if (v1.z < v2.z)
      return false;

    if (v1.w > v2.w)
      return true;
    if (v1.w < v2.w)
      return false;

    return false;
  }
};



#define XX row[0].x
#define XY row[0].y
#define XZ row[0].z
#define XW row[0].w

#define YX row[1].x
#define YY row[1].y
#define YZ row[1].z
#define YW row[1].w

#define ZX row[2].x
#define ZY row[2].y
#define ZZ row[2].z
#define ZW row[2].w

#define WX row[3].x
#define WY row[3].y
#define WZ row[3].z
#define WW row[3].w


class FBXMatrix
{
public:


  FBXMatrix()
  {
  }    

  FBXMatrix( float a0,  float b0,  float c0, float d0,
    float a1,  float b1,  float c1, float d1,
    float a2,  float b2,  float c2, float d2,
    float a3,  float b3,  float c3, float d3)
  {
    XX = a0;
    XY = b0;
    XZ = c0;
    XW = d0;


    YX = a1;
    YY = b1;
    YZ = c1;
    YW = d1;


    ZX = a2;
    ZY = b2;
    ZZ = c2;
    ZW = d2;


    WX = a3;
    WY = b3;
    WZ = c3;
    WW = d3;
  }

  FBXVector4 row[4];

  // assignment operators
  FBXMatrix& operator *= ( CONST FBXMatrix& );
  FBXMatrix& operator += ( CONST FBXMatrix& );
  FBXMatrix& operator -= ( CONST FBXMatrix& );
  FBXMatrix& operator *= ( float );
  FBXMatrix& operator /= ( float );

  // unary operators
  FBXMatrix operator + () const;
  FBXMatrix operator - () const;

  // binary operators
  //FBXMatrix operator * ( CONST FBXMatrix& ) const;
  FBXMatrix operator + ( CONST FBXMatrix& ) const;
  FBXMatrix operator - ( CONST FBXMatrix& ) const;
  FBXMatrix operator * ( float ) const;
  FBXMatrix operator / ( float ) const;

  friend FBXMatrix operator * ( float, CONST FBXMatrix& );
  friend FBXMatrix operator * (const FBXMatrix& a, const FBXMatrix& b);

  float & operator ()  ( const int i, const int j) { return row[i][j]; }
  float operator ()  ( const int i, const int j) const { return row[i][j]; }
};



inline FBXMatrix operator * (const FBXMatrix& a, const FBXMatrix& b) 
{
  FBXMatrix c;


  c.XX = a.XX * b.XX + a.YX * b.XY + a.ZX * b.XZ + a.WX * b.XW;
  c.XY = a.XY * b.XX + a.YY * b.XY + a.ZY * b.XZ + a.WY * b.XW;
  c.XZ = a.XZ * b.XX + a.YZ * b.XY + a.ZZ * b.XZ + a.WZ * b.XW;
  c.XW = a.XW * b.XX + a.YW * b.XY + a.ZW * b.XZ + a.WW * b.XW;

  c.YX = a.XX * b.YX + a.YX * b.YY + a.ZX * b.YZ + a.WX * b.YW;
  c.YY = a.XY * b.YX + a.YY * b.YY + a.ZY * b.YZ + a.WY * b.YW;
  c.YZ = a.XZ * b.YX + a.YZ * b.YY + a.ZZ * b.YZ + a.WZ * b.YW;
  c.YW = a.XW * b.YX + a.YW * b.YY + a.ZW * b.YZ + a.WW * b.YW;

  c.ZX = a.XX * b.ZX + a.YX * b.ZY + a.ZX * b.ZZ + a.WX * b.ZW;
  c.ZY = a.XY * b.ZX + a.YY * b.ZY + a.ZY * b.ZZ + a.WY * b.ZW;
  c.ZZ = a.XZ * b.ZX + a.YZ * b.ZY + a.ZZ * b.ZZ + a.WZ * b.ZW;
  c.ZW = a.XW * b.ZX + a.YW * b.ZY + a.ZW * b.ZZ + a.WW * b.ZW;


  c.WX = a.XX * b.WX + a.YX * b.WY + a.ZX * b.WZ + a.WX * b.WW;
  c.WY = a.XY * b.WX + a.YY * b.WY + a.ZY * b.WZ + a.WY * b.WW;
  c.WZ = a.XZ * b.WX + a.YZ * b.WY + a.ZZ * b.WZ + a.WZ * b.WW;
  c.WW = a.XW * b.WX + a.YW * b.WY + a.ZW * b.WZ + a.WW * b.WW;                                                                  

  return c;


} 


inline void FBXQuaternion::GetColMatrix(FBXMatrix & destMatrix) const
{
  double u, _xs, _ys, _zs, _wx, _wy, _wz, _xx, _xy, _xz, _yy, _yz, _zz;

  /* For unit srcQuat, just set s = 2.0; or set xs = i + 
  *  i, etc. 
  *****************************************************************************/
  u = 2.0 / (i * i + j * j + k * k + s * s);

  _xs = i * u;
  _ys = j * u;
  _zs = k * u;
  _wx = s * _xs;
  _wy = s * _ys;
  _wz = s * _zs;
  _xx = i * _xs;
  _xy = i * _ys;
  _xz = i * _zs;
  _yy = j * _ys;
  _yz = j * _zs;
  _zz = k * _zs;

  /* set up 4x4 destMatrixrix */
  destMatrix(X, X) = 1.0 - (_yy + _zz);
  destMatrix(X, Y) = _xy - _wz;
  destMatrix(X, Z) = _xz + _wy;
  destMatrix(X, W) = 0.0;

  destMatrix(Y, X) = _xy + _wz;
  destMatrix(Y, Y) = 1.0 - (_xx + _zz);
  destMatrix(Y, Z) = _yz - _wx;
  destMatrix(Y, W) = 0.0;

  destMatrix(Z, X) = _xz - _wy;
  destMatrix(Z, Y) = _yz + _wx;
  destMatrix(Z, Z) = 1.0 - (_xx + _yy);
  destMatrix(Z, W) = 0.0;

  destMatrix(W, X) = 0.0;
  destMatrix(W, Y) = 0.0;
  destMatrix(W, Z) = 0.0;
  destMatrix(W, W) = 1.0;

}    



inline void FBXQuaternion::GetRowMatrix(FBXMatrix & destMatrix) const
{
  double u, _xs, _ys, _zs, _wx, _wy, _wz, _xx, _xy, _xz, _yy, _yz, _zz;

  /* For unit srcQuat, just set s = 2.0; or set xs = i + 
  *  i, etc. 
  *****************************************************************************/
  u = 2.0 / (i * i + j * j + k * k + s * s);

  _xs = i * u;
  _ys = j * u;
  _zs = k * u;
  _wx = s * _xs;
  _wy = s * _ys;
  _wz = s * _zs;
  _xx = i * _xs;
  _xy = i * _ys;
  _xz = i * _zs;
  _yy = j * _ys;
  _yz = j * _zs;
  _zz = k * _zs;

  /* set up 4x4 destMatrixrix */
  destMatrix(X, X) = 1.0 - (_yy + _zz);
  destMatrix(Y, X) = _xy - _wz;
  destMatrix(Z, X) = _xz + _wy;
  destMatrix(W, X) = 0.0;
              
  destMatrix(X, Y) = _xy + _wz;
  destMatrix(Y, Y) = 1.0 - (_xx + _zz);
  destMatrix(Z, Y) = _yz - _wx;
  destMatrix(W, Y) = 0.0;
              
  destMatrix(X, Z) = _xz - _wy;
  destMatrix(Y, Z) = _yz + _wx;
  destMatrix(Z, Z) = 1.0 - (_xx + _yy);
  destMatrix(W, Z) = 0.0;
              
  destMatrix(X, W) = 0.0;
  destMatrix(Y, W) = 0.0;
  destMatrix(Z, W) = 0.0;
  destMatrix(W, W) = 1.0;

}    


inline FBXVector3 operator * (const FBXVector3& v3, const FBXMatrix& m4)
{
  // multiply v3 as though it were v4 with w = 1	
  FBXVector4 v4;
  FBXVector3 ret;
  v4.x = v3.x;
  v4.y = v3.y;
  v4.z = v3.z;
  v4.w = 1.0f;
  v4 = v4 * m4;
  v4.Homogenize();

  ret.x = v4.x;
  ret.y = v4.y;
  ret.z = v4.z;
  return( ret );
}


inline FBXVector3 operator * (const FBXMatrix& a, const FBXVector3& v)
{
  FBXVector3 ret;

  ret.x = a(X, X) * v.x + a(Y, X) * v.y + a(Z, X) * v.z + a(W, X);
  ret.y = a(X, Y) * v.x + a(Y, Y) * v.y + a(Z, Y) * v.z + a(W, Y);
  ret.z = a(X, Z) * v.x + a(Y, Z) * v.y + a(Z, Z) * v.z + a(W, Z);

  return ret;
}



inline FBXVector4 operator * (const FBXMatrix& a, const FBXVector4& v)
{
  FBXVector4 ret;

  ret.x = a(X, X) * v.x + a(Y, X) * v.y + a(Z, X) * v.z + a(W, X) * v.w;
  ret.y = a(X, Y) * v.x + a(Y, Y) * v.y + a(Z, Y) * v.z + a(W, Y) * v.w;
  ret.z = a(X, Z) * v.x + a(Y, Z) * v.y + a(Z, Z) * v.z + a(W, Z) * v.w;
  ret.w = a(X, W) * v.x + a(Y, W) * v.y + a(Z, W) * v.z + a(W, W) * v.w;

  return ret;
}

// aT * v
inline FBXVector4 operator * (const FBXVector4& v, const FBXMatrix& a)
{
  FBXVector4 ret;

  ret.x = a(X, X) * v.x + a(X,Y) * v.y + a(X,Z) * v.z + a(X,W) * v.w;
  ret.y = a(Y, X) * v.x + a(Y,Y) * v.y + a(Y,Z) * v.z + a(Y,W) * v.w;
  ret.z = a(Z, X) * v.x + a(Z,Y) * v.y + a(Z,Z) * v.z + a(Z,W) * v.w;
  ret.w = a(W, X) * v.x + a(W,Y) * v.y + a(W,Z) * v.z + a(W,W) * v.w;

  return ret;
}


class FBXVector3_f64 
{
public:
  double x;
  double y;
  double z;
  FBXVector3_f64() 
  {}
  FBXVector3_f64(double _x, double _y, double _z)
  {
    x = _x;
    y = _y;
    z = _z;
  }
};


class SplinePoint
{
public:
  double time;
  double value;

	friend bool operator <  (const SplinePoint& p1, const SplinePoint& p2)
	{
    if (p1.time < p2.time)
      return true;
    return false;
  }
};

typedef std::set<SplinePoint> SplineSet;

class Spline
{
  SplineSet points;

public:
  Spline()
  {
  }
  void SetData (double *x, double *y, size_t numEntries)
  {
    double *xp = x;
    double *yp = y;
    
    SplinePoint pt;
    for(int i = 0; i < numEntries; i++)
    {
      pt.time = *xp++;;
      pt.value = *yp++;;
      points.insert(pt);
    }
  }

  HRESULT RemoveEntry(double time)
  {
    SplinePoint pt;
    pt.time = time;
    pt.value = 0; 
    SplineSet::iterator it = points.find(pt);
    if (it != points.end())
    {
      points.erase(it);
      return 0;
    }

    return -1; // time not found


  }

  void Insert(double time, double x)
  {
    SplinePoint pt;
    pt.time = time;
    pt.value = x; 
    points.insert(pt);
  }



  // v0 = the point before a 
  // v1 = the point a 
  // v2 = the point b 
  // v3 = the point after b  
  double cubic_interpolation(double v0, double v1, double v2, double v3, double x)
  {
    double P = (v3 - v2) - (v0 - v1);
    double Q = (v0 - v1) - P;
    double R = v2 - v0;
    double S = v1;

    double x2 = x * x;
    double x3 = x2 * x;


    return P * x3 + Q * x2 + R * x + S;
  }




  double Evaluate(double t, double defaultValue);


  ~Spline()
  {
  }


};



void FBXQuaternionFromEuler( FBXQuaternion &Qe, KFbxVector4 & v );
float FBXVec3LengthSq( CONST FBXVector3 *pV );
FBXMatrix* FBXMatrixScaling( FBXMatrix *pOut, float sx, float sy, float sz );
FBXMatrix* FBXMatrixMultiply( FBXMatrix *pOut, CONST FBXMatrix *pM1, CONST FBXMatrix *pM2 );           
FBXMatrix* FBXMatrixTranslation( FBXMatrix *pOut, float x, float y, float z );
FBXVector3* FBXVec3Normalize( FBXVector3 *pOut, CONST FBXVector3 *pV );
FBXVector3* FBXVec3TransformCoord( FBXVector3 *pOut, CONST FBXVector3 *pV, CONST FBXMatrix *pM );
FBXMatrix* FBXMatrixInverse( FBXMatrix *pOut, float *pDeterminant, CONST FBXMatrix *pM );
FBXMatrix* FBXMatrixTranspose( FBXMatrix *pOut, CONST FBXMatrix *pM );
FBXMatrix* FBXMatrixTransformation
    ( FBXMatrix *pOut, CONST FBXVector3 *pScalingCenter,
      CONST FBXQuaternion *pScalingRotation, CONST FBXVector3 *pScaling,
      CONST FBXVector3 *pRotationCenter, CONST FBXQuaternion *pRotation,
      CONST FBXVector3 *pTranslation);

FBXQuaternion* FBXQuaternionInverse( FBXQuaternion *pOut, CONST FBXQuaternion *pQ );
FBXQuaternion* FBXQuaternionNormalize( FBXQuaternion *pOut, CONST FBXQuaternion *pQ );
FBXVector3 triangle_normal(const FBXVector3& v1, const FBXVector3& v2, const FBXVector3& v3);

inline float quatDot( const FBXQuaternion& b, const FBXQuaternion& a ) 
{
	return b.i * a.i + b.j * a.j + b.k * a.k + b.s * a.s;
};





