
#pragma once
#pragma warning(disable:4995)
#pragma warning(disable : 4244)  

#include <list>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <windows.h>
#include <math.h>
#include <conio.h>
#include <tchar.h>
#include <strsafe.h>
#include <assert.h>

#include <fbxsdk.h>
#include <fbxfilesdk/fbxfilesdk_nsuse.h>

#include "smart_ptr.h"

//#pragma warning(error : 4996)
#pragma warning(disable:4995)


#define MAX_LIGHTS 3
#define RESET_PIVOT 0
#define FIX_BONES 1
#define RESIZE_AND_CENTER_MODEL 1

#define ENABLE_ANIMATION 1
#define START_TIME 1
#define REJECT_DEFAULT_TAKES 1

#define UPDATE_ANIMATION_MATRIX 1


#define dbgstop _CrtDbgBreak

  
#ifdef IOS_REF
	#undef  IOS_REF
	#define IOS_REF (*(pSdkManager->GetIOSettings()))
#endif
extern float fAnimationScaler;


#define MAX_NUMBER_OF_HW_BONES 64


typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR> > tstring;

#define UL_PI      3.1415926535897932384626433832795028841971693993751
#define UL_SQRT_2  1.4142135623730950488016887242096980785696718753769
#define UL_PI2     (UL_PI/2.0)

#ifndef XYZW
const int X = 0;
const int Y = 1;
const int Z = 2;
const int W = 3;
#define XYZW
#endif


#define UL_DEG2RAD     (UL_PI / 180.0)


typedef unsigned int uint;
typedef std::vector<int> IntList;
  
#include "FBXMath.h"

#define NUM_TEXCOORD_SETS 4

#pragma pack(4)


typedef enum FBXHandedness
{
  kRightHanded,
  kLeftHanded
};



class FBXKeyVector3
{      
public:
  float time;
  FBXVector3 value;

  FBXKeyVector3()
  {       
    value.x = 0;
    value.y = 0;
    value.z = 0;
  }
}; 


class FBXKeyQuaternion 
{
public:

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

// Vertex format
// If this is changed, update UNSKINNED_VERTEX_DECL viewer 

class FBXUnskinnedVertex
{
public:
	FBXVector3 pos;
	FBXVector3 normal;
	FBXVector2 texcoord[NUM_TEXCOORD_SETS];

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

    if (v1.normal < v2.normal)
      return true;

    if (v1.normal > v2.normal)
      return false;

    for(int i = 0; i < NUM_TEXCOORD_SETS; i++)
    {
      const FBXVector2 & v1tc = v1.texcoord[i];
      const FBXVector2 & v2tc = v2.texcoord[i];

      if (v1tc < v2tc)
        return true;

      if (v1tc > v2tc)
        return false;

    }
    return false;
  }

};

// If this is changed, update SKINNED_VERTEX_DECL in viewer

class FBXSkinnedVertex
{
public:

  FBXUnskinnedVertex us;

  FBXVector4 blendWeights;
  union
  {
    uint     boneIndicesAll;
    struct 
    {
      unsigned char boneIndex[4];

    };
  };


  friend bool operator < (const FBXSkinnedVertex& v1, const FBXSkinnedVertex& v2)
  {

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

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

    if (v1.us.normal < v2.us.normal)
      return true;

    if (v1.us.normal > v2.us.normal)
      return false;

    for(int i = 0; i < NUM_TEXCOORD_SETS; i++)
    {
      const FBXVector2 & v1tc = v1.us.texcoord[i];
      const FBXVector2 & v2tc = v2.us.texcoord[i];

      if (v1tc < v2tc)
        return true;

      if (v1tc > v2tc)
        return false;

    }
    if (v1.blendWeights < v2.blendWeights)
      return true;

    if (v1.blendWeights > v2.blendWeights)
      return false;

    if (v1.boneIndicesAll < v2.boneIndicesAll)
      return true;

    if (v1.boneIndicesAll > v2.boneIndicesAll)
      return false;


    return false;
  }
};

#pragma pack()


typedef enum FBXPlaybackType
{
  FBXPLAY_LOOP          = 0,
  FBXPLAY_ONCE          = 1,
  FBXPLAY_PINGPONG      = 2,

  FBXPLAY_FORCE_DWORD   = 0x7fffffff, /* force 32-bit size enum */
} ;




typedef enum FBXEffectDefaultType
{
  FBXEDT_STRING = 0x1,       // pValue points to a null terminated ASCII string 
  FBXEDT_FLOATS = 0x2,       // pValue points to an array of floats - number of floats is NumBytes / sizeof(float)
  FBXEDT_DWORD  = 0x3,       // pValue points to a uint

  FBXEDT_FORCEDWORD = 0x7fffffff
} ;


typedef enum FBXImageFileFormat
{
  FBXIFF_BMP         = 0,
  FBXIFF_JPG         = 1,
  FBXIFF_TGA         = 2,
  FBXIFF_PNG         = 3,
  FBXIFF_DDS         = 4,
  FBXIFF_PPM         = 5,
  FBXIFF_DIB         = 6,
  FBXIFF_HDR         = 7,       //high dynamic range formats
  FBXIFF_PFM         = 8,       //
  FBXIFF_FORCE_DWORD = 0xFFFFFFFF
} ;



class FBXEffectDefault
{
  LPSTR                 pParamName;
  FBXEffectDefaultType  type;           // type of the data pointed to by pValue
  uint                  numBytes;       // size in bytes of the data pointed to by pValue
  LPVOID                pValue;         // data for the default of the effect
};


class FBXEffectInstance
{
  std::string        pEffectFilename;
  uint               numDefaults;
  FBXEffectDefault * pDefaults;
};



class FBXAttributeRange
{
public:
  uint attribId;
  uint faceStart;
  uint faceCount;
  uint vertexStart;
  uint vertexCount;
};

class FBXBoneCombination : public  FBXAttributeRange
{
public:
  std::vector<uint> boneIDList;
};


#pragma warning(disable: 4995)
#pragma warning(default: 4995)

#define FOR_EACH(list, it)  \
	for (it = list.begin(); it != list.end(); ++it)

#define FOR_EACH_REVERSE(list, it)  \
	for (it = list.rbegin(); it != list.rend(); ++it)
#define FOR_EACH(list, it)  \
	for (it = list.begin(); it != list.end(); ++it)

typedef std::vector<FBXVector3> PointsList;

// vertex , weight
typedef std::map< int, double> VertexBoneWeightMap;
typedef std::vector<VertexBoneWeightMap> VertexBoneWeightMapList;

// weight, bone #
typedef std::multimap< double, int> WeightBoneMap;
typedef std::pair< double, int> WeightBoneMapNode;
typedef std::vector<WeightBoneMap> WeightBoneMapList;

typedef std::map< int, double> BoneWeightMap;



typedef std::vector<std::set<int>> ControlPointRemap;

typedef std::map<std::string, int> UvNameSetMap;

void CharToWString( const std::string &source, std::wstring& dest );
void CharToWString( const char* source, std::wstring& dest );

void WCharToString( const wchar_t* source, std::string& dest );
void WCharToString( const std::wstring &source, std::string& dest );

typedef std::vector<unsigned int > uIntVector;
typedef std::vector<int> FBXAttributeList;




typedef std::map< std::string, FBXMatrix> BoneMatrixMap;
typedef std::pair< std::string, FBXMatrix> BoneMatrixMapNode;
typedef BoneMatrixMap::iterator BoneMatrixMapIterator;

extern BoneMatrixMap boneMatrixMap;

void console(const wchar_t * _format, ...);
void console(const char * _format, ...);

#define KFBXTAKENODE_DEFAULT_NAME_2			"default take"



class FBXAnimationKeySet
{
public:
  std::string name;
  double timeStart, timeStop;
	std::vector<FBXKeyVector3> transKeys;
	std::vector<FBXKeyVector3> scaleKeys;
	std::vector<FBXKeyVector3> rotKeys;
	std::vector<FBXKeyQuaternion> quatKeys;
	
  void clear()
	{
		transKeys.clear();
		scaleKeys.clear();
		rotKeys.clear();
	}
};


typedef std::vector<KFbxConstraint *> ConstraintList;

typedef std::map<KFbxObject *, ConstraintList> ConstraintMap; 
typedef std::map<std::string, KFbxAnimStack*> AnimationStackMap; 






KFbxXMatrix GetLocalPositionFromCurrentTake(KFbxNode* pNode, const KTime& pTime);
KFbxXMatrix GetGlobalPositionFromLocalPosition(KFbxNode* pNode, 
											   KFbxAnimStack* lCurrentTakeNode,
											   KTime& pTime, 
											   KFbxXMatrix* pParentGlobalPosition);

KFbxXMatrix GetDefaultLocalPosition(KFbxNode* pNode);
bool AnimationPresent(KFbxAnimLayer * pTakeNode, KFbxNode* pNode);
KFbxXMatrix GetLocalPosition(KFbxNode* pNode, KFbxPose* pPose);



KFbxXMatrix GetLocalPosition(KFbxNode* pNode);
KFbxXMatrix GetGlobalPosition(KFbxNode* pNode);
KFbxXMatrix GetGlobalPosition(KFbxNode* pNode, KTime& pTime);
KFbxXMatrix GetLocalPosition(KFbxNode* pNode, KTime& pTime);



