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); }
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); }
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 §ion = 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 §ion = 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; }
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); } }