Example #1
0
void  Triangulator::ReverseLoop(List<PolyLine> &Loop)
{
    List<PolyLine> NewLoop;
    NewLoop.SetSize(Loop.Num());

    for(int i=Loop.Num()-1, j=0; i>=0; i--, j++)
    {
        NewLoop[i].v1 = Loop[j].v2;
        NewLoop[i].v2 = Loop[j].v1;
        NewLoop[i].lineData = Loop[j].lineData;
    }

    Loop.CopyList(NewLoop);
}
Example #2
0
void  Triangulator::SetNewLoopStartPosition(List<PolyLine> &Loop, DWORD pos)
{
    List<PolyLine> NewLoop;
    NewLoop.SetSize(Loop.Num());

    for(DWORD i=0; i<Loop.Num(); i++)
    {
        DWORD newPos = i+pos;

        if(newPos >= Loop.Num())
            newPos -= Loop.Num();

        NewLoop[i] = Loop[newPos];
    }

    Loop.CopyList(NewLoop);
}
Example #3
0
void SkinMesh::LoadAnimations(CTSTR lpName)
{
    traceIn(SkinMesh::LoadAnimations);

    assert(lpName);

    DWORD i, j, k;

    String strMeshPath;
    if(!Engine::ConvertResourceName(lpName, TEXT("models"), strMeshPath))
        return;

    String strFilePath;
    strFilePath << GetPathWithoutExtension(strMeshPath) << TEXT(".xan");


    //-----------------------------------------------

    XFileInputSerializer animData;

    if(!animData.Open(strFilePath))
    {
        AppWarning(TEXT("Could not open animation file \"%s\""), (TSTR)strFilePath);
        return;
    }

    DWORD ver;
    animData << ver;

    if(ver != ANIMFILE_VER && ver != 0x100)
    {
        AppWarning(TEXT("'%s': Bad animation file version"), strFilePath);
        animData.Close();
        return;
    }

    //-----------------------------------------------

    unsigned int numSequences;
    animData << numSequences;
    SequenceList.SetSize(numSequences);
    for(i=0; i<numSequences; i++)
        animData << SequenceList[i];

    DWORD nBones;
    animData << nBones;
    BoneList.SetSize(nBones);
    for(i=0; i<nBones; i++)
    {
        Bone &bone = BoneList[i];

        List<DWORD>     RigidVerts;
        List<VWeight>   BlendedVerts;
        DWORD           nRigid, nBlended;

        //----------------------------

        animData << bone.Pos
                 << bone.Rot
                 << nRigid
                 << nBlended
                 << bone.flags
                 << bone.idParent;

        animData << RigidVerts;
        animData << BlendedVerts;

        if(bone.idParent != 0xFFFFFFFF)
        {
            bone.Parent = BoneList+bone.idParent;
            bone.LocalPos = bone.Pos - BoneList[bone.idParent].Pos;
            BoneList[bone.idParent].Children << &bone;
        }
        else
        {
            bone.Parent = NULL;
            bone.LocalPos = bone.Pos;

            bone.flags |= BONE_ROOT;
        }

        //----------------------------

        bone.Weights.SetSize(nRigid);

        for(j=0; j<RigidVerts.Num(); j++)
        {
            VWeight &weight = bone.Weights[j];

            weight.vert = RigidVerts[j];
            weight.weight = 1.0f;
        }

        bone.Weights.AppendList(BlendedVerts);

        //----------------------------

        DWORD nAnim;
        animData << nAnim;
        bone.seqKeys.SetSize(nAnim);
        for(j=0; j<nAnim; j++)
        {
            SeqKeys &keys = bone.seqKeys[j];

            DWORD nPosKeys, nRotKeys;

            //----------------------------
            
            animData << nRotKeys;
            keys.hasRotKeys = nRotKeys > 0;
            if(keys.hasRotKeys)
            {
                keys.lpRotKeys = (Quat*)Allocate(nRotKeys*sizeof(Quat));
                animData.Serialize(keys.lpRotKeys, nRotKeys*sizeof(Quat));

                keys.lpRotTans = (Quat*)Allocate(nRotKeys*sizeof(Quat));
                for(k=0; k<nRotKeys; k++)
                {
                    DWORD kp1 = (k == (nRotKeys-1)) ? k : (k+1);
                    DWORD km1 = (k == 0) ? 0 : k-1;

                    Quat &qk   = keys.lpRotKeys[k];
                    Quat &qkp1 = keys.lpRotKeys[kp1];
                    Quat &qkm1 = keys.lpRotKeys[km1];

                    keys.lpRotTans[k] = qk.GetInterpolationTangent(qkm1, qkp1);
                }
            }

            //----------------------------
            
            animData << nPosKeys;
            keys.hasPosKeys = nPosKeys > 0;
            if(keys.hasPosKeys)
            {
                keys.lpPosKeys = (Vect*)Allocate(nPosKeys*sizeof(Vect));
                Vect::SerializeArray(animData, keys.lpPosKeys, nPosKeys);
                
                keys.lpPosTans = (Vect*)Allocate(nPosKeys*sizeof(Vect));
                for(k=0; k<nPosKeys; k++)
                {
                    DWORD kp1 = (k == (nPosKeys-1)) ? k : (k+1);
                    DWORD km1 = (k == 0) ? 0 : k-1;

                    Vect &pk   = keys.lpPosKeys[k];
                    Vect &pkp1 = keys.lpPosKeys[kp1];
                    Vect &pkm1 = keys.lpPosKeys[km1];

                    keys.lpPosTans[k] = pk.GetInterpolationTangent(pkm1, pkp1);
                }
            }
        }
    }

    //-----------------------------------------------

    int num;
    animData << num;
    BoneExtensions.SetSize(num);
    BoneExtensionNames.SetSize(num);

    for(int i=0; i<num; i++)
    {
        animData << BoneExtensionNames[i];
        animData << BoneExtensions[i];
    }

    //-----------------------------------------------

    AnimatedSections.SetSize(nSections);

    if(ver == 0x100) //remove
    {
        UINT *indices = (UINT*)IdxBuffer->GetData();

        List<UINT> adjustedIndices;
        adjustedIndices.CopyArray(indices, IdxBuffer->NumIndices());

        VBData *vbd = VertBuffer->GetData();
        List<Vect> &verts = vbd->VertList;

        //--------- 
        // get vert data
        List<VertAnimInfo> vertInfo;
        vertInfo.SetSize(nVerts);

        for(int i=0; i<nBones; i++)
        {
            Bone &bone = BoneList[i];
            for(int j=0; j<bone.Weights.Num(); j++)
            {
                VWeight &vertWeight = bone.Weights[j];

                if(!vertInfo[vertWeight.vert].bones.HasValue(i))
                {
                    vertInfo[vertWeight.vert].bones << i;
                    vertInfo[vertWeight.vert].weights << vertWeight.weight;
                }
            }
        }

        //--------- 
        // remove excess bone influence from verts (let just set the max to 3 for this)
        /*for(int i=0; i<vertInfo.Num(); i++)
        {
            VertAnimInfo &vert = vertInfo[i];

            while(vert.bones.Num() > 3)
            {
                float weakestWeight = M_INFINITE;
                UINT weakestID;

                for(int j=0; j<vert.bones.Num(); j++)
                {
                    if(vert.weights[j] < weakestWeight)
                    {
                        weakestID = j;
                        weakestWeight = vert.weights[j];
                    }
                }

                float weightAdjust = 1.0f/(1.0f-weakestWeight);
                vert.weights.Remove(weakestID);
                vert.bones.Remove(weakestID);

                for(int j=0; j<vert.weights.Num(); j++)
                    vert.weights[j] *= weightAdjust;
            }
        }*/
        for(int i=0; i<vertInfo.Num(); i++)
        {
            VertAnimInfo &vert = vertInfo[i];

            for(int j=0; j<vert.bones.Num(); j++)
            {
                if(vert.weights[j] <= 0.15f)
                {
                    float weightAdjust = 1.0f/(1.0f-vert.weights[j]);
                    vert.weights.Remove(j);
                    vert.bones.Remove(j);

                    for(int k=0; k<vert.weights.Num(); k++)
                        vert.weights[k] *= weightAdjust;

                    --j;
                }
            }
        }

        //--------- 
        // remove excess bone influence from tris (can only have 4 bones influencing any triangle)
        for(int i=0; i<nSections; i++)
        {
            DrawSection &section = SectionList[i];
            if(!section.numFaces) continue;

            for(int j=0; j<section.numFaces; j++)
            {
                UINT *triVertIDs = &indices[(section.startFace+j)*3];

                List<UINT> bones;
                List<float> bestVertWeights;

                for(int k=0; k<3; k++)
                {
                    VertAnimInfo &info = vertInfo[triVertIDs[k]];

                    for(int l=0; l<info.bones.Num(); l++)
                    {
                        UINT id = bones.FindValueIndex(info.bones[l]);
                        if(id == INVALID)
                        {
                            bones.Add(info.bones[l]);
                            bestVertWeights.Add(info.weights[l]);
                        }
                        else
                            bestVertWeights[id] = MAX(bestVertWeights[id], info.weights[l]);
                    }
                }

                while(bones.Num() > 4)
                {
                    int removeBone, removeBoneID;
                    float bestWeight = M_INFINITE;

                    for(int k=0; k<bones.Num(); k++)
                    {
                        if(bestVertWeights[k] < bestWeight)
                        {
                            removeBone = bones[k];
                            removeBoneID = k;
                            bestWeight = bestVertWeights[k];
                        }
                    }

                    for(int k=0; k<3; k++)
                    {
                        VertAnimInfo &info = vertInfo[triVertIDs[k]];
                        UINT id = info.bones.FindValueIndex(removeBone);
                        if(id == INVALID) continue;

                        float weightAdjust = 1.0f/(1.0f-info.weights[id]);
                        info.weights.Remove(id);
                        info.bones.Remove(id);

                        for(int l=0; l<info.weights.Num(); l++)
                            info.weights[l] *= weightAdjust;
                    }

                    bones.Remove(removeBoneID);
                    bestVertWeights.Remove(removeBoneID);
                }
            }
        }

        //--------- 
        // sort out sections of triangles that are influenced up to a max of 4 bones
        // also, duplicate shared verts
        VBData *newVBD = new VBData;
        newVBD->CopyList(*vbd);

        newVBD->TVList.SetSize(2);
        newVBD->TVList[1].SetWidth(4);
        newVBD->TVList[1].SetSize(nVerts);

        List<SubSectionInfo> newSubSections;

        for(int i=0; i<nSections; i++)
        {
            List<TriBoneInfo> triInfo;

            DrawSection &section = SectionList[i];
            if(!section.numFaces) continue;

            for(int j=0; j<section.numFaces; j++)
            {
                UINT *triVertIDs = &indices[(section.startFace+j)*3];

                TriBoneInfo &newTri = *triInfo.CreateNew();

                for(int k=0; k<3; k++)
                {
                    VertAnimInfo &info = vertInfo[triVertIDs[k]];

                    for(int l=0; l<info.bones.Num(); l++)
                        newTri.bones.SafeAdd(info.bones[l]);
                }
            }

            BitList UsedTris;
            UsedTris.SetSize(section.numFaces);
            DWORD nUsedTris = 0;

            while(nUsedTris != section.numFaces)
            {
                DWORD triSectionID = newSubSections.Num();
                SubSectionInfo *curSubSecInfo = newSubSections.CreateNew();
                curSubSecInfo->section = i;

                for(int j=0; j<triInfo.Num(); j++)
                {
                    if(UsedTris[j]) continue;

                    TriBoneInfo &tri = triInfo[j];

                    List<UINT> secBones;
                    secBones.CopyList(curSubSecInfo->bones);

                    BOOL bBadTri = FALSE;
                    for(int k=0; k<tri.bones.Num(); k++)
                    {
                        secBones.SafeAdd(tri.bones[k]);
                        if(secBones.Num() > 4)
                            break;
                    }

                    if(secBones.Num() > 4) continue;

                    DWORD triID = section.startFace+j;

                    curSubSecInfo->bones.CopyList(secBones);
                    curSubSecInfo->tris << triID;

                    UINT *triVertIDs = &indices[triID*3];
                    for(int k=0; k<3; k++)
                    {
                        VertAnimInfo *info = &vertInfo[triVertIDs[k]];
                        UINT id = info->sections.FindValueIndex(triSectionID);
                        if(id == INVALID)
                        {
                            UINT vertID;
                            if(info->sections.Num() >= 1) //duplicate vertex
                            {
                                vertID = newVBD->DuplicateVertex(triVertIDs[k]);
                                adjustedIndices[(triID*3)+k] = vertID;

                                VertAnimInfo &newVertInfo = *vertInfo.CreateNew();
                                info = &vertInfo[triVertIDs[k]]; //reset pointer

                                newVertInfo.bones.CopyList(info->bones);
                                newVertInfo.weights.CopyList(info->weights);
                                newVertInfo.sections << triSectionID;
                            }
                            else
                                vertID = triVertIDs[k];

                            info->sections << triSectionID;
                            info->sectionVertIDs << vertID;

                            List<Vect4> &vertWeights = *newVBD->TVList[1].GetV4();
                            for(int l=0; l<4; l++)
                            {
                                if(l >= curSubSecInfo->bones.Num())
                                    vertWeights[vertID].ptr[l] = 0.0f;
                                else
                                {
                                    UINT boneID = curSubSecInfo->bones[l];
                                    UINT weightID = info->bones.FindValueIndex(boneID);
                                    if(weightID == INVALID)
                                        vertWeights[vertID].ptr[l] = 0.0f;
                                    else
                                        vertWeights[vertID].ptr[l] = info->weights[weightID];
                                }
                            }
                        }
                        else
                            adjustedIndices[(triID*3)+k] = info->sectionVertIDs[id];
                    }

                    UsedTris.Set(j);
                    ++nUsedTris;
                }
            }
            for(int j=0; j<triInfo.Num(); j++)
                triInfo[j].FreeData();
        }

        //---------
        // create animated draw sections and create new index buffer
        DWORD curTriID = 0;
        List<UINT> newIndices;

        for(int i=0; i<newSubSections.Num(); i++)
        {
            SubSectionInfo &subSecInfo = newSubSections[i];
            AnimSection &animSection = AnimatedSections[subSecInfo.section];
            AnimSubSection &subSection = *animSection.SubSections.CreateNew();

            subSection.numBones = subSecInfo.bones.Num();
            for(int j=0; j<subSecInfo.bones.Num(); j++)
                subSection.bones[j] = subSecInfo.bones[j];

            subSection.startFace = curTriID;

            for(int j=0; j<subSecInfo.tris.Num(); j++)
            {
                UINT *tri = &adjustedIndices[subSecInfo.tris[j]*3];
                newIndices << tri[0] << tri[1] << tri[2];

                ++curTriID;
            }

            subSection.numFaces = curTriID-subSection.startFace;

            subSecInfo.FreeData();
        }

        //rebuild original bone data
        for(int i=0; i<BoneList.Num(); i++)
            BoneList[i].Weights.Clear();

        for(int i=0; i<vertInfo.Num(); i++)
        {
            for(int j=0; j<vertInfo[i].bones.Num(); j++)
            {
                VWeight weight;
                weight.vert = i;
                weight.weight = vertInfo[i].weights[j];

                BoneList[vertInfo[i].bones[j]].Weights << weight;
            }

            vertInfo[i].FreeData();
        }

        delete VertBuffer;
        delete IdxBuffer;

        UINT numIndices;
        UINT *indexArray;
        newIndices.TransferTo(indexArray, numIndices);

        nVerts = newVBD->VertList.Num();

        IdxBuffer = CreateIndexBuffer(GS_UNSIGNED_LONG, indexArray, numIndices);
        VertBuffer = CreateVertexBuffer(newVBD);
    }
    else
    {
        for(int i=0; i<nSections; i++)
            animData << AnimatedSections[i].SubSections;
    }

    animData.Close();

    traceOut;
}
Example #4
0
void  Triangulator::ConnectChibiLoops(ChibiLoopNode &loopNode, List<LoopVerts> &LoopList, List<LoopVerts> &NewLoopList)
{
    DWORD i, j, k, l;

    List<PolyLine> CurLoop;
    CurLoop.CopyList(LoopList[loopNode.loop]);

    if(!ChibiLoopFacingUp(CurLoop))
        ReverseLoop(CurLoop);

    List<DWORD> AlreadyUsed;

    for(i=0; i<loopNode.Children.Num(); i++)
    {
        ChibiLoopNode &childNode = loopNode.Children[i];
        List<PolyLine> &childLoop = LoopList[childNode.loop];

        if(ChibiLoopFacingUp(childLoop))
            ReverseLoop(childLoop);
    }

    List<DWORD> CurChildren;
    CurChildren.SetSize(loopNode.Children.Num());
    for(i=0; i<loopNode.Children.Num(); i++)
        CurChildren[i] = i;

    i = 0;

    while(CurChildren.Num())
    {
        ChibiLoopNode &childNode = loopNode.Children[CurChildren[i]];
        List<PolyLine> &childLoop = LoopList[childNode.loop];

        //---------------------------------------------
        // find closest points between loops

        DWORD curBestChoiceLoop1 = INVALID;
        DWORD curBestChoiceLoop2 = INVALID;
        float closestPos = 0.0f;

        for(j=0; j<CurLoop.Num(); j++)
        {
            if(AlreadyUsed.FindValueIndex(CurLoop[j].v1) != INVALID)
                continue;

            Vect2 &v1 = Verts[CurLoop[j].v1];

            for(k=0; k<childLoop.Num(); k++)
            {
                if(AlreadyUsed.FindValueIndex(childLoop[k].v1) != INVALID)
                    continue;

                Vect2 &v2 = Verts[childLoop[k].v1];

                BOOL bBadChoice = LineIntersectsShape(v1, v2, CurLoop);

                if(bBadChoice)
                    continue;

                for(l=0; l<CurChildren.Num(); l++)
                {
                    if(LineIntersectsShape(v1, v2, LoopList[loopNode.Children[CurChildren[l]].loop]))
                    {
                        bBadChoice = TRUE;
                        break;
                    }
                }

                if(bBadChoice)
                    continue;

                float dist = v2.Dist(v1);

                if((curBestChoiceLoop1 != INVALID) && (dist > closestPos))
                    continue;

                closestPos = dist;
                curBestChoiceLoop1 = j;
                curBestChoiceLoop2 = k;
            }
        }

        if(curBestChoiceLoop1 == INVALID)
        {
            i = (i == CurChildren.Num()-1) ? 0 : (i+1);
            if(i == 0)
            {
                AppWarning(TEXT("...almost infinitely looped there.  Fortunately I have measures against such devious things."));
                break;
            }
            continue;
        }

        AlreadyUsed << CurLoop[curBestChoiceLoop1].v1;
        AlreadyUsed << childLoop[curBestChoiceLoop2].v1;

        //---------------------------------------------
        // connect loops

        if(CurLoop[0].lineData && !childLoop[0].lineData)
        {
            for(j=0; j<childLoop.Num(); j++)
                childLoop[j].lineData = CurLoop[0].lineData;
        }

        SetNewLoopStartPosition(CurLoop,   curBestChoiceLoop1);
        SetNewLoopStartPosition(childLoop, curBestChoiceLoop2);

        if(!CurLoop[0].lineData && childLoop[0].lineData)
        {
            for(j=0; j<CurLoop.Num(); j++)
                CurLoop[j].lineData = childLoop[0].lineData;
        }

        PolyLine &lastLine = CurLoop.Last();
        PolyLine *pLine = CurLoop.CreateNew();
        pLine->v1 = lastLine.v2;
        pLine->v2 = childLoop[0].v1;

        CurLoop.AppendList(childLoop);
        pLine = CurLoop.CreateNew();
        pLine->v1 = childLoop[0].v1;
        pLine->v2 = CurLoop[0].v1;

        /*for(j=0; j<CurLoop.Num(); j++)
        {
            String chong;
            chong << long(j) << TEXT(": x: ") << FormattedString(TEXT("%0.4f"), Verts[CurLoop[j].v1].x) << TEXT("\ty: ") << FormattedString(TEXT("%0.4f"), Verts[CurLoop[j].v1].y) << TEXT("\r\n");
            OutputDebugString(chong);
        }
        OutputDebugString(TEXT("====================================\r\n"));*/

        CurChildren.Remove(i);
        i = 0;
    }

    NewLoopList.CreateNew()->CopyList(CurLoop);
    CurLoop.Clear();

    for(i=0; i<loopNode.Children.Num(); i++)
    {
        ChibiLoopNode &childNode = loopNode.Children[i];

        for(j=0; j<childNode.Children.Num(); j++)
            ConnectChibiLoops(childNode.Children[j], LoopList, NewLoopList);
    }
}