bool HasSomeFCurves(KFbxObject* pNode, KFbxAnimLayer* pAnimLayer);
bool HasKeysOnFCurves(KFbxAnimCurveNode* pFCNode);


KFbxXMatrix GetLocalPosition(KFbxNode* pNode);
KFbxXMatrix GetGlobalPosition(KFbxNode* pNode);
KFbxXMatrix GetGlobalPosition(KFbxNode* pNode, const KTime& pTime);
KFbxXMatrix GetLocalPosition(KFbxNode* pNode, KTime& pTime);



#define FBXSTDMETHOD(method)        HRESULT STDMETHODCALLTYPE method
#define FBXSTDMETHOD_(type,method)  type STDMETHODCALLTYPE method

#define V_FBXSTDMETHOD(method)        virtual HRESULT STDMETHODCALLTYPE method
#define V_FBXSTDMETHOD_(type,method)  virtual type STDMETHODCALLTYPE method



#pragma pack(4)
class FBXColorValue 
{
public:

    union
    {
      float n[4];
      struct
      {
        float r;
        float g;
        float b;
        float a;
      };

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

    void clear()
    {
      r = g = b = a = 0;
    }

} ;
#pragma pack()





class FBXVertexSkinning;

typedef smart_ptr<FBXVertexSkinning> spFBXVertexSkinning;
                   
 
#define FBXMESH_OPTIONS_UNSKINNED 0
#define FBXMESH_OPTIONS_SKINNED 1


typedef std::vector<FBXUnskinnedVertex> FBXUnskinnedVertexList;
typedef std::vector<FBXSkinnedVertex>   FBXSkinnedVertexList;




typedef enum ColorType
{
  kLAMBERT,
  kPHONG,
  kCOLOR_TYPE = 0xFFFFFFFF // force to be DWORD
};

typedef enum FBXTextureType
{
  kDiffuseTexture,
  kDiffuseFactorTexture,

  kAmbientTexture,
  kAmbientFactorTexture,

  kBumpTexture,
  kNormalMapTexture,
  kBumpFactorTexture,

  kEmissiveTexture,
  kEmissiveFactorTexture,

  kSpecularTexture,
  kSpecularFactorTexture,
  kShininessTexture,

  kTransparentColorTexture,
  kTransparencyFactorTexture,

  kReflectionTexture,
  kReflectionFactorTexture,
  kTextureTypeSize,
};


class IFBXTextureContainer
{
public:
  IFBXTextureContainer()
  {
  }

  virtual ~IFBXTextureContainer()
  {

  }
  virtual bool TextureValid() = 0;


  FBXTextureType textureType;
  uint uvSetNumber;

  std::string textureName;
  std::string textureFileName; 


};

typedef smart_ptr<IFBXTextureContainer> spIFBXTexture;
typedef std::map <FBXTextureType, spIFBXTexture> FBXTextureArray;  // indexed by type
typedef std::vector< FBXTextureArray > FBXTextureArrayList;
typedef std::vector<FBXVector2> FBXTextureCoordsList;
typedef std::vector<FBXTextureCoordsList> FBXTextureCoordsListArray;


class FBXMaterialColor
{
public:

  ColorType  colorType;

  FBXColorValue emissive;
  float emissiveFactor;

  FBXColorValue ambient;
  float ambientFactor;

  FBXColorValue diffuse;
  float diffuseFactor;

  float bump;
  float bumpFactor;

  FBXColorValue transparentColor;
  float transparencyFactor;


  FBXColorValue specular;
  float specularFactor;
  float shininess;

  FBXColorValue reflection;
  float reflectionFactor;
  void ClearColors()
  {
    colorType = kLAMBERT;
    emissiveFactor = 1;
    ambientFactor = 1;
    diffuseFactor = 1;
    bump = 1;
    bumpFactor = 1;
    transparencyFactor = 1;
    specularFactor = 1;
    shininess = 1;
    reflectionFactor = 1;

    emissive.clear();

    ambient.clear();

    diffuse.clear();



    transparentColor.clear();


    specular.clear();


    reflection.clear();
  }

};



class FBXMaterial 
{
public:

  FBXMaterialColor color;
  std::string materialName; 
  std::string decalFilename;
  int materialID;

  FBXTextureArrayList textureArrayList;

};

typedef std::vector<FBXMaterial> FBXMaterialList;

class FBXMesh
{
public:
  FBXMesh()
  {

    m_options = 0;

    m_bTextureCoordinatesPresent = false;
  }


  bool                            m_bTextureCoordinatesPresent;
  uint                            m_options;

  FBXMaterialList                 m_materialList;

  std::vector<uint>               m_adjacencyList;

  FBXUnskinnedVertexList          m_unskinnedVertexList;
  FBXSkinnedVertexList            m_skinnedVertexList;
  IntList                         m_indexList;


  FBXAttributeList                m_attributeList;
  std::vector<FBXAttributeRange>  m_attributeRangeList;

  HRESULT GenerateAttributeTable();

  FBXVector3 & GetPosition(uint );
  FBXVector3 & GetNormal(uint );
  STDMETHOD_(uint, GetNumFaces)(void) const;
  STDMETHOD_(uint, GetNumVertices)(void) ;
  STDMETHOD_(uint, GetNumBytesPerVertex)(void) ;
  STDMETHOD_(uint, GetOptions)(void) ;
  STDMETHOD(CloneMesh)( uint Options, FBXMesh ** ppCloneMesh) ;
  STDMETHOD(GetAttributeTable)(FBXAttributeRange *pAttribTable, uint* pAttribTableSize) const;


  HRESULT ComputeNormals();

  //STDMETHOD(ConvertPointRepsToAdjacency)( CONST uint* pPRep, uint* pAdjacency) ;
  //STDMETHOD(ConvertAdjacencyToPointReps)( CONST uint* pAdjacency, uint* pPRep) ;
  STDMETHOD(GenerateAdjacency)( ) ;



