- Main Page
- Classes
- Files
- Directories
- Examples

# ExportScene03/main.cxx

    /****************************************************************************************

       Copyright (C) 2012 Autodesk, Inc.
       All rights reserved.

       Use of this software is subject to the terms of the Autodesk license agreement
       provided at the time of installation or download, or which otherwise accompanies
       this software in either electronic or hard copy form.

    ****************************************************************************************/

    //
    // The scene created in this example is a textured cube, a pyramid
    // with materials mapped on it's faces and triangle deformed by vertex cache.
    // An animation stack displays 6 different angles of all models.
    //
    // The example illustrates how to:
    //        1) create a cube in mesh
    //        2) map textures on diffuse, ambient and emissive channel of the cube
    //        3) create an UV set for each channel with a texture for the cube
    //        4) create a pyramid in mesh
    //        5) create and map materials on the diffuse channel for each faces of the pyramid
    //        6) create a cube with our custom mesh type
    //        7) create and map materials on the diffuse channel for our custom mesh cube
    //        8) create and add to our custom meshed cube a User Data Layer
    //        9) create vertex cache deformer
    //       10) create an animation stack
    //       11) animate vertex
    //       12) export a scene in a .FBX file
    //
    //
    // 1. To test vertex (3 doubles) cache (default) :
    //
    // ./ExportScene03 cacheFileName
    //
    // 2. To test int32 cache :
    //
    // ./ExportScene03 cacheFileName 1
    //

    #include <fbxsdk.h>

    #include "../Common/Common.h"
    #include "MyKFbxMesh.h"

    #define SAMPLE_FILENAME_MC "ExportScene03_MC.fbx"
    #define SAMPLE_FILENAME_PC2 "ExportScene03_PC2.fbx"
    #define PID_MY_GEOMETRY_LEMENT 0

    // Function prototypes.
    bool CreateScene(FbxScene* pScene, char* pSampleFileName);

    FbxNode* CreateCubeWithTexture(FbxScene* pScene, char* pName);
    FbxNode* CreatePyramidWithMaterials(FbxScene* pScene, char* pName);
    FbxNode* CreateTriangle(FbxScene* pScene, char* pName);
    FbxNode* CreateCubeWithMaterialAndMyKFbxMesh(FbxScene* pScene, char* pName);

    void CreateTexture(FbxScene* pScene, FbxMesh* pMesh);
    void CreateMaterials(FbxScene* pScene, FbxMesh* pMesh);
    void CreateMaterialsWithMyKFbxMesh(FbxScene* pScene, MyKFbxMesh* pMyKFbxMesh);

    void MapShapeOnPyramid(FbxScene* pScene, FbxNode* pPyramid);
    void MapVertexCacheOnTriangle(FbxScene* pScene, FbxNode* pTriangle, char* pSampleFileName);

    void SetCubeDefaultPosition(FbxNode* pCube);
    void SetPyramidDefaultPosition(FbxNode* pPyramid);
    void SetTriangleDefaultPosition(FbxNode* pTriangle);
    void SetMyKFbxMeshCubeDefaultPosition(FbxNode* pMyKFbxCube);

    void Animate(FbxNode* pNode, FbxAnimLayer* pAnimLayer);
    void AnimateVertexCacheOnTriangleDoubleVertex(FbxNode* pNode, double pFrameRate);
    void AnimateVertexCacheOnTriangleInt32(FbxNode* pNode, double pFrameRate);
    void AnimateVertexCacheOnTriangleFloat(FbxNode* pNode, double pFrameRate);

    bool gExportVertexCacheMCFormat = true;

    // gCacheType == 0 (default)  - double vertex array
    //            == 1            - int32 array
    int  gCacheType = 2;

    int main(int argc, char** argv)
    {
        FbxManager* lSdkManager = NULL;
        FbxScene* lScene = NULL;
        char* lSampleFileName = NULL;
        bool lResult;

        // Prepare the FBX SDK.
        InitializeSdkObjects(lSdkManager, lScene);

        //Add the new class we have created to the Sdk Manager
        //Our class MyKFbxMesh is derived from FbxMesh
        lSdkManager->RegisterFbxClass("MyKFbxMesh", FBX_TYPE(MyKFbxMesh), FBX_TYPE(FbxMesh));
        //Now, our class MyKFbxMesh is ready to be used

        lSdkManager->RegisterFbxClass("MyFbxObject", FBX_TYPE(MyFbxObject), FBX_TYPE(FbxObject), "MyFbxObjectType", "MyFbxObjectSubType");

        // The example can take an output file name as an argument.
        if(argc > 1)
        {
            lSampleFileName = argv[1];
        }
        // A default output file name is given otherwise.
        else
        {
            lSampleFileName = gExportVertexCacheMCFormat ? (char *)SAMPLE_FILENAME_MC : (char *)SAMPLE_FILENAME_PC2;
        }

        if(argc > 2)
        {
            gCacheType = atoi(argv[2]);
        }

        // Create the scene.
        lResult = CreateScene(lScene, lSampleFileName);

        if(lResult == false)
        {
            FBXSDK_printf("\n\nAn error occurred while creating the scene...\n");
            DestroySdkObjects(lSdkManager);
            return 0;
        }

        // Save the scene.
        lResult = SaveScene(lSdkManager, lScene, lSampleFileName);

        if(lResult == false)
        {
            FBXSDK_printf("\n\nAn error occurred while saving the scene...\n");
            DestroySdkObjects(lSdkManager);
            return 0;
        }

        // Destroy all objects created by the FBX SDK.
        DestroySdkObjects(lSdkManager);

        return 0;
    }

    bool CreateScene(FbxScene* pScene, char* pSampleFileName)
    {
        FbxNode* lCube = CreateCubeWithTexture(pScene, "Cube");
        FbxNode* lPyramid = CreatePyramidWithMaterials(pScene, "Pyramid");
        FbxNode* lTriangle = CreateTriangle(pScene, "Triangle");
        FbxNode* lMyKFbxMeshCube = CreateCubeWithMaterialAndMyKFbxMesh(pScene, "CubeMyKFbxMesh");
        MyFbxObject* lMyFbxObject = MyFbxObject::Create(pScene, "MyFbxObject 1");

        MapShapeOnPyramid(pScene, lPyramid);
        MapVertexCacheOnTriangle(pScene, lTriangle, pSampleFileName);

        SetCubeDefaultPosition(lCube);
        SetPyramidDefaultPosition(lPyramid);
        SetTriangleDefaultPosition(lTriangle);
        SetMyKFbxMeshCubeDefaultPosition(lMyKFbxMeshCube);

        // Build the node tree.
        FbxNode* lRootNode = pScene->GetRootNode();
        lRootNode->AddChild(lCube);
        lRootNode->AddChild(lPyramid);
        lRootNode->AddChild(lMyKFbxMeshCube);
        lRootNode->AddChild(lTriangle);
        lRootNode->ConnectSrcObject(lMyFbxObject);

        // Create the Animation Stack
        FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, "Show all faces");

        // The animation nodes can only exist on AnimLayers therefore it is mandatory to
        // add at least one AnimLayer to the AnimStack. And for the purpose of this example,
        // one layer is all we need.
        FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
        lAnimStack->AddMember(lAnimLayer);

        //Create a simple animated fcurve
        FbxProperty lMyProperty = lMyFbxObject->FindProperty("MyAnimatedPropertyName");
        if( lMyProperty.IsValid() )
        {
            lMyProperty.Set(0.0);   //Default value
            lMyProperty.ModifyFlag(FbxPropertyAttr::eAnimatable, true);
            lMyProperty.CreateCurveNode(lAnimLayer);
            FbxAnimCurve* lMyFCurve = lMyProperty.GetCurve<FbxAnimCurve>(lAnimLayer, true);
            if( lMyFCurve )
            {
                FbxAnimCurveKey key;

                key.Set(FBXSDK_TIME_ZERO, -100); lMyFCurve->KeyAdd(key.GetTime(), key);
                key.Set(FbxTime(100), 0)   ; lMyFCurve->KeyAdd(key.GetTime(), key);
                key.Set(FbxTime(200), 100) ; lMyFCurve->KeyAdd(key.GetTime(), key);
            }
        }

        Animate(lCube, lAnimLayer);
        Animate(lPyramid, lAnimLayer);
        Animate(lMyKFbxMeshCube, lAnimLayer);
        FbxGlobalSettings& lGlobalSettings = pScene->GetGlobalSettings();

        switch(gCacheType)
        {
        case 0:
        default:
            AnimateVertexCacheOnTriangleDoubleVertex(lTriangle, FbxTime::GetFrameRate(lGlobalSettings.GetTimeMode()));
            break;
        case 1:
            AnimateVertexCacheOnTriangleInt32(lTriangle, FbxTime::GetFrameRate(lGlobalSettings.GetTimeMode()));
            break;
        case 2:
            AnimateVertexCacheOnTriangleFloat(lTriangle, FbxTime::GetFrameRate(lGlobalSettings.GetTimeMode()));
            break;
        }

        return true;
    }

    // Create a cube with a texture.
    FbxNode* CreateCubeWithTexture(FbxScene* pScene, char* pName)
    {
        int i, j;
        FbxMesh* lMesh = FbxMesh::Create(pScene,pName);

        FbxVector4 lControlPoint0(-50, 0, 50);
        FbxVector4 lControlPoint1(50, 0, 50);
        FbxVector4 lControlPoint2(50, 100, 50);
        FbxVector4 lControlPoint3(-50, 100, 50);
        FbxVector4 lControlPoint4(-50, 0, -50);
        FbxVector4 lControlPoint5(50, 0, -50);
        FbxVector4 lControlPoint6(50, 100, -50);
        FbxVector4 lControlPoint7(-50, 100, -50);

        FbxVector4 lNormalXPos(1, 0, 0);
        FbxVector4 lNormalXNeg(-1, 0, 0);
        FbxVector4 lNormalYPos(0, 1, 0);
        FbxVector4 lNormalYNeg(0, -1, 0);
        FbxVector4 lNormalZPos(0, 0, 1);
        FbxVector4 lNormalZNeg(0, 0, -1);

        // Create control points.
        lMesh->InitControlPoints(24);
        FbxVector4* lControlPoints = lMesh->GetControlPoints();

        lControlPoints[0] = lControlPoint0;
        lControlPoints[1] = lControlPoint1;
        lControlPoints[2] = lControlPoint2;
        lControlPoints[3] = lControlPoint3;
        lControlPoints[4] = lControlPoint1;
        lControlPoints[5] = lControlPoint5;
        lControlPoints[6] = lControlPoint6;
        lControlPoints[7] = lControlPoint2;
        lControlPoints[8] = lControlPoint5;
        lControlPoints[9] = lControlPoint4;
        lControlPoints[10] = lControlPoint7;
        lControlPoints[11] = lControlPoint6;
        lControlPoints[12] = lControlPoint4;
        lControlPoints[13] = lControlPoint0;
        lControlPoints[14] = lControlPoint3;
        lControlPoints[15] = lControlPoint7;
        lControlPoints[16] = lControlPoint3;
        lControlPoints[17] = lControlPoint2;
        lControlPoints[18] = lControlPoint6;
        lControlPoints[19] = lControlPoint7;
        lControlPoints[20] = lControlPoint1;
        lControlPoints[21] = lControlPoint0;
        lControlPoints[22] = lControlPoint4;
        lControlPoints[23] = lControlPoint5;

        // We want to have one normal for each vertex (or control point),
        // so we set the mapping mode to eByControlPoint.
        FbxGeometryElementNormal* lGeometryElementNormal= lMesh->CreateElementNormal();

        lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);

        // Here are two different ways to set the normal values.
        bool firstWayNormalCalculations=true;
        if (firstWayNormalCalculations)
        {
            // The first method is to set the actual normal value
            // for every control point.
            lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);

            lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);
        }
        else
        {
            // The second method is to the possible values of the normals
            // in the direct array, and set the index of that value
            // in the index array for every control point.
            lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

            // Add the 6 different normals to the direct array
            lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
            lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);

            // Now for each control point, we need to specify which normal to use
            lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
            lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
        }

        // Array of polygon vertices.
        int lPolygonVertices[] = { 0, 1, 2, 3,
            4, 5, 6, 7,
            8, 9, 10, 11,
            12, 13, 14, 15,
            16, 17, 18, 19,
            20, 21, 22, 23 };

        // Create UV for Diffuse channel
        FbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV( "DiffuseUV");
        FBX_ASSERT( lUVDiffuseElement != NULL);
        lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
        lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        FbxVector2 lVectors0(0, 0);
        FbxVector2 lVectors1(1, 0);
        FbxVector2 lVectors2(1, 1);
        FbxVector2 lVectors3(0, 1);

        lUVDiffuseElement->GetDirectArray().Add(lVectors0);
        lUVDiffuseElement->GetDirectArray().Add(lVectors1);
        lUVDiffuseElement->GetDirectArray().Add(lVectors2);
        lUVDiffuseElement->GetDirectArray().Add(lVectors3);

        // Create UV for Ambient channel
        FbxGeometryElementUV* lUVAmbientElement = lMesh->CreateElementUV("AmbientUV");

        lUVAmbientElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
        lUVAmbientElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        lVectors0.Set(0, 0);
        lVectors1.Set(1, 0);
        lVectors2.Set(0, 0.418586879968643);
        lVectors3.Set(1, 0.418586879968643);

        lUVAmbientElement->GetDirectArray().Add(lVectors0);
        lUVAmbientElement->GetDirectArray().Add(lVectors1);
        lUVAmbientElement->GetDirectArray().Add(lVectors2);
        lUVAmbientElement->GetDirectArray().Add(lVectors3);

        // Create UV for Emissive channel
        FbxGeometryElementUV* lUVEmissiveElement = lMesh->CreateElementUV("EmissiveUV");

        lUVEmissiveElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
        lUVEmissiveElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        lVectors0.Set(0.2343, 0);
        lVectors1.Set(1, 0.555);
        lVectors2.Set(0.333, 0.999);
        lVectors3.Set(0.555, 0.666);

        lUVEmissiveElement->GetDirectArray().Add(lVectors0);
        lUVEmissiveElement->GetDirectArray().Add(lVectors1);
        lUVEmissiveElement->GetDirectArray().Add(lVectors2);
        lUVEmissiveElement->GetDirectArray().Add(lVectors3);

        //Now we have set the UVs as eIndexToDirect reference and in eByPolygonVertex  mapping mode
        //we must update the size of the index array.
        lUVDiffuseElement->GetIndexArray().SetCount(24);
        lUVAmbientElement->GetIndexArray().SetCount(24);
        lUVEmissiveElement->GetIndexArray().SetCount(24);

        // Create polygons. Assign texture and texture UV indices.
        for(i = 0; i < 6; i++)
        {
            //we won't use the default way of assigning textures, as we have
            //textures on more than just the default (diffuse) channel.
            lMesh->BeginPolygon(-1, -1, false);

            for(j = 0; j < 4; j++)
            {
                //this function points
                lMesh->AddPolygon(lPolygonVertices[i*4 + j] // Control point index.
                );
                //Now we have to update the index array of the UVs for diffuse, ambient and emissive
                lUVDiffuseElement->GetIndexArray().SetAt(i*4+j, j);
                lUVAmbientElement->GetIndexArray().SetAt(i*4+j, j);
                lUVEmissiveElement->GetIndexArray().SetAt(i*4+j, j);

            }

            lMesh->EndPolygon ();
        }

        FbxNode* lNode = FbxNode::Create(pScene,pName);

        lNode->SetNodeAttribute(lMesh);
        lNode->SetShadingMode(FbxNode::eTextureShading);

        CreateTexture(pScene, lMesh);

        return lNode;
    }

    // Create a pyramid with materials.
    FbxNode* CreatePyramidWithMaterials(FbxScene* pScene, char* pName)
    {
        int i, j;
        FbxMesh* lMesh = FbxMesh::Create(pScene, pName);

        FbxVector4 lControlPoint0(-50, 0, 50);
        FbxVector4 lControlPoint1(50, 0, 50);
        FbxVector4 lControlPoint2(50, 0, -50);
        FbxVector4 lControlPoint3(-50, 0, -50);
        FbxVector4 lControlPoint4(0, 100, 0);

        FbxVector4 lNormalP0(0, 1, 0);
        FbxVector4 lNormalP1(0, 0.447, 0.894);
        FbxVector4 lNormalP2(0.894, 0.447, 0);
        FbxVector4 lNormalP3(0, 0.447, -0.894);
        FbxVector4 lNormalP4(-0.894, 0.447, 0);

        // Create control points.
        lMesh->InitControlPoints(16);
        FbxVector4* lControlPoints = lMesh->GetControlPoints();

        lControlPoints[0] = lControlPoint0;
        lControlPoints[1] = lControlPoint1;
        lControlPoints[2] = lControlPoint2;
        lControlPoints[3] = lControlPoint3;
        lControlPoints[4] = lControlPoint0;
        lControlPoints[5] = lControlPoint1;
        lControlPoints[6] = lControlPoint4;
        lControlPoints[7] = lControlPoint1;
        lControlPoints[8] = lControlPoint2;
        lControlPoints[9] = lControlPoint4;
        lControlPoints[10] = lControlPoint2;
        lControlPoints[11] = lControlPoint3;
        lControlPoints[12] = lControlPoint4;
        lControlPoints[13] = lControlPoint3;
        lControlPoints[14] = lControlPoint0;
        lControlPoints[15] = lControlPoint4;

        // specify normals per control point.

        FbxGeometryElementNormal* lNormalElement= lMesh->CreateElementNormal();
        lNormalElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
        lNormalElement->SetReferenceMode(FbxGeometryElement::eDirect);

        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP4);
        lNormalElement->GetDirectArray().Add(lNormalP4);
        lNormalElement->GetDirectArray().Add(lNormalP4);

        // Array of polygon vertices.
        int lPolygonVertices[] = { 0, 3, 2, 1,
            4, 5, 6,
            7, 8, 9,
            10, 11, 12,
            13, 14, 15 };

        // Set material mapping.
        FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial();
        lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
        lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        // Create polygons. Assign material indices.

        // Pyramid base.
        lMesh->BeginPolygon(0); // Material index.

        for(j = 0; j < 4; j++)
        {
            lMesh->AddPolygon(lPolygonVertices[j]); // Control point index.
        }

        lMesh->EndPolygon ();

        // Pyramid sides.
        for(i = 1; i < 5; i++)
        {
            lMesh->BeginPolygon(i); // Material index.

            for(j = 0; j < 3; j++)
            {
                lMesh->AddPolygon(lPolygonVertices[4 + 3*(i - 1) + j]); // Control point index.
            }

            lMesh->EndPolygon ();
        }

        FbxNode* lNode = FbxNode::Create(pScene,pName);

        lNode->SetNodeAttribute(lMesh);

        CreateMaterials(pScene, lMesh);

        return lNode;
    }

    FbxNode* CreateTriangle(FbxScene* pScene, char* pName)
    {
        FbxMesh* lMesh = FbxMesh::Create(pScene, pName);

        // The three vertices
        FbxVector4 lControlPoint0(-50, 0, 50);
        FbxVector4 lControlPoint1(50, 0, 50);
        FbxVector4 lControlPoint2(0, 50, -50);

        // Create control points.
        lMesh->InitControlPoints(3);
        FbxVector4* lControlPoints = lMesh->GetControlPoints();

        lControlPoints[0] = lControlPoint0;
        lControlPoints[1] = lControlPoint1;
        lControlPoints[2] = lControlPoint2;

        // Create the triangle's polygon
        lMesh->BeginPolygon();
        lMesh->AddPolygon(0); // Control point 0
        lMesh->AddPolygon(1); // Control point 1
        lMesh->AddPolygon(2); // Control point 2
        lMesh->EndPolygon();

        FbxNode* lNode = FbxNode::Create(pScene,pName);
        lNode->SetNodeAttribute(lMesh);

        return lNode;
    }

    FbxNode* CreateCubeWithMaterialAndMyKFbxMesh(FbxScene* pScene, char* pName)
    {
        int i, j;

        //create a cube with our newly created class
        MyKFbxMesh* lMyKFbxMesh = MyKFbxMesh::Create(pScene,pName);
        FbxDouble3 lVector3(0.1, 0.2, 0.3);
        FbxDouble4 lVector4(0.1, 0.2, 0.3, 0.4);
        FbxDouble4 lVector41(1.1, 1.2, 1.3, 1.4);
        FbxDouble4 lVector42(2.1, 2.2, 2.3, 2.4);
        FbxDouble4 lVector43(3.1, 3.2, 3.3, 3.4);
        FbxDouble4x4 lMatrix(lVector4,lVector41,lVector42,lVector43);

        FbxColor lGreen(0.0, 0.0, 1.0);

        FbxTime lTime(333);
        //Set user-specific properties of our classes
        FbxString lString = "My Property 5 Value";
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY1).Set(true);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY2).Set((int) 1);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY3).Set((float)2.2);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY4).Set((double)3.3);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY5).Set(lString);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY6).Set(lVector3);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY6).Set(lGreen);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY8).Set(lVector4);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY9).Set(lMatrix);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY10).Set(3);
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY10).AddEnumValue("AAA");
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY10).AddEnumValue("BBB");
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY10).AddEnumValue("CCC");
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY10).AddEnumValue("DDD");
        lMyKFbxMesh->GetProperty((int) MyKFbxMesh::eMY_PROPERTY11).Set(lTime);

        FbxVector4 lControlPoint0(-25, 0, 25);
        FbxVector4 lControlPoint1(25, 0, 25);
        FbxVector4 lControlPoint2(25, 50, 25);
        FbxVector4 lControlPoint3(-25, 50, 25);
        FbxVector4 lControlPoint4(-25, 0, -25);
        FbxVector4 lControlPoint5(25, 0, -25);
        FbxVector4 lControlPoint6(25, 50, -25);
        FbxVector4 lControlPoint7(-25, 50, -25);

        FbxVector4 lNormalXPos(1, 0, 0);
        FbxVector4 lNormalXNeg(-1, 0, 0);
        FbxVector4 lNormalYPos(0, 1, 0);
        FbxVector4 lNormalYNeg(0, -1, 0);
        FbxVector4 lNormalZPos(0, 0, 1);
        FbxVector4 lNormalZNeg(0, 0, -1);

        // Create control points.
        lMyKFbxMesh->InitControlPoints(24);
        FbxVector4* lControlPoints = lMyKFbxMesh->GetControlPoints();

        lControlPoints[0] = lControlPoint0;
        lControlPoints[1] = lControlPoint1;
        lControlPoints[2] = lControlPoint2;
        lControlPoints[3] = lControlPoint3;
        lControlPoints[4] = lControlPoint1;
        lControlPoints[5] = lControlPoint5;
        lControlPoints[6] = lControlPoint6;
        lControlPoints[7] = lControlPoint2;
        lControlPoints[8] = lControlPoint5;
        lControlPoints[9] = lControlPoint4;
        lControlPoints[10] = lControlPoint7;
        lControlPoints[11] = lControlPoint6;
        lControlPoints[12] = lControlPoint4;
        lControlPoints[13] = lControlPoint0;
        lControlPoints[14] = lControlPoint3;
        lControlPoints[15] = lControlPoint7;
        lControlPoints[16] = lControlPoint3;
        lControlPoints[17] = lControlPoint2;
        lControlPoints[18] = lControlPoint6;
        lControlPoints[19] = lControlPoint7;
        lControlPoints[20] = lControlPoint1;
        lControlPoints[21] = lControlPoint0;
        lControlPoints[22] = lControlPoint4;
        lControlPoints[23] = lControlPoint5;

        // We want to have one normal for each vertex (or control point),
        // so we set the mapping mode to eByControlPoint.
        FbxGeometryElementNormal* lGeometryElementNormal = lMyKFbxMesh->CreateElementNormal();
        lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);

        // The second method is to the possible values of the normals
        // in the direct array, and set the index of that value
        // in the index array for every control point.
        lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        // Add the 6 different normals to the direct array
        lGeometryElementNormal->GetDirectArray().Add(lNormalZPos);
        lGeometryElementNormal->GetDirectArray().Add(lNormalXPos);
        lGeometryElementNormal->GetDirectArray().Add(lNormalZNeg);
        lGeometryElementNormal->GetDirectArray().Add(lNormalXNeg);
        lGeometryElementNormal->GetDirectArray().Add(lNormalYPos);
        lGeometryElementNormal->GetDirectArray().Add(lNormalYNeg);

        // Now for each control point, we need to specify which normal to use
        lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(0); // index of lNormalZPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(1); // index of lNormalXPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(2); // index of lNormalZNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(3); // index of lNormalXNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(4); // index of lNormalYPos in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.
        lGeometryElementNormal->GetIndexArray().Add(5); // index of lNormalYNeg in the direct array.

        // Array of polygon vertices.
        int lPolygonVertices[] = { 0, 1, 2, 3,
            4, 5, 6, 7,
            8, 9, 10, 11,
            12, 13, 14, 15,
            16, 17, 18, 19,
            20, 21, 22, 23 };

        // Set material mapping.
        FbxGeometryElementMaterial* lMaterialElement = lMyKFbxMesh->CreateElementMaterial();
        lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
        lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        // Create UV coordinates.
        FbxGeometryElementUV* lUVElement = lMyKFbxMesh->CreateElementUV( "");
        FBX_ASSERT( lUVElement != NULL);
        lUVElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
        lUVElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

        FbxVector2 lVectors0(0, 0);
        FbxVector2 lVectors1(1, 0);
        FbxVector2 lVectors2(1, 1);
        FbxVector2 lVectors3(0, 1);

        lUVElement->GetDirectArray().Add(lVectors0);
        lUVElement->GetDirectArray().Add(lVectors1);
        lUVElement->GetDirectArray().Add(lVectors2);
        lUVElement->GetDirectArray().Add(lVectors3);

        for(i = 0; i < 6; i++)
        {
            //we created 6 lambert materials in the MyKFbxMesh
            //make each face use a different one
            lMyKFbxMesh->BeginPolygon(i);

            for(j = 0; j < 4; j++)
            {
                lMyKFbxMesh->AddPolygon(lPolygonVertices[i*4 + j], // Control point index.
                    j); // Valid texture UV index since texture UV mapping is by polygon vertex.
            }

            lMyKFbxMesh->EndPolygon ();
        }

        //Add a User Data Element
        //As of now, the types supported by a User Data Element are: FbxBoolDT, FbxIntDT, FbxFloatDT and FbxDoubleDT

        //For this example, we will create a element which possess 1 float and 1 bool

        //create a template array of KFbxDataTypes
        FbxArray<FbxDataType> lArrayType;

        //Create a template array of const char*
        FbxArray<const char*> lArrayNames;

        //let's add our types and the names of each of the added types
        lArrayType.Add(FbxFloatDT);
        lArrayNames.Add("My Float");

        lArrayType.Add(FbxBoolDT);
        lArrayNames.Add("My Bool");

        //Now we are ready to create the User Data Element
        FbxGeometryElementUserData* lFbxGeometryElementUserData = FbxGeometryElementUserData::Create(lMyKFbxMesh, "My Geometry Element",PID_MY_GEOMETRY_LEMENT,lArrayType, lArrayNames);
        //And UserData create function is still in implementing

        //For this example we will set the mapping mode to POLYGON_VERTEX
        lFbxGeometryElementUserData->SetMappingMode(FbxGeometryElement::eByPolygonVertex);

        //As we are using the eDirect Reference mode, and we are using polygon vertex Mapping mode
        //we have to resize the direct array to the number of polygon vertex we have in this mesh
        lFbxGeometryElementUserData->ResizeAllDirectArrays(lMyKFbxMesh->GetPolygonVertexCount());

        //To change the values in the direct array, we simply get the array and modify what we need to
        FbxLayerElementArrayTemplate<void*>* directArrayF = lFbxGeometryElementUserData->GetDirectArrayVoid("My Float");
        float *lDirectArrayFloat = NULL;
        lDirectArrayFloat = directArrayF->GetLocked(lDirectArrayFloat);

        FbxLayerElementArrayTemplate<void*>* directArrayB = lFbxGeometryElementUserData->GetDirectArrayVoid("My Bool");
        bool *lDirectArrayBool = NULL;
        directArrayB->GetLocked(lDirectArrayBool);

        //Modify every data for each polygon vertex on our mesh with some value
        for(i=0; i<lMyKFbxMesh->GetPolygonVertexCount(); ++i)
        {
            if(lDirectArrayFloat)
                lDirectArrayFloat[i]=(float)(i+0.5);
            if(lDirectArrayBool)
                lDirectArrayBool[i]= (i%2==0);
        }

        directArrayF->Release((void**)&lDirectArrayFloat);
        directArrayB->Release((void**)&lDirectArrayBool);

        FbxNode* lNode = FbxNode::Create(pScene,pName);

        lNode->SetNodeAttribute(lMyKFbxMesh);
        lNode->SetShadingMode(FbxNode::eTextureShading);

        //let's create the materials
        //6 materials, 1 for each face of the cube
        CreateMaterialsWithMyKFbxMesh(pScene, lMyKFbxMesh);

        return lNode;
    }

    // Create texture for cube.
    void CreateTexture(FbxScene* pScene, FbxMesh* pMesh)
    {
        // A texture need to be connected to a property on the material,
        // so let's use the material (if it exists) or create a new one
        FbxSurfacePhong* lMaterial = NULL;

        //get the node of mesh, add material for it.
        FbxNode* lNode = pMesh->GetNode();
        if(lNode)
        {
            lMaterial = lNode->GetSrcObject<FbxSurfacePhong>(0);
            if (lMaterial == NULL)
            {
                FbxString lMaterialName = "toto";
                FbxString lShadingName  = "Phong";
                FbxDouble3 lBlack(0.0, 0.0, 0.0);
                FbxDouble3 lRed(1.0, 0.0, 0.0);
                FbxDouble3 lDiffuseColor(0.75, 0.75, 0.0);
                lMaterial = FbxSurfacePhong::Create(pScene, lMaterialName.Buffer());

                // Generate primary and secondary colors.
                lMaterial->Emissive           .Set(lBlack);
                lMaterial->Ambient            .Set(lRed);
                lMaterial->AmbientFactor      .Set(1.);
                // Add texture for diffuse channel
                lMaterial->Diffuse           .Set(lDiffuseColor);
                lMaterial->DiffuseFactor     .Set(1.);
                lMaterial->TransparencyFactor.Set(0.4);
                lMaterial->ShadingModel      .Set(lShadingName);
                lMaterial->Shininess         .Set(0.5);
                lMaterial->Specular          .Set(lBlack);
                lMaterial->SpecularFactor    .Set(0.3);

                lNode->AddMaterial(lMaterial);
            }
        }

        FbxFileTexture* lTexture = FbxFileTexture::Create(pScene,"Diffuse Texture");

        // Set texture properties.
        lTexture->SetFileName("scene03.jpg"); // Resource file is in current directory.
        lTexture->SetTextureUse(FbxTexture::eStandard);
        lTexture->SetMappingType(FbxTexture::eUV);
        lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
        lTexture->SetSwapUV(false);
        lTexture->SetTranslation(0.0, 0.0);
        lTexture->SetScale(1.0, 1.0);
        lTexture->SetRotation(0.0, 0.0);

        // don't forget to connect the texture to the corresponding property of the material
        if (lMaterial)
            lMaterial->Diffuse.ConnectSrcObject(lTexture);

        lTexture = FbxFileTexture::Create(pScene,"Ambient Texture");

        // Set texture properties.
        lTexture->SetFileName("gradient.jpg"); // Resource file is in current directory.
        lTexture->SetTextureUse(FbxTexture::eStandard);
        lTexture->SetMappingType(FbxTexture::eUV);
        lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
        lTexture->SetSwapUV(false);
        lTexture->SetTranslation(0.0, 0.0);
        lTexture->SetScale(1.0, 1.0);
        lTexture->SetRotation(0.0, 0.0);

        // don't forget to connect the texture to the corresponding property of the material
        if (lMaterial)
            lMaterial->Ambient.ConnectSrcObject(lTexture);

        lTexture = FbxFileTexture::Create(pScene,"Emissive Texture");

        // Set texture properties.
        lTexture->SetFileName("spotty.jpg"); // Resource file is in current directory.
        lTexture->SetTextureUse(FbxTexture::eStandard);
        lTexture->SetMappingType(FbxTexture::eUV);
        lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
        lTexture->SetSwapUV(false);
        lTexture->SetTranslation(0.0, 0.0);
        lTexture->SetScale(1.0, 1.0);
        lTexture->SetRotation(0.0, 0.0);

        // don't forget to connect the texture to the corresponding property of the material
        if (lMaterial)
            lMaterial->Emissive.ConnectSrcObject(lTexture);
    }

    // Create materials for pyramid.
    void CreateMaterials(FbxScene* pScene, FbxMesh* pMesh)
    {
        int i;

        for (i = 0; i < 5; i++ )
        {
            FbxString lMaterialName = "material";
            FbxString lShadingName = "Phong";
            lMaterialName += i;
            FbxDouble3 lBlack(0.0, 0.0, 0.0);
            FbxDouble3 lRed(1.0, 0.0, 0.0);
            FbxDouble3 lColor;
            FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, lMaterialName.Buffer());

            // Generate primary and secondary colors.
            lMaterial->Emissive.Set(lBlack);
            lMaterial->Ambient.Set(lRed);
            lColor = FbxDouble3(i > 2   ? 1.0 : 0.0,
                i > 0 && i < 4 ? 1.0 : 0.0,
                i % 2   ? 0.0 : 1.0);
            lMaterial->Diffuse.Set(lColor);
            lMaterial->TransparencyFactor.Set(0.0);
            lMaterial->ShadingModel.Set(lShadingName);
            lMaterial->Shininess.Set(0.5);

            //get the node of mesh, add material for it.
            FbxNode* lNode = pMesh->GetNode();
            if(lNode)
                lNode->AddMaterial(lMaterial);
        }
    }

    void CreateMaterialsWithMyKFbxMesh(FbxScene* pScene, MyKFbxMesh* pMyKFbxMesh)
    {
        int i;
        for (i = 0; i != 6; ++i )
        {
            FbxString lMaterialName = "material";
            FbxString lShadingModelName = i%2==0 ? "Lambert" : "Phong";
            lMaterialName += i;
            FbxDouble3 lBlack(0.0, 0.0, 0.0);
            FbxDouble3 lRed(1.0, 0.0, 0.0);
            FbxDouble3 lColor;
            FbxSurfaceLambert *lMaterial = FbxSurfaceLambert::Create(pScene, lMaterialName.Buffer());

            // Generate primary and secondary colors.

            lMaterial->Emissive.Set(lBlack);
            lMaterial->Ambient.Set(lRed);
            lColor = FbxDouble3(i > 2   ? 1.0 : 0.0,
                i > 0 && i < 4 ? 1.0 : 0.0,
                i % 2   ? 0.0 : 1.0);
            lMaterial->Diffuse.Set(lColor);
            lMaterial->TransparencyFactor.Set(0.0);
            lMaterial->ShadingModel.Set(lShadingModelName);

            //get the node of mesh, add material for it.
            FbxNode* lNode = pMyKFbxMesh->GetNode();
            if(lNode)
                lNode->AddMaterial(lMaterial);

        }
    }

    // Map pyramid control points onto an upside down shape.
    void MapShapeOnPyramid(FbxScene* pScene, FbxNode* pPyramid)
    {
        FbxShape* lShape = FbxShape::Create(pScene,"Upside Down");

        FbxVector4 lControlPoint0(-50, 100, 50);
        FbxVector4 lControlPoint1(50, 100, 50);
        FbxVector4 lControlPoint2(50, 100, -50);
        FbxVector4 lControlPoint3(-50, 100, -50);
        FbxVector4 lControlPoint4(0, 0, 0);

        FbxVector4 lNormalP0(0, 1, 0);
        FbxVector4 lNormalP1(0, -0.447, 0.894);
        FbxVector4 lNormalP2(0.894, -0.447, 0);
        FbxVector4 lNormalP3(0, -0.447, -0.894);
        FbxVector4 lNormalP4(-0.894, -0.447, 0);

        // Create control points.
        lShape->InitControlPoints(16);
        FbxVector4* lControlPoints = lShape->GetControlPoints();

        lControlPoints[0] = lControlPoint0;
        lControlPoints[1] = lControlPoint1;
        lControlPoints[2] = lControlPoint2;
        lControlPoints[3] = lControlPoint3;
        lControlPoints[4] = lControlPoint0;
        lControlPoints[5] = lControlPoint1;
        lControlPoints[6] = lControlPoint4;
        lControlPoints[7] = lControlPoint1;
        lControlPoints[8] = lControlPoint2;
        lControlPoints[9] = lControlPoint4;
        lControlPoints[10] = lControlPoint2;
        lControlPoints[11] = lControlPoint3;
        lControlPoints[12] = lControlPoint4;
        lControlPoints[13] = lControlPoint3;
        lControlPoints[14] = lControlPoint0;
        lControlPoints[15] = lControlPoint4;

        FbxGeometryElementNormal* lNormalElement = lShape->CreateElementNormal();
        lNormalElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
        lNormalElement->SetReferenceMode(FbxGeometryElement::eDirect);

        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP0);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP1);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP2);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP3);
        lNormalElement->GetDirectArray().Add(lNormalP4);
        lNormalElement->GetDirectArray().Add(lNormalP4);
        lNormalElement->GetDirectArray().Add(lNormalP4);

        FbxBlendShape* lBlendShape = FbxBlendShape::Create(pScene,"");
        FbxBlendShapeChannel* lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, "");
        pPyramid->GetMesh()->AddDeformer(lBlendShape);
        lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
        lBlendShapeChannel->AddTargetShape(lShape);
    }

    void MapVertexCacheOnTriangle(FbxScene* pScene, FbxNode* pTriangle, char* pSampleFileName)
    {
        // By convention, all cache files are created in a _fpc folder located at the same
        // place as the .fbx file.
        FbxString lFBXAbsolutePath = FbxPathUtils::Resolve(pSampleFileName);

        // Create a cache directory with the same name as the fbx file
        FbxString lFPCAbsoluteDirectory;

        lFPCAbsoluteDirectory  = FbxPathUtils::GetFolderName(lFBXAbsolutePath);
        lFPCAbsoluteDirectory += "/";
        lFPCAbsoluteDirectory += FbxPathUtils::GetFileName(pSampleFileName, false);
        lFPCAbsoluteDirectory += "_fpc";

        // Make this path the shortest possible
        lFPCAbsoluteDirectory = FbxPathUtils::Clean(lFPCAbsoluteDirectory);

        // Now get the point cache absolute and relative file name
        FbxString lAbsolutePCFileName = lFPCAbsoluteDirectory + FbxString("/") + pTriangle->GetName();
        lAbsolutePCFileName += gExportVertexCacheMCFormat ? ".xml" : ".pc2";

        FbxString lRelativePCFileName = FbxPathUtils::GetRelativeFilePath(FbxPathUtils::GetFolderName(lFBXAbsolutePath)+"/", lAbsolutePCFileName);

        // Make sure the direcotry exist.
        if (!FbxFolder::EnsureExistance(lAbsolutePCFileName))
        {
            // Cannot create this directory. So do not create the point cache
            return;
        }

        //
        // Create the cache file
        //
        FbxCache* lCache = FbxCache::Create(pScene, pTriangle->GetName());

        lCache->SetCacheFileName(lRelativePCFileName, lAbsolutePCFileName);
        lCache->SetCacheFileFormat(gExportVertexCacheMCFormat ? FbxCache::eMayaCache : FbxCache::eMaxPointCacheV2);

        //
        // Create the vertex deformer
        //
        FbxVertexCacheDeformer* lDeformer = FbxVertexCacheDeformer::Create(pScene, pTriangle->GetName());

        lDeformer->SetCache(lCache);
        lDeformer->SetCacheChannel(pTriangle->GetName());
        lDeformer->SetActive(true);

        // Apply the deformer on the mesh
        pTriangle->GetGeometry()->AddDeformer(lDeformer);
    }

    // Cube is translated to the left.
    void SetCubeDefaultPosition(FbxNode* pCube)
    {
        pCube->LclTranslation.Set(FbxVector4(-75.0, -50.0, 0.0));
        pCube->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0));
        pCube->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0));
    }

    // Pyramid is translated to the right.
    void SetPyramidDefaultPosition(FbxNode* pPyramid)
    {
        pPyramid->LclTranslation.Set(FbxVector4(75.0, -50.0, 0.0));
        pPyramid->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0));
        pPyramid->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0));
    }

    void SetTriangleDefaultPosition(FbxNode* pTriangle)
    {
        pTriangle->LclTranslation.Set(FbxVector4(200.0, -50.0, 0.0));
        pTriangle->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0));
        pTriangle->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0));
    }

    void SetMyKFbxMeshCubeDefaultPosition(FbxNode* pMyKFbxCube)
    {
        pMyKFbxCube->LclTranslation.Set(FbxVector4(-200.0, -25.0, 0.0));
        pMyKFbxCube->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0));
        pMyKFbxCube->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0));
    }

    // Displays 6 different angles.
    void Animate(FbxNode* pNode, FbxAnimLayer* pAnimLayer)
    {
        FbxAnimCurve* lCurve = NULL;
        FbxTime lTime;
        int lKeyIndex = 0;

        lCurve = pNode->LclRotation.GetCurve<FbxAnimCurve>(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
        if (lCurve)
        {
            lCurve->KeyModifyBegin();

            lTime.SetSecondDouble(0.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 0.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(0.5);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 90.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(1.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 180.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(1.5);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 270.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(2.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 360.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lCurve->KeyModifyEnd();
        }

        lCurve = pNode->LclRotation.GetCurve<FbxAnimCurve>(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
        if (lCurve)
        {
            lCurve->KeyModifyBegin();

            lTime.SetSecondDouble(2.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 0.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(2.5);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 90.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(3.5);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, -90.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(4.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 0.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lCurve->KeyModifyEnd();
        }

        // The upside down shape is at index 0 because it is the only one.
        // The cube has no shape so the function returns NULL is this case.
        FbxGeometry* lGeometry = (FbxGeometry*) pNode->GetNodeAttribute();
        lCurve = lGeometry->GetShapeChannel(0, 0, pAnimLayer, true);
        if (lCurve)
        {
            lCurve->KeyModifyBegin();

            lTime.SetSecondDouble(0.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 0.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(2.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 100.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lTime.SetSecondDouble(4.0);
            lKeyIndex = lCurve->KeyAdd(lTime);
            lCurve->KeySetValue(lKeyIndex, 0.0);
            lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);

            lCurve->KeyModifyEnd();
        }
    }

    void AnimateVertexCacheOnTriangleDoubleVertex(FbxNode* pTriangle, double pFrameRate)
    {
        //
        // Move the vertices from their original position to the center.
        //
        FbxVertexCacheDeformer* lDeformer = static_cast<FbxVertexCacheDeformer*>(pTriangle->GetGeometry()->GetDeformer(0, FbxDeformer::eVertexCache));
        FbxCache*               lCache = lDeformer->GetCache();
        bool                     lRet;

        // Write samples for 4 seconds
        FbxTime lTimeIncrement, lCurrentTime, lStopTime;
        lTimeIncrement.SetTime(0, 0, 0, 1); // 1 frame @ current frame rate
        lStopTime.SetTime(0, 0, 4);         // 4 seconds

        unsigned int lFrameCount = (unsigned int)(lStopTime.Get()/lTimeIncrement.Get());

        // Open the file for writing
        if (gExportVertexCacheMCFormat)
        {
            lRet = lCache->OpenFileForWrite(FbxCache::eMCOneFile, pFrameRate, pTriangle->GetName());
        }
        else
        {
            lRet = lCache->OpenFileForWrite(0.0, pFrameRate, lFrameCount, 3);
        }

        if (!lRet)
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
            return;
        }

        int lChannelIndex = lCache->GetChannelIndex(pTriangle->GetName());
        unsigned int lCurrentFrame = 0;

        while (lCurrentTime <= lStopTime)
        {
            double lVertices[3][3];
            double lScaleFactor = 1.0-double(lCurrentTime.GetSecondDouble()/lStopTime.GetSecondDouble());

            lVertices[0][0] = -50.0 * lScaleFactor;  // X
            lVertices[0][1] = 0.0;                   // Y
            lVertices[0][2] = 50.0  * lScaleFactor;  // Z

            lVertices[1][0] = 50.0  * lScaleFactor;  // X
            lVertices[1][1] = 0.0;                   // Y
            lVertices[1][2] = 50.0  * lScaleFactor;  // Z

            lVertices[2][0] = 0.0   * lScaleFactor;  // X
            lVertices[2][1] = 50.0  * lScaleFactor;  // Y
            lVertices[2][2] = -50.0 * lScaleFactor;  // Z

            if (gExportVertexCacheMCFormat)
            {
                lCache->Write(lChannelIndex, lCurrentTime, &lVertices[0][0], 3);
            }
            else
            {
                lCache->Write(lCurrentFrame, &lVertices[0][0]);
            }

            lCurrentTime += lTimeIncrement;
            lCurrentFrame++;
        }

        if (!lCache->CloseFile())
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
        }
    }

    void AnimateVertexCacheOnTriangleInt32(FbxNode* pTriangle, double pFrameRate)
    {
        //
        // Move the vertices from their original position to the center.
        //
        FbxVertexCacheDeformer* lDeformer = static_cast<FbxVertexCacheDeformer*>(pTriangle->GetGeometry()->GetDeformer(0, FbxDeformer::eVertexCache));
        FbxCache*               lCache = lDeformer->GetCache();
        bool                     lRet = false;

        // Write samples for 4 seconds
        FbxTime lTimeIncrement, lCurrentTime, lStopTime;
        lTimeIncrement.SetTime(0, 0, 0, 1); // 1 frame @ current frame rate
        lStopTime.SetTime(0, 0, 4);         // 4 seconds

        // Open the file for writing int32 array
        if (gExportVertexCacheMCFormat)
        {
            lRet = lCache->OpenFileForWrite(FbxCache::eMCOneFile, pFrameRate, pTriangle->GetName(), FbxCache::eInt32Array);
        }

        if (!lRet)
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
            return;
        }

        int lChannelIndex = lCache->GetChannelIndex(pTriangle->GetName());
        int lCurrentFrame = 0;

        while (lCurrentTime <= lStopTime)
        {
            int v[2];

            v[0] = -10 + lCurrentFrame;
            v[1] = v[0]+1;

            if (gExportVertexCacheMCFormat)
            {
                lCache->Write(lChannelIndex, lCurrentTime, &v[0], 2);
            }

            lCurrentTime += lTimeIncrement;
            lCurrentFrame++;
        }

        if (!lCache->CloseFile())
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
        }

        // Open the file for reading int32 array
        if (gExportVertexCacheMCFormat)
        {
            lRet = lCache->OpenFileForRead();
        }

        if (!lRet)
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
            return;
        }

        FbxTime lCurrentTime2;
        lCurrentFrame = 0;

        FBXSDK_printf("Testing awCache int32 array read and write\n");
        bool passTest = true;
        // FBXSDK_printf("Should print out -10 .. 110\n");
        while (lCurrentTime2 <= lStopTime)
        {
            int v[2];
            if (gExportVertexCacheMCFormat)
            {
                lCache->Read(lChannelIndex, lCurrentTime2, &v[0], 2);
                if ((v[0] != -10 + lCurrentFrame) || (v[0]+1 != v[1]) )
                {
                    FBXSDK_printf("awCache int32 array read/write mismatch\n");
                    passTest = false;
                    break;
                }
                // FBXSDK_printf("%d ",v[0]);
            }

            lCurrentTime2 += lTimeIncrement;
            lCurrentFrame++;
        }

        if (!lCache->CloseFile())
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
        }

        if (passTest)
        {
        ;
        FBXSDK_printf("awCache int32 array read and write test passed\n");
        }
    }

    void AnimateVertexCacheOnTriangleFloat(FbxNode* pTriangle, double pFrameRate)
    {
        //
        // Move the vertices from their original position to the center.
        //
        FbxVertexCacheDeformer* lDeformer = static_cast<FbxVertexCacheDeformer*>(pTriangle->GetGeometry()->GetDeformer(0, FbxDeformer::eVertexCache));
        FbxCache*               lCache = lDeformer->GetCache();
        bool                     lRet;

        // Write samples for 4 seconds
        FbxTime lTimeIncrement, lCurrentTime, lStopTime;
        lTimeIncrement.SetTime(0, 0, 0, 1); // 1 frame @ current frame rate
        lStopTime.SetTime(0, 0, 4);         // 4 seconds

        // Open the file for writing
        if (gExportVertexCacheMCFormat)
        {
            lRet = lCache->OpenFileForWrite(FbxCache::eMCOneFile, pFrameRate, pTriangle->GetName(), FbxCache::eFloatVectorArray);
        }
        else
        {
            lRet = false;
        }

        if (!lRet)
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
            return;
        }

        int lChannelIndex = lCache->GetChannelIndex(pTriangle->GetName());
        unsigned int lCurrentFrame = 0;

        while (lCurrentTime <= lStopTime)
        {
            float lVertices[3][3];
            float lScaleFactor = 1.0f-float(lCurrentTime.GetSecondDouble()/lStopTime.GetSecondDouble());

            lVertices[0][0] = -50.0f * lScaleFactor;  // X
            lVertices[0][1] = 0.0f;                   // Y
            lVertices[0][2] = 50.0f  * lScaleFactor;  // Z

            lVertices[1][0] = 50.0f  * lScaleFactor;  // X
            lVertices[1][1] = 0.0f;                   // Y
            lVertices[1][2] = 50.0f  * lScaleFactor;  // Z

            lVertices[2][0] = 0.0f   * lScaleFactor;  // X
            lVertices[2][1] = 50.0f  * lScaleFactor;  // Y
            lVertices[2][2] = -50.0f * lScaleFactor;  // Z

            if (gExportVertexCacheMCFormat)
            {
                lCache->Write(lChannelIndex, lCurrentTime, &lVertices[0][0], 3);
            }

            lCurrentTime += lTimeIncrement;
            lCurrentFrame++;
        }

        if (!lCache->CloseFile())
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
        }

        // Open the file for reading int32 array
        if (gExportVertexCacheMCFormat)
        {
            lRet = lCache->OpenFileForRead();
        }

        if (!lRet)
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
            return;
        }

        FbxTime lCurrentTime2;
        lCurrentFrame = 0;
        #define AbsFlt(a)      (((a) < 0) ? -(a) : (a))
        #define CmpFlt(a,b)    (AbsFlt((a)-(b)) > 1e-5)

        FBXSDK_printf("Testing awCache Float3 array read and write\n");
        bool passTest = true;
        while (lCurrentTime2 <= lStopTime)
        {
            float lVertices[3][3];
            float lScaleFactor = 1.0f-float(lCurrentTime2.GetSecondDouble()/lStopTime.GetSecondDouble());

            if (gExportVertexCacheMCFormat)
            {
                lCache->Read(lChannelIndex, lCurrentTime2, &lVertices[0][0], 3);

                if ((CmpFlt(lVertices[0][0], -50.0f * lScaleFactor) || CmpFlt(lVertices[0][1], 0.0f                ) || CmpFlt(lVertices[0][2], 50.0f * lScaleFactor)) ||
                    (CmpFlt(lVertices[1][0],  50.0f * lScaleFactor) || CmpFlt(lVertices[1][1], 0.0f                ) || CmpFlt(lVertices[1][2], 50.0f * lScaleFactor)) ||
                    (CmpFlt(lVertices[2][0],   0.0f * lScaleFactor) || CmpFlt(lVertices[2][1], 50.0f * lScaleFactor) || CmpFlt(lVertices[2][2],-50.0f * lScaleFactor)))
                {
                    FBXSDK_printf("awCache Float3 array read/write mismatch\n");
                    passTest = false;
                    break;
                }
            }

            lCurrentTime2 += lTimeIncrement;
            lCurrentFrame++;
        }

        #undef AbsFlt
        #undef CmpFlt

        if (!lCache->CloseFile())
        {
            // print out the error
            FBXSDK_printf("File open error: %s\n", lCache->GetError().GetLastErrorString());
        }

        if (passTest)
        {
            FBXSDK_printf("awCache float3 array read and write test passed\n");
        }

    }