#include "DrawScene.h"
#include "SceneCache.h"
#include "GetPosition.h"
              ShadingMode pShadingMode);
void ComputeShapeDeformation(
FbxMesh* pMesh, 
 
void ComputeClusterDeformation(
FbxAMatrix& pGlobalPosition, 
 
void ComputeLinearDeformation(
FbxAMatrix& pGlobalPosition, 
 
void ComputeDualQuaternionDeformation(
FbxAMatrix& pGlobalPosition, 
 
void ComputeSkinDeformation(
FbxAMatrix& pGlobalPosition, 
 
void ReadVertexCacheData(
FbxMesh* pMesh, 
 
void MatrixScale(
FbxAMatrix& pMatrix, 
double pValue);
 
void MatrixAddToDiagonal(
FbxAMatrix& pMatrix, 
double pValue);
 
{
    
    
    
    for (int lLightIndex = 0; lLightIndex < lLightCount; ++lLightIndex)
    {
        if (lNode)
{
            FbxAMatrix lGlobalPosition = GetGlobalPosition(lNode, pTime, pPose);
 
            FbxAMatrix lGlobalOffPosition = lGlobalPosition * lGeometryOffset;
 
            DrawLight(lNode, pTime, lGlobalOffPosition);
    }
    }
}
                       ShadingMode pShadingMode)
{
    FbxAMatrix lGlobalPosition = GetGlobalPosition(pNode, pTime, pPose, &pParentGlobalPosition);
 
    {
    
    
    FbxAMatrix lGlobalOffPosition = lGlobalPosition * lGeometryOffset;
 
        DrawNode(pNode, pTime, pAnimLayer, pParentGlobalPosition, lGlobalOffPosition, pPose, pShadingMode);
    }
    for (int lChildIndex = 0; lChildIndex < lChildCount; ++lChildIndex)
    {
        DrawNodeRecursive(pNode->
GetChild(lChildIndex), pTime, pAnimLayer, lGlobalPosition, pPose, pShadingMode);
 
    }
}
              FbxPose* pPose, ShadingMode pShadingMode)
 
{
    if (lNodeAttribute)
    {
        
        {
            DrawMarker(pGlobalPosition);
        }
        {
            DrawSkeleton(pNode, pParentGlobalPosition, pGlobalPosition);
        }
        
        {
            DrawMesh(pNode, pTime, pAnimLayer, pGlobalPosition, pPose, pShadingMode);
        }
        {
            DrawCamera(pNode, pTime, pAnimLayer, pGlobalPosition);
        }
        {
            DrawNull(pGlobalPosition);
        }
    }
    else
    {
        
        DrawNull(pGlobalPosition);
    }
}
{
    GlDrawMarker(pGlobalPosition);  
}
{
    
    
    {
        GlDrawLimbNode(pParentGlobalPosition, pGlobalPosition); 
    }
}
{
    
    if (lVertexCount == 0)
    {
        return;
    }
    const VBOMesh * lMeshCache = 
static_cast<const VBOMesh *
>(lMesh->
GetUserDataPtr());
 
    
    const bool lHasDeformation = lHasVertexCache || lHasShape || lHasSkin;
    if (!lMeshCache || lHasDeformation)
    {
    }
    if (lHasDeformation)
    {
        
        if (lHasVertexCache)
        {
            ReadVertexCacheData(lMesh, pTime, lVertexArray);
        }
        else
        {
            if (lHasShape)
            {
                
                ComputeShapeDeformation(lMesh, pTime, pAnimLayer, lVertexArray);
            }
            
            int lClusterCount = 0;
            for (int lSkinIndex = 0; lSkinIndex < lSkinCount; ++lSkinIndex)
            {
            }
            if (lClusterCount)
            {
                
                ComputeSkinDeformation(pGlobalPosition, lMesh, pTime, lVertexArray, pPose);
            }
        }
        if (lMeshCache)
            lMeshCache->UpdateVertexPosition(lMesh, lVertexArray);
    }
    glPushMatrix();
    glMultMatrixd((const double*)pGlobalPosition);
    if (lMeshCache)
    {
        lMeshCache->BeginDraw(pShadingMode);
        const int lSubMeshCount = lMeshCache->GetSubMeshCount();
        for (int lIndex = 0; lIndex < lSubMeshCount; ++lIndex)
        {
            if (pShadingMode == SHADING_MODE_SHADED)
            {
                if (lMaterial)
                {
                    const MaterialCache * lMaterialCache = 
static_cast<const MaterialCache *
>(lMaterial->
GetUserDataPtr());
 
                    if (lMaterialCache)
                    {
                        lMaterialCache->SetCurrentMaterial();
                    }
                }
                else
                {
                    
                    MaterialCache::SetDefaultMaterial();
                }
            }
            lMeshCache->Draw(lIndex, pShadingMode);
        }
        lMeshCache->EndDraw();
    }
    else
    {
        
        glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
        for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; lPolygonIndex++)
        {
            glBegin(GL_LINE_LOOP);
            for (int lVerticeIndex = 0; lVerticeIndex < lVerticeCount; lVerticeIndex++)
            {
                glVertex3dv((GLdouble *)lVertexArray[lMesh->
GetPolygonVertex(lPolygonIndex, lVerticeIndex)]);
 
            }
            glEnd();
        }
    }
    glPopMatrix();
    delete [] lVertexArray;
}
{
    memcpy(lDstVertexArray, pVertexArray, lVertexCount * 
sizeof(
FbxVector4));
 
    for(int lBlendShapeIndex = 0; lBlendShapeIndex<lBlendShapeDeformerCount; ++lBlendShapeIndex)
    {
        for(int lChannelIndex = 0; lChannelIndex<lBlendShapeChannelCount; ++lChannelIndex)
        {
            if(lChannel)
            {
                
                if (!lFCurve) continue;
                double lWeight = lFCurve->
Evaluate(pTime);
 
                
                
                
                
                int lStartIndex = -1;
                int lEndIndex = -1;
                for(int lShapeIndex = 0; lShapeIndex<lShapeCount; ++lShapeIndex)
                {
                    if(lWeight > 0 && lWeight <= lFullWeights[0])
                    {
                        lEndIndex = 0;
                        break;
                    }
                    if(lWeight > lFullWeights[lShapeIndex] && lWeight < lFullWeights[lShapeIndex+1])
                    {
                        lStartIndex = lShapeIndex;
                        lEndIndex = lShapeIndex + 1;
                        break;
                    }
                }
                if(lStartIndex > -1)
                {
                }
                if(lEndIndex > -1)
                {
                }
                
                if(lStartIndex == -1 && lEndShape) 
                {
                    double lEndWeight = lFullWeights[0];
                    
                    lWeight = (lWeight/lEndWeight) * 100;
                    
                    memcpy(lDstVertexArray, lSrcVertexArray, lVertexCount * 
sizeof(
FbxVector4));
 
                    for (int j = 0; j < lVertexCount; j++)
                    {
                        
                        lDstVertexArray[j] += lInfluence;
                    }   
                }
                
                else if(lStartShape && lEndShape)
                {
                    double lStartWeight = lFullWeights[lStartIndex];
                    double lEndWeight = lFullWeights[lEndIndex];
                    
                    lWeight = ((lWeight-lStartWeight)/(lEndWeight-lStartWeight)) * 100;
                    
                    for (int j = 0; j < lVertexCount; j++)
                    {
                        
                        lDstVertexArray[j] += lInfluence;
                    }   
                }
            }
        }
    }
    memcpy(pVertexArray, lDstVertexArray, lVertexCount * 
sizeof(
FbxVector4));
 
    delete [] lDstVertexArray;
}
void ComputeClusterDeformation(
FbxAMatrix& pGlobalPosition, 
 
{
    FbxAMatrix lClusterRelativeCurrentPositionInverse;
 
    
    {
        
        lAssociateGlobalInitPosition *= lAssociateGeometry;
        lAssociateGlobalCurrentPosition = GetGlobalPosition(pCluster->
GetAssociateModel(), pTime, pPose);
 
        
        lReferenceGeometry = GetGeometry(pMesh->
GetNode());
 
        lReferenceGlobalInitPosition *= lReferenceGeometry;
        lReferenceGlobalCurrentPosition = pGlobalPosition;
        
        
        lClusterGeometry = GetGeometry(pCluster->
GetLink());
 
        lClusterGlobalInitPosition *= lClusterGeometry;
        lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->
GetLink(), pTime, pPose);
 
        
        
        pVertexTransformMatrix = lReferenceGlobalInitPosition.
Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.
Inverse() *
 
            lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.
Inverse() * lReferenceGlobalInitPosition;
 
    }
    else
    {
        lReferenceGlobalCurrentPosition = pGlobalPosition;
        
        lReferenceGeometry = GetGeometry(pMesh->
GetNode());
 
        lReferenceGlobalInitPosition *= lReferenceGeometry;
        
        lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->
GetLink(), pTime, pPose);
 
        
        lClusterRelativeInitPosition = lClusterGlobalInitPosition.
Inverse() * lReferenceGlobalInitPosition;
 
        
        lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.
Inverse() * lClusterGlobalCurrentPosition;
 
        
        pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition;
    }
}
void ComputeLinearDeformation(
FbxAMatrix& pGlobalPosition, 
 
{
    
    memset(lClusterDeformation, 0, lVertexCount * 
sizeof(
FbxAMatrix));
 
    double* lClusterWeight = new double[lVertexCount];
    memset(lClusterWeight, 0, lVertexCount * sizeof(double));
    {
        for (int i = 0; i < lVertexCount; ++i)
        {
        }
    }
    
    
    for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)
    {
        
        for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)
        {
                continue;
            ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose);
            for (int k = 0; k < lVertexIndexCount; ++k) 
            {            
                
                
                if (lIndex >= lVertexCount)
                    continue;
                if (lWeight == 0.0)
                {
                    continue;
                }
                
                MatrixScale(lInfluence, lWeight);
                {    
                    
                    MatrixAddToDiagonal(lInfluence, 1.0 - lWeight);
                    lClusterDeformation[lIndex] = lInfluence * lClusterDeformation[lIndex];
                    
                    lClusterWeight[lIndex] = 1.0;
                }
                else 
                {
                    
                    MatrixAdd(lClusterDeformation[lIndex], lInfluence);
                    
                    lClusterWeight[lIndex] += lWeight;
                }
            }
        }
    }
    
    for (int i = 0; i < lVertexCount; i++) 
    {
        double lWeight = lClusterWeight[i];
        
        if (lWeight != 0.0) 
        {
            lDstVertex = lClusterDeformation[i].
MultT(lSrcVertex);
 
            {
                
                lDstVertex /= lWeight;
            }
            {
                
                lSrcVertex *= (1.0 - lWeight);
                lDstVertex += lSrcVertex;
            }
        } 
    }
    delete [] lClusterDeformation;
    delete [] lClusterWeight;
}
void ComputeDualQuaternionDeformation(
FbxAMatrix& pGlobalPosition, 
 
{
    
    double* lClusterWeight = new double[lVertexCount];
    memset(lClusterWeight, 0, lVertexCount * sizeof(double));
    
    
    for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)
    {
        for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)
        {
                continue;
            ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose);
            for (int k = 0; k < lVertexIndexCount; ++k) 
            { 
                
                
                if (lIndex >= lVertexCount)
                    continue;
                if (lWeight == 0.0)
                    continue;
                
                {    
                    
                    lDQClusterDeformation[lIndex] = lInfluence;
                    
                    lClusterWeight[lIndex] = 1.0;
                }
                else 
                {
                    if(lClusterIndex == 0)
                    {
                        lDQClusterDeformation[lIndex] = lInfluence;
                    }
                    else
                    {
                        
                        
                        
                        if( lSign >= 0.0 )
                        {
                            lDQClusterDeformation[lIndex] += lInfluence;
                        }
                        else
                        {
                            lDQClusterDeformation[lIndex] -= lInfluence;
                        }
                    }
                    
                    lClusterWeight[lIndex] += lWeight;
                }
            }
        }
    }
    
    for (int i = 0; i < lVertexCount; i++) 
    {
        double lWeightSum = lClusterWeight[i];
        
        if (lWeightSum != 0.0) 
        {
            lDstVertex = lDQClusterDeformation[i].
Deform(lDstVertex);
 
            {
                
                lDstVertex /= lWeightSum;
            }
            {
                
                lSrcVertex *= (1.0 - lWeightSum);
                lDstVertex += lSrcVertex;
            }
        } 
    }
    delete [] lDQClusterDeformation;
    delete [] lClusterWeight;
}
void ComputeSkinDeformation(
FbxAMatrix& pGlobalPosition, 
 
{
    {
        ComputeLinearDeformation(pGlobalPosition, pMesh, pTime, pVertexArray, pPose);
    }
    {
        ComputeDualQuaternionDeformation(pGlobalPosition, pMesh, pTime, pVertexArray, pPose);
    }
    {
        ComputeLinearDeformation(pGlobalPosition, pMesh, pTime, lVertexArrayLinear, pPose);
        ComputeDualQuaternionDeformation(pGlobalPosition, pMesh, pTime, lVertexArrayDQ, pPose);
        
        
        
        
        for(int lBWIndex = 0; lBWIndex<lBlendWeightsCount; ++lBWIndex)
        {
            pVertexArray[lBWIndex] = lVertexArrayDQ[lBWIndex] * lBlendWeight + lVertexArrayLinear[lBWIndex] * (1 - lBlendWeight);
        }
    }
}
void ReadVertexCacheData(
FbxMesh* pMesh, 
 
{
    bool                    lReadSucceed  = false;
    unsigned int            BufferSize    = 0;
        
        return; 
    unsigned int Length = 0;
    if (Length != lVertexCount*3)
        
        return;
    lReadSucceed = lCache->
Read(&lReadBuf, BufferSize, pTime, lChannelIndex);
 
    if (lReadSucceed)
    {
        unsigned int lReadBufIndex = 0;
        while (lReadBufIndex < 3*lVertexCount)
        {
            
            
            
            pVertexArray[lReadBufIndex/3].
mData[0] = lReadBuf[lReadBufIndex]; lReadBufIndex++;
 
            pVertexArray[lReadBufIndex/3].
mData[1] = lReadBuf[lReadBufIndex]; lReadBufIndex++;
 
            pVertexArray[lReadBufIndex/3].
mData[2] = lReadBuf[lReadBufIndex]; lReadBufIndex++;
 
        }
    }
}
{
    FbxVector4 lCameraPosition, lCameraDefaultDirection, lCameraInterestPosition;
 
    lCameraPosition = pGlobalPosition.
GetT();
 
    
    lCameraDefaultDirection = lCameraPosition + lXPositiveAxis;
    lCameraGlobalPosition = pGlobalPosition;
    
    {
        lCameraInterestPosition = GetGlobalPosition(pNode->
GetTarget(), pTime).GetT();
 
        
            lCameraDefaultDirection, 
            lCameraInterestPosition, 
            lCameraDirection);
        
        
        lCameraGlobalPosition.
SetR(lCameraDirection);
 
    }
    
    double lRoll = 0;
    if (cam)
    {
    }
    GlDrawCamera(lCameraGlobalPosition, lRoll);
}
{
    if (!lLight)
        return;
    
    
    lLightRotation.
SetR(lYNegativeAxis);
 
    const FbxAMatrix lLightGlobalPosition = pGlobalPosition * lLightRotation;
 
    glPushMatrix();
    glMultMatrixd((const double*)lLightGlobalPosition);
    const LightCache * lLightCache = 
static_cast<const LightCache *
>(lLight->
GetUserDataPtr());
 
    if (lLightCache)
    {
        lLightCache->SetLight(pTime);
    }
    glPopMatrix();
}
{
    GlDrawCrossHair(pGlobalPosition);
}
void MatrixScale(
FbxAMatrix& pMatrix, 
double pValue)
 
{
    int i,j;
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            pMatrix[i][j] *= pValue;
        }
    }
}
void MatrixAddToDiagonal(
FbxAMatrix& pMatrix, 
double pValue)
 
{
    pMatrix[0][0] += pValue;
    pMatrix[1][1] += pValue;
    pMatrix[2][2] += pValue;
    pMatrix[3][3] += pValue;
}
{
    int i,j;
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            pDstMatrix[i][j] += pSrcMatrix[i][j];
        }
    }
}