  STDMETHOD(SetAttributeTable)( CONST FBXAttributeRange *pAttribTable, uint cAttribTableSize) ;
};



typedef smart_ptr<FBXMesh> spFBXMesh;





typedef enum FBXDataFormat
{
  FBXFMT_UNKNOWN              =  0,

  FBXFMT_R8G8B8               = 20,
  FBXFMT_A8R8G8B8             = 21,
  FBXFMT_X8R8G8B8             = 22,
  FBXFMT_R5G6B5               = 23,
  FBXFMT_X1R5G5B5             = 24,
  FBXFMT_A1R5G5B5             = 25,
  FBXFMT_A4R4G4B4             = 26,
  FBXFMT_R3G3B2               = 27,
  FBXFMT_A8                   = 28,
  FBXFMT_A8R3G3B2             = 29,
  FBXFMT_X4R4G4B4             = 30,
  FBXFMT_A2B10G10R10          = 31,
  FBXFMT_A8B8G8R8             = 32,
  FBXFMT_X8B8G8R8             = 33,
  FBXFMT_G16R16               = 34,
  FBXFMT_A2R10G10B10          = 35,
  FBXFMT_A16B16G16R16         = 36,

  FBXFMT_A8P8                 = 40,
  FBXFMT_P8                   = 41,

  FBXFMT_L8                   = 50,
  FBXFMT_A8L8                 = 51,
  FBXFMT_A4L4                 = 52,

  FBXFMT_V8U8                 = 60,
  FBXFMT_L6V5U5               = 61,
  FBXFMT_X8L8V8U8             = 62,
  FBXFMT_Q8W8V8U8             = 63,
  FBXFMT_V16U16               = 64,
  FBXFMT_A2W10V10U10          = 67,

  FBXFMT_UYVY                 = MAKEFOURCC('U', 'Y', 'V', 'Y'),
  FBXFMT_R8G8_B8G8            = MAKEFOURCC('R', 'G', 'B', 'G'),
  FBXFMT_YUY2                 = MAKEFOURCC('Y', 'U', 'Y', '2'),
  FBXFMT_G8R8_G8B8            = MAKEFOURCC('G', 'R', 'G', 'B'),
  FBXFMT_DXT1                 = MAKEFOURCC('D', 'X', 'T', '1'),
  FBXFMT_DXT2                 = MAKEFOURCC('D', 'X', 'T', '2'),
  FBXFMT_DXT3                 = MAKEFOURCC('D', 'X', 'T', '3'),
  FBXFMT_DXT4                 = MAKEFOURCC('D', 'X', 'T', '4'),
  FBXFMT_DXT5                 = MAKEFOURCC('D', 'X', 'T', '5'),

  FBXFMT_D16_LOCKABLE         = 70,
  FBXFMT_D32                  = 71,
  FBXFMT_D15S1                = 73,
  FBXFMT_D24S8                = 75,
  FBXFMT_D24X8                = 77,
  FBXFMT_D24X4S4              = 79,
  FBXFMT_D16                  = 80,

  FBXFMT_D32F_LOCKABLE        = 82,
  FBXFMT_D24FS8               = 83,

  /* D3D9Ex only -- */
#if !defined(D3D_DISABLE_9EX)

  /* Z-Stencil formats valid for CPU access */
  FBXFMT_D32_LOCKABLE         = 84,
  FBXFMT_S8_LOCKABLE          = 85,

#endif // !D3D_DISABLE_9EX
  /* -- D3D9Ex only */


  FBXFMT_L16                  = 81,

  FBXFMT_VERTEXDATA           =100,
  FBXFMT_INDEX16              =101,
  FBXFMT_INDEX32              =102,

  FBXFMT_Q16W16V16U16         =110,

  FBXFMT_MULTI2_ARGB8         = MAKEFOURCC('M','E','T','1'),

  // Floating point surface formats

  // s10e5 formats (16-bits per channel)
  FBXFMT_R16F                 = 111,
  FBXFMT_G16R16F              = 112,
  FBXFMT_A16B16G16R16F        = 113,

  // IEEE s23e8 formats (32-bits per channel)
  FBXFMT_R32F                 = 114,
  FBXFMT_G32R32F              = 115,
  FBXFMT_A32B32G32R32F        = 116,

  FBXFMT_CxV8U8               = 117,

  /* D3D9Ex only -- */
#if !defined(D3D_DISABLE_9EX)

  // Monochrome 1 bit per pixel format
  FBXFMT_A1                   = 118,

  // 2.8 biased fixed point
  FBXFMT_A2B10G10R10_XR_BIAS  = 119,


  // Binary format indicating that the data has no inherent type
  FBXFMT_BINARYBUFFER         = 199,

#endif // !D3D_DISABLE_9EX
  /* -- D3D9Ex only */


  FBXFMT_FORCE_DWORD          =0x7fffffff
} ;

/* Types */
typedef enum FBXResourceType 
{
  FBXRTYPE_SURFACE                =  1,
  FBXRTYPE_VOLUME                 =  2,                                                                   
  FBXRTYPE_TEXTURE                =  3,
  FBXRTYPE_VOLUMETEXTURE          =  4,
  FBXRTYPE_CUBETEXTURE            =  5,
  FBXRTYPE_VERTEXBUFFER           =  6,
  FBXRTYPE_INDEXBUFFER            =  7,           //if this changes, change _D3DDEVINFO_RESOURCEMANAGER definition


  FBXRTYPE_FORCE_DWORD            = 0x7fffffff
} ;








inline FBXMatrix* FBXMatrixIdentity( FBXMatrix *pOut )
{
  pOut->row[0][1] = pOut->row[0][2] = pOut->row[0][3] =
  pOut->row[1][0] = pOut->row[1][2] = pOut->row[1][3] =
  pOut->row[2][0] = pOut->row[2][1] = pOut->row[2][3] =
  pOut->row[3][0] = pOut->row[3][1] = pOut->row[3][2] = 0.0f;

  pOut->row[0][0] = pOut->row[1][1] = pOut->row[2][2] = pOut->row[3][3] = 1.0f;
  return pOut;
}
//----------------------------------------------------------------------------
// FBXMESHCONTAINER:
// ------------------
// This struct encapsulates a mesh object in a transformation frame
// hierarchy. The app can derive from this structure to add other app specific
// data to this.
//----------------------------------------------------------------------------
class IFBXMeshContainer
{
public:
  virtual ~IFBXMeshContainer()
  {
   
  }
  std::string              name;
  spFBXMesh                spMesh;

  spFBXVertexSkinning      spVertexSkinning;

};

typedef smart_ptr<IFBXMeshContainer> spIFBXMeshContainer;
typedef enum FrameType
{
  kNOTSET,
	kSKELETON,
	kLIGHT,
	kCAMERA,
	kMESH,
	kMARKER,
	kNULL,
};


typedef enum InheritanceType
{
	kINHERIT_RrSs, 
	kINHERIT_RSrs, 
	kINHERIT_Rrs 
};
//----------------------------------------------------------------------------
// FBXFrame:
// ----------
// This struct is the encapsulates a transform frame in a transformation frame
// hierarchy. The app can derive from this structure to add other app specific
// data to this
//----------------------------------------------------------------------------
class FBXFrame
{
public:

  FBXFrame()
  {   
    pFrameSibling = 0;
    pFrameFirstChild = 0; 
    pNode = NULL;
  }

  FrameType         frameType;
  std::string       name;
  FBXMatrix         transformationMatrix;
  FBXMatrix         combinedTransformationMatrix;

  InheritanceType   inheritanceType;

  //The FBXFrame is sometimes insufficient to animate complex objects like cameras, lights, etc...
  //Keep a pointer to the FBX node so that we can still use its curves to interpolate.
  KFbxNode *pNode;

  smart_ptr<IFBXMeshContainer>  spMeshContainer;

  FBXFrame       *pFrameSibling;
  FBXFrame       *pFrameFirstChild;
} ;


typedef std::map<KFbxNode *, FBXFrame *> NodeToFrameMap; 









class FBXSkinBone
{
public:
  FBXSkinBone()
  {
    FBXMatrixIdentity(&boneTransformMatrix);
    pFrame = NULL;
  }

  FBXFrame * pFrame;

  std::string name;
  std::vector<uint> vertices;
  std::vector<float> weights;
  FBXMatrix boneTransformMatrix;
};


class FBXVertexBone
{
public:
  int boneID;
  float weight;
};


class FBXVertexSkinning
{
public:
  // bone ID
  FBXVertexSkinning()
  {
    m_maxBoneInfluences = 0;
    m_minBoneInfluence = 0;

  }
  float m_minBoneInfluence;   // Sets the minimum bone influence. Influence values smaller than this are ignored.
  // bone number
  std::map<int, FBXSkinBone> m_skinBoneMap;

  // vertID / bones
  
  std::map<int, std::vector<FBXVertexBone>> m_vertBoneList;
  uint m_maxBoneInfluences;

  void RemoveZeroWeightedBoneInfluences();

  // Specify the which vertices do each bones influence and by how much
  FBXSTDMETHOD(SetBoneInfluence)( uint bone, uint numInfluences, CONST uint* vertices, CONST float* weights) ;
  FBXSTDMETHOD(SetBoneVertexInfluence)( uint boneNum, uint influenceNum, float weight) ;
  FBXSTDMETHOD_(uint, GetNumBoneInfluences)( uint bone) ;
  FBXSTDMETHOD(GetBoneInfluence)( uint bone, uint* vertices, float* weights) ;
  FBXSTDMETHOD(GetBoneVertexInfluence)( uint boneNum, uint influenceNum, float *pWeight, uint *pVertexNum) ;
  FBXSTDMETHOD(GetMaxVertexInfluences)( uint* maxVertexInfluences) ;
  FBXSTDMETHOD_(uint, GetNumBones)(void) ;
  FBXSTDMETHOD(FindBoneVertexInfluenceIndex)( uint boneNum, uint vertexNum, uint *pInfluenceIndex) ;

  // This gets the max face influences based on a triangle mesh with the specified index buffer
  //FBXSTDMETHOD(GetMaxFaceInfluences)( LPDIRECT3DINDEXBUFFER9 pIB, uint NumFaces, uint* maxFaceInfluences) ;

  // Set min bone influence. Bone influences that are smaller than this are ignored
  FBXSTDMETHOD(SetMinBoneInfluence)( float MinInfl) ;
  // Get min bone influence. 
  FBXSTDMETHOD_(float, GetMinBoneInfluence)(void) ;

  // Bone names are returned by FBXLoadSkinMeshFromXof. They are not used by any other method of this object
  FBXSTDMETHOD(SetBoneFrame)( uint Bone, FBXFrame *) ; // pName is copied to an internal string buffer
  FBXFrame * GetBoneFrame(unsigned long boneNum);

  // Bone offset matrices are returned by FBXLoadSkinMeshFromXof. They are not used by any other method of this object
  FBXSTDMETHOD(SetBoneName)( uint Bone, const char *); 
  FBXSTDMETHOD(SetBoneOffsetMatrix)( uint Bone, FBXMatrix &boneTransform) ; // pBoneTransform is copied to an internal buffer
  FBXSTDMETHOD_(FBXMatrix &, GetBoneOffsetMatrix)( uint Bone) ; // A pointer to an internal matrix is returned. Do not free this.

  // Clone a skin info object
  FBXSTDMETHOD(Clone)( FBXVertexSkinning ** ppSkinInfo) ;

  // Update bone influence information to match vertices after they are reordered. This should be called 
  // if the target vertex buffer has been reordered externally.
  //FBXSTDMETHOD(Remap)( uint NumVertices, uint* pVertexRemap) ;

  // These methods enable the modification of the vertex layout of the vertices that will be skinned


  // Apply SW skinning based on current pose matrices to the target vertices.
  FBXSTDMETHOD(UpdateSkinnedMesh)( 
    CONST FBXMatrix* pBoneTransforms, 
    CONST FBXMatrix* pBoneInvTransposeTransforms, 
    FBXSkinnedVertexList & skinnedVertexList,
    FBXUnskinnedVertex * pVerticesDst) ;


  // Takes a mesh and returns a new mesh with per vertex blend weights and indices 
  // and a bone combination table that describes which bones palettes affect which subsets of the mesh
  FBXSTDMETHOD(ConvertToIndexedBlendedMesh)( 
    spFBXMesh & pMesh,
    uint Options, 
    uint paletteSize, 
    uint* pFaceRemap, 

    uint* pMaxVertexInfl,
    uint* pNumBoneCombinations, 
    std::vector<FBXBoneCombination> &ppBoneCombinationTable, 

    spFBXMesh & ppMesh) ;
};



HRESULT FBXCreateMesh(spFBXMesh & ppMesh);



HRESULT FBXCreateSkinInfo(uint NumVertices,uint NumBones,FBXVertexSkinning ** ppSkinInfo);





//----------------------------------------------------------------------------
// IFBXAllocateHierarchy:
// -----------------------
// This interface is implemented by the application to allocate/free frame and
// mesh container objects. Methods on this are called during loading and
// destroying frame hierarchies
  
typedef std::vector<FBXFrame *>  FBXMeshFrameList;
class IFBXAllocateHierarchy
{
public:
  FBXMeshFrameList m_meshFrameList;  // list of all meshes.  To get to the meshes w/o frame traversal

  virtual ~IFBXAllocateHierarchy()
  {
    
  }
  // IFBXAllocateHierarchy

  //------------------------------------------------------------------------
  // CreateFrame:
  // ------------
  // Requests allocation of a frame object.
  //
  // Parameters:
  //  Name
  //		Name of the frame to be created
  //	ppNewFrame
  //		Returns the created frame object
  //
  //------------------------------------------------------------------------
  V_FBXSTDMETHOD(CreateFrame)( const char * Name, FBXFrame * *ppNewFrame) = 0;

  V_FBXSTDMETHOD(CreateTextureContainer)( IFBXTextureContainer * *ppNewTexture, const char * textureName,
    const char * fileName, FBXTextureType textureType, int uvSetNumber) = 0;

  //------------------------------------------------------------------------
  // CreateMeshContainer:
  // --------------------
  // Requests allocation of a mesh container object.
  //
  // Parameters:
  //  Name
  //		Name of the mesh
  //	pMesh
  //		Pointer to the mesh object if basic polygon data found
  //	pPMesh
  //		Pointer to the progressive mesh object if progressive mesh data found
  //	pPatchMesh
  //		Pointer to the patch mesh object if patch data found
  //	pMaterials
  //		Array of materials used in the mesh
  //	pAdjacency
  //		Adjacency array for the mesh
  //	pSkinInfo
  //		Pointer to the skininfo object if the mesh is skinned
  //	pBoneNames
  //		Array of names, one for each bone in the skinned mesh. 
  //		The numberof bones can be found from the pSkinMesh object
  //	pBoneOffsetMatrices
  //		Array of matrices, one for each bone in the skinned mesh.
  //
  //------------------------------------------------------------------------
  virtual HRESULT CreateMeshContainer( 
											   const char * MeshName,
											   spFBXMesh &pSrcMesh,
											   FBXVertexSkinning * pSkinInfo, 
											   IFBXMeshContainer **ppNewMeshContainer ) = 0;


  //------------------------------------------------------------------------
  // DestroyFrame:
  // -------------
  // Requests de-allocation of a frame object.
  //
  // Parameters:
  //  pFrameToFree
  //		Pointer to the frame to be de-allocated
  //
  //------------------------------------------------------------------------
  V_FBXSTDMETHOD(DestroyFrame)( FBXFrame * pFrameToFree)  = 0; 

  //------------------------------------------------------------------------
  // DestroyMeshContainer:
  // ---------------------
  // Requests de-allocation of a mesh container object.
  //
  // Parameters:
  //  pMeshContainerToFree
  //		Pointer to the mesh container object to be de-allocated
  //
  //------------------------------------------------------------------------
  //V_FBXSTDMETHOD(DestroyMeshContainer)( IFBXMeshContainer* pMeshContainerToFree)  = 0; 
};



//----------------------------------------------------------------------------
// FBXCALLBACK_SEARCH_FLAGS:
// --------------------------
// Flags that can be passed into IFBXAnimationSet::GetCallback. 
//----------------------------------------------------------------------------
typedef enum _FBXCALLBACK_SEARCH_FLAGS
{
  FBXCALLBACK_SEARCH_EXCLUDING_INITIAL_POSITION = 0x01,  // exclude callbacks at the initial position from the search
  FBXCALLBACK_SEARCH_BEHIND_INITIAL_POSITION    = 0x02,  // reverse the callback search direction

  FBXCALLBACK_SEARCH_FORCE_DWORD                = 0x7fffffff,
} FBXCALLBACK_SEARCH_FLAGS;



typedef std::set<FBXKeyQuaternion> QuatKeySet;

class QuatSet
{
public:
  QuatKeySet quatKeySet;
  QuatSet();
  void SetData (const FBXKeyQuaternion *quats, size_t numEntries);
  FBXQuaternion Evaluate(double t, FBXQuaternion defaultValue);
  ~QuatSet();

};

class KeyFrameContainer
{
public:
  std::string name;
  Spline Rx;
  Spline Ry;
  Spline Rz;

  Spline Tx;
  Spline Ty;
  Spline Tz;

  Spline Sx;
  Spline Sy;
  Spline Sz;

  QuatSet Q;

  FBXAnimationKeySet animationKeySet;
};


typedef std::map<FBXFrame*, KeyFrameContainer> BoneFrameToKeyFrameSetMap;


//----------------------------------------------------------------------------
// FBXKEY_CALLBACK:
// -----------------
// This structure describes an callback key for use in keyframe animation.
// It specifies a pointer to user data at a given Time. 
//----------------------------------------------------------------------------
class FBXKeyCallback
{
public:
  float time;
  void * pCallbackData;
};

class IFBXAnimationSet
{
public:
  virtual ~IFBXAnimationSet()
  {
  }
  std::string m_name;


  std::vector<FBXKeyCallback> m_callbackKeys;
  BoneFrameToKeyFrameSetMap m_boneFrameToKeyFrameSetMap;

  std::vector<FBXFrame*> m_boneList;






  FBXAnimationKeySet * GetKeySet(int index)
  {
    FBXFrame* bone = m_boneList[index];
    BoneFrameToKeyFrameSetMap::iterator it =  m_boneFrameToKeyFrameSetMap.find(bone);
    if (it == m_boneFrameToKeyFrameSetMap.end())
      return 0;

    return &it->second.animationKeySet;
  }


  KeyFrameContainer * GetKeyFrameContainer(int index)
  {
    FBXFrame* bone = m_boneList[index];
    BoneFrameToKeyFrameSetMap::iterator it =  m_boneFrameToKeyFrameSetMap.find(bone);
    if (it == m_boneFrameToKeyFrameSetMap.end())
      return 0;

    return &it->second;
  }




  double m_PeriodicPosition;
  double m_TimeStart;
  double m_TimeStop;
  double m_ticksPerSecond;
  FBXPlaybackType m_playbackType;


  // Name
  V_FBXSTDMETHOD_(const char * , GetName)(void) = 0;

  // Period
  V_FBXSTDMETHOD_(double, GetPeriod)(void)  = 0;
  V_FBXSTDMETHOD_(double, GetPeriodicPosition)( double Position)  = 0;    // Maps position into animation period

  // Animation names
  V_FBXSTDMETHOD_(uint, GetNumAnimations)(void)  = 0;
  V_FBXSTDMETHOD(GetAnimationNameByIndex)( UINT Index, const char *  *ppName)  = 0;
  V_FBXSTDMETHOD(GetAnimationIndexByName)( const char *  pName, UINT *pIndex)  = 0;

  // SRT
  V_FBXSTDMETHOD(GetSRT)( 
    double PeriodicPosition,            // Position mapped to period (use GetPeriodicPosition)
    UINT Animation,                     // Animation index
    FBXVector3 *pScale,                // Returns the scale
    FBXVector3 *pRotation,          // Returns the rotation as a quaternion
    FBXVector3 *pTranslation)  = 0;    // Returns the translation

  // Callbacks
  V_FBXSTDMETHOD(GetCallback)( 
    double Position,                    // Position from which to find callbacks
    uint Flags,                        // Callback search flags
    double *pCallbackPosition,          // Returns the position of the callback
    LPVOID *ppCallbackData)  = 0;       // Returns the callback data pointer
};

typedef smart_ptr<IFBXAnimationSet> spIFBXAnimationSet;







//----------------------------------------------------------------------------
// FBXCOMPRESSION_FLAGS:
// ----------------------
// Flags that can be passed into FBXKeyframedAnimationSet::Compress. 
//----------------------------------------------------------------------------
typedef enum FBXCompressionFlags
{
  FBXCOMPRESS_DEFAULT     = 0x00,

  FBXCOMPRESS_FORCE_DWORD = 0x7fffffff,
};


//----------------------------------------------------------------------------
// FBXKeyframedAnimationSet:
// ---------------------------
// This interface implements a compressable keyframed animation set.
//----------------------------------------------------------------------------


class FBXKeyframedAnimationSet: public IFBXAnimationSet
{
public:
  // Name
  FBXSTDMETHOD_(const char * , GetName)(void) ;

  // Period
  FBXSTDMETHOD_(double, GetPeriod)(void) ;
  FBXSTDMETHOD_(double, GetPeriodicPosition)( double Position) ;    // Maps position into animation period

  // Animation names
  FBXSTDMETHOD_(uint, GetNumAnimations)(void) ;
  FBXSTDMETHOD(GetAnimationNameByIndex)( uint Index, const char *  *ppName) ;
  FBXSTDMETHOD(GetAnimationIndexByName)( const char *  pName, uint *pIndex) ;

  // SRT
  FBXSTDMETHOD(GetSRT)( 
    double PeriodicPosition,            // Position mapped to period (use GetPeriodicPosition)
    UINT Animation,                     // Animation index
    FBXVector3 *pScale,                // Returns the scale
    FBXVector3 *pRotation,          // Returns the rotation as a quaternion
    FBXVector3 *pTranslation) ;    // Returns the translation

  // Callbacks
  FBXSTDMETHOD(GetCallback)( 
    double Position,                    // Position from which to find callbacks
    uint Flags,                        // Callback search flags
    double *pCallbackPosition,          // Returns the position of the callback
    LPVOID *ppCallbackData) ;       // Returns the callback data pointer

  // Playback
  FBXSTDMETHOD_(FBXPlaybackType, GetPlaybackType)(void) ;
  FBXSTDMETHOD_(double, GetSourceTicksPerSecond)(void) ;

  // Scale keys
  FBXSTDMETHOD_(uint, GetNumScaleKeys)( UINT Animation) ;
  FBXSTDMETHOD(GetScaleKeys)( uint Animation, FBXKeyVector3* pScaleKeys) ;
  FBXSTDMETHOD(GetScaleKey)( uint Animation, UINT Key, FBXKeyVector3* pScaleKey) ;
  FBXSTDMETHOD(SetScaleKey)( uint Animation, UINT Key, FBXKeyVector3* pScaleKey) ;

  // Rotation keys
  FBXSTDMETHOD_(uint, GetNumRotationKeys)( UINT Animation) ;
  FBXSTDMETHOD(GetRotationKeys)( uint Animation, FBXKeyVector3* pRotationKeys) ;
  FBXSTDMETHOD(GetRotationKey)( uint Animation, uint Key, FBXKeyVector3* pRotationKey) ;
  FBXSTDMETHOD(SetRotationKey)( uint Animation, uint Key, FBXKeyVector3* pRotationKey) ;

  // Translation keys
  FBXSTDMETHOD_(uint, GetNumTranslationKeys)( UINT Animation) ;
  FBXSTDMETHOD(GetTranslationKeys)( UINT Animation, FBXKeyVector3* pTranslationKeys) ;
  FBXSTDMETHOD(GetTranslationKey)( UINT Animation, uint Key, FBXKeyVector3* pTranslationKey) ;
  FBXSTDMETHOD(SetTranslationKey)( uint Animation, uint Key, FBXKeyVector3* pTranslationKey) ;

  // Callback keys
  FBXSTDMETHOD_(UINT, GetNumCallbackKeys)(void) ;
  FBXSTDMETHOD(GetCallbackKeys)( FBXKeyCallback * pCallbackKeys) ;
  FBXSTDMETHOD(GetCallbackKey)( uint Key, FBXKeyCallback * pCallbackKey) ;
  FBXSTDMETHOD(SetCallbackKey)( uint Key, FBXKeyCallback * pCallbackKey) ;

  // Key removal methods. These are slow, and should not be used once the animation starts playing
  FBXSTDMETHOD(UnregisterScaleKey)( uint Animation, uint Key) ;
  FBXSTDMETHOD(UnregisterRotationKey)( uint Animation, uint Key) ;
  FBXSTDMETHOD(UnregisterTranslationKey)( uint Animation, uint Key) ;

  // One-time animation SRT keyframe registration
  FBXSTDMETHOD(RegisterAnimationSRTKeys)( 
    FBXFrame * boneFrame,                                   // 
    FBXAnimationKeySet & animationKeySet,
    uint *pAnimationIndex) ;					// Returns the animation index 

/// Compression
  FBXSTDMETHOD(Compress)( 
    uint Flags,                            // Compression flags (use FBXCOMPRESS_STRONG for better results)
    float Lossiness,                        // Compression loss ratio in the [0, 1] range
    FBXFrame * pHierarchy,                 // Frame hierarchy (optional)
    void * *ppCompressedData) ;   // Returns the compressed animation set
  
  FBXSTDMETHOD(UnregisterAnimation)( uint Index) ;
};


typedef smart_ptr<FBXKeyframedAnimationSet> spIFBXKeyframedAnimationSet;

//----------------------------------------------------------------------------
// FBXCompressedAnimationSet:
// ----------------------------
// This interface implements a compressed keyframed animation set.
//----------------------------------------------------------------------------


class FBXCompressedAnimationSet: public IFBXAnimationSet
{
public:
  // Name
  FBXSTDMETHOD_(const char * , GetName)(void) ;

  // Period
  FBXSTDMETHOD_(double, GetPeriod)(void) ;
  FBXSTDMETHOD_(double, GetPeriodicPosition)( double Position) ;    // Maps position into animation period

  // Animation names
  FBXSTDMETHOD_(uint, GetNumAnimations)(void) ;
  FBXSTDMETHOD(GetAnimationNameByIndex)( UINT Index, const char *  *ppName) ;
  FBXSTDMETHOD(GetAnimationIndexByName)( const char *  pName, UINT *pIndex) ;

  // SRT
  FBXSTDMETHOD(GetSRT)( 
    double PeriodicPosition,            // Position mapped to period (use GetPeriodicPosition)
    UINT Animation,                     // Animation index
    FBXVector3 *pScale,                // Returns the scale
    FBXVector3 *pRotation,          // Returns the rotation as a quaternion
    FBXVector3 *pTranslation) ;    // Returns the translation

  // Callbacks
  FBXSTDMETHOD(GetCallback)( 
    double Position,                    // Position from which to find callbacks
    uint Flags,                        // Callback search flags
    double *pCallbackPosition,          // Returns the position of the callback
    LPVOID *ppCallbackData) ;       // Returns the callback data pointer

  // Playback
  FBXSTDMETHOD_(FBXPlaybackType, GetPlaybackType)(void) ;
  FBXSTDMETHOD_(double, GetSourceTicksPerSecond)(void) ;

  // Scale keys
  //FBXSTDMETHOD(GetCompressedData)( IFBXBuffer * *ppCompressedData) ;

  // Callback keys
  FBXSTDMETHOD_(UINT, GetNumCallbackKeys)(void) ;
  FBXSTDMETHOD(GetCallbackKeys)( FBXKeyCallback * pCallbackKeys) ;
};

typedef smart_ptr<FBXCompressedAnimationSet> spFBXCompressedAnimationSet;


//----------------------------------------------------------------------------
// FBXPRIORITY_TYPE:
// ------------------
// This enum defines the type of priority group that a track can be assigned to.
//----------------------------------------------------------------------------
typedef enum FBXPriorityType 
{
  FBXPRIORITY_LOW         = 0,           // This track should be blended with all low priority tracks before mixed with the high priority result
  FBXPRIORITY_HIGH        = 1,           // This track should be blended with all high priority tracks before mixed with the low priority result

  FBXPRIORITY_FORCE_DWORD = 0x7fffffff,  /* force 32-bit size enum */
};

//----------------------------------------------------------------------------
// FBXTRACK_DESC:
// ---------------
// This structure describes the mixing information of an animation track. 
// The mixing information consists of the current position, speed, and blending 
// weight for the track.  The Flags field also specifies whether the track is 
// low or high priority.  Tracks with the same priority are blended together
// and then the two resulting values are blended using the priority blend factor.
// A track also has an animation set (stored separately) associated with it.  
//----------------------------------------------------------------------------

class FBXTrackDescription
{
public:
  FBXPriorityType     priority;
  float               weight;
  float               speed;
  double              position;
  bool                enable;
};

//-------

//----------------------------------------------------------------------------
// FBXEventType:
// ---------------
// This enum defines the type of events keyable via the animation controller.
//----------------------------------------------------------------------------
typedef enum FBXEventType
{
  FBXEVENT_TRACKSPEED  = 0,
  FBXEVENT_TRACKWEIGHT   = 1,
  FBXEVENT_TRACKPOSITION = 2,
  FBXEVENT_TRACKENABLE   = 3,
  FBXEVENT_PRIORITYBLEND = 4,

  FBXEVENT_TRACKSPEED_RESTORE,
  FBXEVENT_TRACKWEIGHT_RESTORE,
  FBXEVENT_PRIORITYBLEND_RESTORE,


  FBXEVENT_FORCE_DWORD   = 0x7fffffff, /* force 32-bit size enum */
} ;

//----------------------------------------------------------------------------
// FBXTransitionType:
// --------------------
// This enum defines the type of transtion performed on a event that 
// transitions from one value to another.
//----------------------------------------------------------------------------
typedef enum FBXTransitionType 
{
  FBXTRANSITION_LINEAR        = 0x000,     // Linear transition from one value to the next
  FBXTRANSITION_EASEINEASEOUT = 0x001,     // Ease-In Ease-Out spline transition from one value to the next

  FBXTRANSITION_FORCE_DWORD   = 0x7fffffff, /* force 32-bit size enum */
};

//----------------------------------------------------------------------------
// FBXEVENT_DESC:
// ---------------
// This structure describes a animation controller event.
// It gives the event's type, track (if the event is a track event), global 
// start time, duration, transition method, and target value.
//----------------------------------------------------------------------------
class FBXEventDescription
{
public:
  FBXEventType        type;
  UINT                trackIndex;
  double              startTime;
  double              duration;
  FBXTransitionType   transition;
  union
  {
    float           weight;
    float           speed;
    double          position;
    bool            enable;
  };
  union
  {
    float           saveWeight;
    float           saveSpeed;
    double          saveBlend;
    //double          Position; not restored
    //bool            Enable;
  };
  

};

//----------------------------------------------------------------------------
// FBXEventHandle:
// ----------------
// Handle values used to efficiently reference animation controller events.
//----------------------------------------------------------------------------
//typedef void * FBXEventHandle;


//----------------------------------------------------------------------------
// IFBXAnimationCallbackHandler:
// ------------------------------
// This interface is intended to be implemented by the application, and can
// be used to handle callbacks in animation sets generated when 
// FBXAnimationController::AdvanceTime() is called.  
//----------------------------------------------------------------------------

class IFBXAnimationCallbackHandler
{
public:
  //----------------------------------------------------------------------------
  // IFBXAnimationCallbackHandler::HandleCallback:
  // ----------------------------------------------
  // This method gets called when a callback occurs for an animation set in one
  // of the tracks during the FBXAnimationController::AdvanceTime() call.  
  //
  // Parameters:
  //  Track
  //      Index of the track on which the callback occured.
  //  pCallbackData
  //      Pointer to user owned callback data.
  //
  //----------------------------------------------------------------------------
  FBXSTDMETHOD(HandleCallback)( UINT TrackIndex, LPVOID pCallbackData) ; 
};


//----------------------------------------------------------------------------
// FBXAnimationController:
// -------------------------
// This interface implements the main animation functionality. It connects
// animation sets with the transform frames that are being animated. Allows
// mixing multiple animations for blended animations or for transistions
// It adds also has methods to modify blending parameters over time to 
// enable smooth transistions and other effects.
//----------------------------------------------------------------------------


typedef std::map<double, FBXEventDescription> FBXEventList;

// map a handle to the event itself
typedef  FBXEventList::iterator FBXEventHandle;




class FBXEventManager
{
public:

  FBXEventManager()
  {
  }


  FBXEventList m_eventList;

  std::set<FBXEventHandle> m_activeEvents; 

  void clear();

  FBXEventHandle AddEvent(FBXEventDescription &event);
  HRESULT GetNextEvent(FBXEventHandle &event, FBXEventHandle &nextEvent);


  FBXEventDescription & GetEvent(FBXEventHandle & handle)
  {
    return handle->second;
  }


};

class FBXTrack
{
public:
  FBXTrack()
  {
    animSet = 0;
    desc.enable = false;
    desc.weight = 1;
    desc.speed = 30;
    desc.position = 0;
    desc.priority = FBXPRIORITY_LOW;


  }
  IFBXAnimationSet * animSet;

  FBXTrackDescription desc;

  FBXEventManager eventManager;

  FBXEventHandle AddEvent(FBXEventDescription event);

  // need copy of event
  FBXEventHandle AddTrackEvent(int trackIndex, FBXEventDescription  event);

};

typedef std::map<FBXFrame*, FBXMatrix *> BoneToMatrixMap;
                      




class FBXAnimationController;
typedef smart_ptr<FBXAnimationController> spIFBXAnimationController;


class FBXAnimationController
{
public:
  FBXAnimationController()
  {
    m_time = 0;
    // updated by adding animations
    m_timeStart = FLT_MAX;
    m_timeStop = -FLT_MAX;
    m_priorityBlendingWeight = 0;
  }
  double m_time;
  double m_timeStop;
  double m_timeStart;

  double m_priorityBlendingWeight;

  FBXEventManager m_controllerEventManager;

 


  BoneToMatrixMap m_boneToMatrixMap;
  std::vector<FBXTrack> m_trackList;

  std::vector<spIFBXAnimationSet> m_animationSetList;
  std::vector<int> m_freeAnimationSetListIndices;








  FBXSTDMETHOD_(uint, GetNumTracks)();

  HRESULT AddEvent(FBXEventDescription event, FBXEventHandle & handle);

  // need copy of event
  HRESULT AddTrackEvent(int trackIndex, FBXEventDescription  event, FBXEventHandle & eventHande);

  // Animation output registration
  FBXSTDMETHOD(RegisterAnimationOutput)( 
    FBXFrame* pFrame, 
    FBXMatrix *pMatrix, 
    FBXVector3 *pScale, 
    FBXVector3 *pRotation, 
    FBXVector3 *pTranslation) ;

  // Animation set registration
  FBXSTDMETHOD(RegisterAnimationSet)( IFBXAnimationSet * pAnimSet) ;
  FBXSTDMETHOD(RegisterAnimationSet)( spIFBXAnimationSet & pAnimSet) ;
  FBXSTDMETHOD(RegisterAnimationSet)( spIFBXKeyframedAnimationSet & pAnimSet) ;
  FBXSTDMETHOD(UnregisterAnimationSet)( IFBXAnimationSet * pAnimSet) ;

  FBXSTDMETHOD_(uint, GetNumAnimationSets)(void) ;
  FBXSTDMETHOD(GetAnimationSet)( UINT Index, IFBXAnimationSet * *ppAnimationSet) ;
  FBXSTDMETHOD(GetAnimationSetByName)( const char *  szName, IFBXAnimationSet * *ppAnimationSet) ;

  // Global time
  FBXSTDMETHOD(AdvanceTime)( double TimeDelta, IFBXAnimationCallbackHandler * pCallbackHandler) ;
  FBXSTDMETHOD(ResetTime)(void) ;
  FBXSTDMETHOD(ResetTimeIfLooped)(void) ;
  FBXSTDMETHOD_(double, GetTime)(void) ;

  // Tracks
  FBXSTDMETHOD(SetTrackAnimationSet)( UINT TrackIndex, IFBXAnimationSet * pAnimSet) ;
  FBXSTDMETHOD(GetTrackAnimationSet)( UINT TrackIndex, IFBXAnimationSet * *ppAnimSet) ;

  FBXSTDMETHOD(SetTrackPriority)( UINT TrackIndex, FBXPriorityType priority) ;

  FBXSTDMETHOD(SetTrackSpeed)( UINT TrackIndex, float speed) ;
  FBXSTDMETHOD(SetTrackWeight)( UINT TrackIndex, float weight) ;
  FBXSTDMETHOD(SetTrackPosition)( UINT TrackIndex, double position) ;
  FBXSTDMETHOD(SetTrackEnable)( UINT TrackIndex, bool Enable) ;

  FBXSTDMETHOD(SetTrackDesc)( UINT TrackIndex, FBXTrackDescription * pDesc) ;
  FBXSTDMETHOD(GetTrackDesc)( UINT TrackIndex, FBXTrackDescription * pDesc) ;

  // Priority blending
  FBXSTDMETHOD(SetPriorityBlend)( float BlendWeight) ;
  FBXSTDMETHOD_(float, GetPriorityBlend)(void) ;

  // Event keying
  FBXSTDMETHOD(KeyTrackSpeed)( UINT TrackIndex, float NewSpeed, double StartTime, double Duration, FBXTransitionType Transition, FBXEventHandle & eventHandle) ;
  FBXSTDMETHOD(KeyTrackWeight)( UINT TrackIndex, float NewWeight, double StartTime, double Duration, FBXTransitionType Transition, FBXEventHandle & eventHandle) ;
  FBXSTDMETHOD(KeyTrackPosition)( UINT TrackIndex, double NewPosition, double StartTime, FBXEventHandle & eventHandle) ;
  FBXSTDMETHOD(KeyTrackEnable)( UINT TrackIndex, bool NewEnable, double StartTime, FBXEventHandle & eventHandle) ;

  FBXSTDMETHOD(KeyPriorityBlend)( float NewBlendWeight, double StartTime, double Duration, FBXTransitionType Transition, FBXEventHandle & eventHandle) ;

  // Event unkeying
  FBXSTDMETHOD(UnkeyEvent)( FBXEventHandle &hEvent) ;

  FBXSTDMETHOD(UnkeyAllTrackEvents)( UINT TrackIndex) ;
  FBXSTDMETHOD(UnkeyAllPriorityBlends)(void) ;

  // Event enumeration
  FBXSTDMETHOD(GetCurrentTrackEvent)( UINT TrackIndex, FBXEventType EventType, FBXEventHandle & eventHandle) ;
  FBXSTDMETHOD(GetCurrentPriorityBlend)(FBXEventHandle & eventHandle) ;

  FBXSTDMETHOD(GetUpcomingTrackEvent)( UINT Track, FBXEventHandle &hEvent, FBXEventHandle & eventHandle) ;
  FBXSTDMETHOD(GetUpcomingPriorityBlend)( FBXEventHandle &hEvent, FBXEventHandle & eventHandle) ;

  FBXSTDMETHOD(ValidateEvent)( FBXEventHandle &hEvent) ;

  FBXSTDMETHOD(GetEventDesc)( FBXEventHandle &hEvent, FBXEventDescription *pDesc) ;

  // Cloning
  FBXSTDMETHOD(CloneAnimationController)( spIFBXAnimationController &pAnimController) ;
};






//----------------------------------------------------------------------------
// FBXFrameAppendChild:
// ---------------------
// Add a child frame to a frame
//
// Parameters:
//	pFrameParent
//		Pointer to the parent node
//  pFrameChild
//      Pointer to the child node
//
//----------------------------------------------------------------------------





//----------------------------------------------------------------------------
// FBXFrameCalculateBoundingSphere:
// ---------------------------------
// Computes the bounding sphere of all the meshes in the frame hierarchy.
//
// Parameters:
//	pFrameRoot
//		Pointer to the root node
//	pObjectCenter
//		Returns the center of the bounding sphere
//	pObjectRadius
//		Returns the radius of the bounding sphere
//
//----------------------------------------------------------------------------
HRESULT 
FBXFrameCalculateBoundingSphere
(
 CONST FBXFrame *pFrameRoot,       
 FBXVector3 * pObjectCenter,  
 float *pObjectRadius          
 );


//----------------------------------------------------------------------------
// FBXCreateKeyframedAnimationSet:
// --------------------------------
// This function creates a compressable keyframed animations set interface.
// 
// Parameters:
//  pName
//      Name of the animation set
//  TicksPerSecond
//      Number of keyframe ticks that elapse per second
//  Playback
//      Playback mode of keyframe looping
//  NumAnimations
//      Number of SRT animations
//  NumCallbackKeys
//      Number of callback keys
//  pCallbackKeys
//      Array of callback keys
//  ppAnimationSet
//      Returns the animation set interface
// 
//-----------------------------------------------------------------------------		
HRESULT 
FBXCreateKeyframedAnimationSet
(
 const char *  pName,                               
 double TicksPerSecond,
 FBXPlaybackType Playback,
 UINT NumCallbackKeys,                       
 CONST FBXKeyCallback *pCallbackKeys,           
 spIFBXKeyframedAnimationSet &pAnimationSet 
 );


//----------------------------------------------------------------------------
// FBXCreateCompressedAnimationSet:
// --------------------------------
// This function creates a compressed animations set interface from 
// compressed data.
// 
// Parameters:
//  pName
//      Name of the animation set
//  TicksPerSecond
//      Number of keyframe ticks that elapse per second
//  Playback
//      Playback mode of keyframe looping
//  pCompressedData
//      Compressed animation SRT data
//  NumCallbackKeys
//      Number of callback keys
//  pCallbackKeys
//      Array of callback keys
//  ppAnimationSet
//      Returns the animation set interface
// 
//-----------------------------------------------------------------------------		
HRESULT 
FBXCreateCompressedAnimationSet
(
 const char *  pName,                               
 double TicksPerSecond,
 FBXPlaybackType Playback,
 void * pCompressedData,                         
 UINT NumCallbackKeys,                       
 CONST FBXKeyCallback *pCallbackKeys,           
 FBXCompressedAnimationSet  ** ppAnimationSet 
 );


//----------------------------------------------------------------------------
// FBXCreateAnimationController:
// ------------------------------
// This function creates an animation controller object.
//
// Parameters:
//  ppAnimController
//      Returns the animation controller interface
//
//-----------------------------------------------------------------------------		
HRESULT FBXCreateAnimationController( spIFBXAnimationController &ppAnimController);
HRESULT  FBXFrameDestroy(FBXFrame * pFrameRoot,IFBXAllocateHierarchy * pAlloc);

typedef smart_ptr<FBXAnimationController> spIFBXAnimationController;
typedef smart_ptr<IFBXAllocateHierarchy> spIFBXAllocateHierarchy;

HRESULT LoadMeshHierarchyFromFBX( const char * filename, 
  IFBXAllocateHierarchy * pAllocHierarchy, 
  FBXFrame *  *ppFrameHierarchy, 
  spIFBXAnimationController &ppAnimController);


HRESULT LoadMeshHierarchyFromOBJ( const char * filename, 
  IFBXAllocateHierarchy * pAllocHierarchy, 
  FBXFrame *  *ppFrameHierarchy, 
  spIFBXAnimationController &ppAnimController);

void MatrixConvert(KFbxXMatrix & fbxMatrix, FBXMatrix & d3dMatrix);


class FBXAnimationSet
{
public:
	FBXAnimationSet()
	{
		numKeyFrameSets = 0;

		animationName.clear();
	}
	std::string animationName;
	int numKeyFrameSets;
	spIFBXKeyframedAnimationSet keyFramedAnimationSet;    

};

typedef std::set< FBXFrame *> FBXFrameSet;

typedef std::set< std::string> NameSet;
typedef std::vector< std::string> NameList;

typedef smart_ptr<FBXAnimationSet> spFBXAnimationSet;

typedef std::map< std::string, spFBXAnimationSet> TakeNameToAnimationSetMap;
typedef std::pair< std::string, FBXAnimationSet> TakeMapNode;

// time, keyValue
typedef std::map< KTime, float> TimeKeyMap;

typedef std::set<KTime> TimeSet;






class FBXMeshLoader
{
public:

  UvNameSetMap uvSetNameMap;


  FBXTextureCoordsListArray    m_textureCoordsListArray;
  std::string               m_strMediaDir;               // Directory where the mesh was found

	FBXMeshLoader();

	~FBXMeshLoader();

	HRESULT Create( const WCHAR* strFilename );       

	void LoadMaterialsFromNode(spFBXMesh & spMesh, IFBXAllocateHierarchy * pAlloc, KFbxNode* pNode);
	void CreateEffectInstancesFromMaterials(std::vector<FBXMaterial> &materials, 
		std::vector<FBXEffectInstance> &effectInstances,
		std::list<std::vector<FBXEffectDefault> >&defaultValuesList);

	HRESULT CreateMeshObject( 
		IFBXAllocateHierarchy * pAlloc, 
		FBXFrame * pFrame,
		KFbxNode* pNode,
    NodeToFrameMap & nodeToFrameMap);

	// map name to set number



	HRESULT CreateBoneStructure( 
		KFbxNode* pNode, 
    FBXVertexSkinning * * pSkinInfo, 
		int nVerts,
		ControlPointRemap & controlPointRemap,
    NodeToFrameMap & nodeToFrameMap);

	void SetMaterial(KFbxSurfaceMaterial *lMaterial, FBXMaterial & material);




	const char* GetMediaDirectory() { return m_strMediaDir.c_str(); }
  int GetBoneCount(KFbxNode* pNode);

private:

	void LoadGeometryFromNode(spFBXMesh & spMesh, KFbxNode* pNode, FBXFrame * pFrame, 
		ControlPointRemap & controlPointRemap);

	void LoadAttributeIDsFromLayer(spFBXMesh & spMesh,  KFbxNode* pNode, KFbxMesh* pMesh, KFbxLayer * pLayer);


	HRESULT LoadGeometryFromNode(spFBXMesh & spMesh, KFbxNode* pNode, bool bSplit, ControlPointRemap & controlPointRemap );

	void LoadTextureCoordinatesFromLayer(spFBXMesh & spMesh,  KFbxMesh* pFBXMesh, KFbxLayer * pLayer, bool bSplit);    

	void LoadTextureCoordinatesFromElement(spFBXMesh & spMesh,  KFbxMesh* pFBXMesh, 
		KFbxLayer * pLayer,
		KFbxLayerElement::ELayerElementType pTypeIdentifier, bool bSplit);    



	bool CheckMaterialsFromLayer( KFbxMesh* pFBXMesh, KFbxLayer * pLayer);
	bool CheckTexturesFromLayer( KFbxMesh* pFBXMesh, KFbxLayer * pLayer);    
	void CheckLayer( KFbxMesh* pFBXMesh, KFbxLayer * pLayer);    



	bool CheckTexturesFromElement( KFbxMesh* pFBXMesh, 
		KFbxLayer * pLayer,
		KFbxLayerElement::ELayerElementType pTypeIdentifier);    

	void  InitMaterial( FBXMaterial& pMaterial );


  void clear()
  {
    uvSetNameMap.clear();
    m_textureCoordsListArray.clear();
    m_strMediaDir.clear();               // Directory where the mesh was found

  }
  
};



class FBXLoader : 	public FBXMeshLoader
{
	KFbxScene* m_scene;
  std::string m_currentTake;
  KFbxAnimLayer* m_animLayer;
  KFbxAnimStack* m_animStack;

public:

  AnimationStackMap m_animationStackMap; // to get stack from name

  NodeToFrameMap m_nodeToFrameMap;

  ConstraintMap m_constraintMap;
  uint m_NumAnimations;

  std::vector<std::string> m_takeNameList;
  NameSet m_cameraSet;
  std::string m_cameraDefault;
  NameSet m_lightSet;

  TakeNameToAnimationSetMap m_takeNameToAnimationSetMap;

  FBXFrame * m_pRootFrame;

  int m_SDKMajor,  m_SDKMinor,  m_SDKRevision;

  smart_ptr<KFbxSdkManager> m_SdkManager;
  smart_ptr<KFbxImporter> m_importer;
  KString m_FileName;


  FBXFrame * *m_ppFrameHierarchy;



	KFbxScene* GetScene()
  {
    return m_scene;
  }


  KFbxAnimLayer* GetAnimationLayer()
  {
    return m_animLayer;
  }

  const char * GetCurrentTakeName()
  {
    return m_currentTake.c_str(); 
  }
  void SetCurrentTake(const char* pName)
  {
    m_currentTake = pName;
    assert(m_animationStackMap.find(m_currentTake) !=  m_animationStackMap.end());

    m_animStack = m_animationStackMap[m_currentTake];
    GetScene()->GetEvaluator()->SetContext(m_animStack);

    int layerNo = 0;
    m_animLayer = m_animStack->GetMember(FBX_TYPE(KFbxAnimLayer), layerNo);


  }




	void PreparePointCacheData(KFbxScene* pScene);
	void ConvertNurbsAndPatch(KFbxSdkManager* pSdkManager, KFbxScene* pScene);
	void ConvertNurbsAndPatchRecursive(KFbxSdkManager* pSdkManager, KFbxNode* pNode);

	KFbxXMatrix GetPoseMatrix(KFbxPose* pPose, int pNodeIndex);

	IFBXAllocateHierarchy *m_pAllocHierarchy;
	spIFBXAnimationController m_spAnimController;

	void LoadSupportedTextures(KFbxScene* pScene);
	void LoadTexture(KFbxTexture* pTexture);
	void ConvertAnimation(KFbxNode* pNode);
	void ConvertAnimation(KFbxScene* pScene);

  HRESULT  FBXFrameAppendChild(FBXFrame * pFrameParent,CONST FBXFrame *pFrameChild);

  KFbxSdkManager * InitializeSDKObjects(KFbxScene*& pScene);

	void LoadSupportedTexturesRecursive(KFbxNode* pNode);
	void SetNodeProperties(KFbxNode* pNode, KFbxPose* pPose, FBXFrame * pFrame);


	FBXFrame *FindFrameRecursive(FBXFrame* pFrame,std::string name);
	void CreateMesh(KFbxXMatrix& pGlobalPosition, KFbxMesh* pMesh);
	void ProcessNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessMeshNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessSkeletonNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessMarkerNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessCameraNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessLightNode(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessNodeRecursive(KFbxNode* pNode, KFbxPose* pPose, FBXFrame *pFrame);
	void ProcessScene(KFbxScene* pScene, int pPoseIndex = -1);

	FBXFrame *CreateFramesInSceneRecursive(KFbxNode* pNode);
	FBXFrame *CreateFramesInScene(KFbxScene* pScene);

	void CountAnimationElementsRecursive(KFbxNode* pScene);
	void CountAnimationElements(KFbxScene* pScene);
	void CountAnimationElements(KFbxNode* pScene);



	//Collect all the names of takes cameras and lights.
	void CollectNamesRecursive(KFbxAnimStack*pAnimStack,KFbxNode* pNode);
  void CollectNamesRecursive(KFbxAnimLayer* pAnimLayer, KFbxNode* pNode);
	void CollectNames(KFbxScene* pScene);


	void AddAnimation(KFbxScene* pScene);
	void AddAnimation(KFbxAnimLayer* pAnimLayer, KFbxNode* node, std::string &takeName, 
    FBXAnimationSet *pAnimationSet, FBXFrame * pFrame);
	void AddAnimationRecursive(KFbxAnimLayer* pAnimLayer, KFbxNode* node, std::string &takeName, 
    FBXAnimationSet *pAnimationSet, FBXFrame *pFrame);
	void AddAnimationRecursive(KFbxAnimStack* pAnimStack, KFbxNode* node, FBXFrame *pFrame);
	bool AnimationTake(KFbxAnimLayer* pAnimLayer, KFbxNode* node,  std::string &takeName, 
    FBXAnimationKeySet & animationKeySet);
  bool ConstraintAnimationTake(KFbxAnimLayer* pAnimLayer,KFbxNode* pNode, std::string &takeName, 
    FBXAnimationKeySet & animationKeySet);


	void ComputeShapeDeformation(KFbxNode* pNode, KFbxMesh* pMesh);

	void MatrixScale(KFbxXMatrix& pMatrix, double pValue);
	void MatrixAddToDiagonal(KFbxXMatrix& pMatrix, double pValue);
	void MatrixAdd(KFbxXMatrix& pDstMatrix, KFbxXMatrix& pSrcMatrix);

	HRESULT LoadScene(KFbxSdkManager* pSdkManager, const char* pFilename);

	HRESULT InitializeFBXSDK();
	void Release();

	void ImportFunction(); 

  FBXLoader()
  {
    m_scene = NULL;
    m_ppFrameHierarchy = 0;
    m_cameraDefault="";

    m_animLayer = NULL;
    m_animStack = NULL;

  }              
	~FBXLoader();

	HRESULT ReadFBX(const char * filename,
		IFBXAllocateHierarchy * allocateHierarchy ,
		FBXFrame * *ppFrameHierarchy,
		spIFBXAnimationController & spAnimController);

  HRESULT ReadOBJ(const char * filename,
    IFBXAllocateHierarchy * allocateHierarchy ,
    FBXFrame * *ppFrameHierarchy,
    spIFBXAnimationController & spAnimController);


};



KFbxXMatrix GetDefaultPosition(KFbxNode* pNode);
KFbxXMatrix GetGeometry(KFbxNode* pNode);

void MatrixConvert(KFbxXMatrix & fbxMatrix, FBXMatrix & d3dMatrix);


void GetLocalRotation(KFbxNode* pNode, KFbxXMatrix & preMatrix, KFbxXMatrix & postMatrix);
void GetLocalScaling(KFbxNode* pNode, KFbxXMatrix & preMatrix, KFbxXMatrix & postMatrix);



HRESULT FBXFrameCalculateBoundingSphere(CONST FBXFrame *pFrameRoot,       FBXVector3* pObjectCenter,  float *pObjectRadius );



void dprintf(const char * format, ... );
void dprintf(const wchar_t * format, ... );
#define NUM_SURFACE_MATERIALS 16
extern char * AllSurfaceMaterialsNames[NUM_SURFACE_MATERIALS];


bool HasSomeFCurves(KFbxObject* pNode, KFbxAnimLayer* pAnimLayer);

void DisplayMetaDataConnections(FBXFILESDK_NAMESPACE::KFbxObject* pNode);
void DisplayString(const char* pHeader, const char* pValue  = "", const char* pSuffix  = "");
void DisplayBool(const char* pHeader, bool pValue, const char* pSuffix  = "");
void DisplayInt(const char* pHeader, int pValue, const char* pSuffix  = "");
void DisplayDouble(const char* pHeader, double pValue, const char* pSuffix  = "");
void Display2DVector(const char* pHeader, FBXFILESDK_NAMESPACE::KFbxVector2 pValue, const char* pSuffix  = "");
void Display3DVector(const char* pHeader, FBXFILESDK_NAMESPACE::KFbxVector4 pValue, const char* pSuffix  = "");
void DisplayColor(const char* pHeader, FBXFILESDK_NAMESPACE::KFbxColor pValue, const char* pSuffix  = "");
void Display4DVector(const char* pHeader, FBXFILESDK_NAMESPACE::KFbxVector4 pValue, const char* pSuffix  = "");



class FileOptions
{
public:
  FileOptions()
  {


    bForceChartGeneration = false;
    bForceOneMaterial = false;
    bRePackTextureCoordinates = false;

    bGenerateObjectSpaceNormalMap = true;
    bFlipFaces = false;
    bCalcNormals = false;
    bCalcTextureCoordinates = false;

    m_width = 1024;
    m_height = 1024;
    m_borderPadding = 16;
    maxFacesPerChart = 5000;   // maxFacesPerChart = 0 means no limit
    m_fPackStep = 0.95;
    sharpChartAngleCos = 1.0/3.0;
    bEnableDistortionCheck = true;
    bEnableSharpCheck = true;

    maxAveDistortion = 10;
    maxDistortion = 20;
    maxRatioError = 10;
    maxStdDevError = 10;

  }
  int m_width, m_height;
  int m_borderPadding; // in texels
  double m_fPackStep;
  int maxFacesPerChart;
  double sharpChartAngleCos;

  int bEnableDistortionCheck;
  int bEnableSharpCheck;

  double maxDistortion;
  double maxAveDistortion;

  double maxRatioError;
  double maxStdDevError;


  bool bFlipFaces;
  bool bForceChartGeneration;
  bool bForceOneMaterial;
  bool bCalcNormals;
  bool bCalcTextureCoordinates;
  bool bRePackTextureCoordinates;
  bool bGenerateObjectSpaceNormalMap;
};

extern FileOptions g_fileOptions;

FBXVector3 TriangleNormal(const FBXVector3& v1, const FBXVector3& v2, const FBXVector3& v3);
