void CSkelMeshViewer::TagMesh(CSkelMeshInstance *Inst) { for (int i = 0; i < TaggedMeshes.Num(); i++) { if (TaggedMeshes[i]->pMesh == Inst->pMesh) { // already tagged, remove delete TaggedMeshes[i]; TaggedMeshes.RemoveAt(i); return; } } // not tagget yet, create a copy of the mesh CSkelMeshInstance* NewInst = new CSkelMeshInstance(); NewInst->SetMesh(Inst->pMesh); TaggedMeshes.Add(NewInst); }
void CSkelMeshViewer::TagMesh(CSkelMeshInstance *Inst) { for (int i = 0; i < TaggedMeshes.Num(); i++) { if (TaggedMeshes[i]->pMesh == Inst->pMesh) { // already tagged, remove delete TaggedMeshes[i]; TaggedMeshes.RemoveAt(i); return; } } // not tagget yet, create a copy of the mesh CSkelMeshInstance* NewInst = new CSkelMeshInstance(); NewInst->SetMesh(Inst->pMesh); // remember animation which is linked to the object (UE2, UE4) NewInst->SetAnim(Anim); TaggedMeshes.Add(NewInst); }
CSkelMeshViewer::CSkelMeshViewer(CSkeletalMesh* Mesh0, CApplication* Window) : CMeshViewer(Mesh0->OriginalMesh, Window) , Mesh(Mesh0) , AnimIndex(-1) , IsFollowingMesh(false) , ShowSkel(0) , ShowLabels(false) , ShowAttach(false) , ShowUV(false) { CSkelMeshInstance *SkelInst = new CSkelMeshInstance(); SkelInst->SetMesh(Mesh); if (GForceAnimSet) { CAnimSet *AttachAnim = GetAnimSet(GForceAnimSet); if (!AttachAnim) { appPrintf("WARNING: specified wrong AnimSet (%s class) object to attach\n", GForceAnimSet->GetClassName()); GForceAnimSet = NULL; } if (AttachAnim) SkelInst->SetAnim(AttachAnim); } else if (Mesh->OriginalMesh->IsA("SkeletalMesh")) // UE2 class { const USkeletalMesh *OriginalMesh = static_cast<USkeletalMesh*>(Mesh->OriginalMesh); if (OriginalMesh->Animation) SkelInst->SetAnim(OriginalMesh->Animation->ConvertedAnim); } Inst = SkelInst; // compute bounds for the current mesh CVec3 Mins, Maxs; if (Mesh0->Lods.Num()) { const CSkelMeshLod &Lod = Mesh0->Lods[0]; ComputeBounds(&Lod.Verts[0].Position, Lod.NumVerts, sizeof(CSkelMeshVertex), Mins, Maxs); // ... transform bounds SkelInst->BaseTransformScaled.TransformPointSlow(Mins, Mins); SkelInst->BaseTransformScaled.TransformPointSlow(Maxs, Maxs); } else { Mins = Maxs = nullVec3; } // extend bounds with additional meshes for (int i = 0; i < TaggedMeshes.Num(); i++) { CSkelMeshInstance* Inst = TaggedMeshes[i]; if (Inst->pMesh != SkelInst->pMesh) { const CSkeletalMesh *Mesh2 = Inst->pMesh; // the same code for Inst CVec3 Bounds2[2]; const CSkelMeshLod &Lod2 = Mesh2->Lods[0]; ComputeBounds(&Lod2.Verts[0].Position, Lod2.NumVerts, sizeof(CSkelMeshVertex), Bounds2[0], Bounds2[1]); Inst->BaseTransformScaled.TransformPointSlow(Bounds2[0], Bounds2[0]); Inst->BaseTransformScaled.TransformPointSlow(Bounds2[1], Bounds2[1]); ComputeBounds(Bounds2, 2, sizeof(CVec3), Mins, Maxs, true); // include Bounds2 into Mins/Maxs } // reset animation for all meshes TaggedMeshes[i]->TweenAnim(NULL, 0); } InitViewerPosition(Mins, Maxs); #if HIGHLIGHT_CURRENT TimeSinceCreate = -2; // ignore first 2 frames: 1st frame will be called after mesh changing, 2nd frame could load textures etc #endif #if SHOW_BOUNDS appPrintf("Bounds.min = %g %g %g\n", FVECTOR_ARG(Mesh->BoundingBox.Min)); appPrintf("Bounds.max = %g %g %g\n", FVECTOR_ARG(Mesh->BoundingBox.Max)); appPrintf("Origin = %g %g %g\n", FVECTOR_ARG(Mesh->MeshOrigin)); appPrintf("Sphere = %g %g %g R=%g\n", FVECTOR_ARG(Mesh->BoundingSphere), Mesh->BoundingSphere.R); appPrintf("Offset = %g %g %g\n", VECTOR_ARG(offset)); #endif // SHOW_BOUNDS }
void CSkelMeshViewer::ProcessKey(int key) { guard(CSkelMeshViewer::ProcessKey); #if TEST_ANIMS static float Alpha = -1.0f; //!!!! #endif int i; CSkelMeshInstance *MeshInst = static_cast<CSkelMeshInstance*>(Inst); int NumAnims = MeshInst->GetAnimCount(); //?? use Meshes[] instead ... const char *AnimName; float Frame; float NumFrames; float Rate; MeshInst->GetAnimParams(0, AnimName, Frame, NumFrames, Rate); switch (key) { // animation control case '[': case ']': if (NumAnims) { if (key == '[') { if (--AnimIndex < -1) AnimIndex = NumAnims - 1; } else { if (++AnimIndex >= NumAnims) AnimIndex = -1; } // note: AnimIndex changed now AnimName = MeshInst->GetAnimName(AnimIndex); MeshInst->TweenAnim(AnimName, 0.25); // change animation with tweening for (i = 0; i < Meshes.Num(); i++) Meshes[i]->TweenAnim(AnimName, 0.25); } break; case ',': // '<' case '.': // '>' if (NumFrames) { if (key == ',') Frame -= 0.2f; else Frame += 0.2f; Frame = bound(Frame, 0, NumFrames-1); MeshInst->FreezeAnimAt(Frame); for (i = 0; i < Meshes.Num(); i++) Meshes[i]->FreezeAnimAt(Frame); } break; case ' ': if (AnimIndex >= 0) { MeshInst->PlayAnim(AnimName); for (i = 0; i < Meshes.Num(); i++) Meshes[i]->PlayAnim(AnimName); } break; case 'x': if (AnimIndex >= 0) { MeshInst->LoopAnim(AnimName); for (i = 0; i < Meshes.Num(); i++) Meshes[i]->LoopAnim(AnimName); } break; // mesh debug output case 'l': if (++MeshInst->LodNum >= Mesh->Lods.Num()) MeshInst->LodNum = 0; break; case 'u': if (++MeshInst->UVIndex >= Mesh->Lods[MeshInst->LodNum].NumTexCoords) MeshInst->UVIndex = 0; break; case 's': if (++ShowSkel > 2) ShowSkel = 0; break; case 'b': ShowLabels = !ShowLabels; break; case 'a': ShowAttach = !ShowAttach; break; case 'i': DrawFlags ^= DF_SHOW_INFLUENCES; break; case 'b'|KEY_CTRL: MeshInst->DumpBones(); break; #if TEST_ANIMS //!! testing, remove later case 'y': if (Alpha >= 0) { Alpha = -1; MeshInst->ClearSkelAnims(); return; } Alpha = 0; MeshInst->LoopAnim("CrouchF", 1, 0, 2); // MeshInst->LoopAnim("WalkF", 1, 0, 2); // MeshInst->LoopAnim("RunR", 1, 0, 2); // MeshInst->LoopAnim("SwimF", 1, 0, 2); MeshInst->SetSecondaryAnim(2, "RunF"); break; case 'y'|KEY_CTRL: MeshInst->SetBlendParams(0, 1.0f, "b_MF_Forearm_R"); // MeshInst->SetBlendParams(0, 1.0f, "b_MF_Hand_R"); // MeshInst->SetBlendParams(0, 1.0f, "b_MF_ForeTwist2_R"); break; case 'c': Alpha -= 0.02; if (Alpha < 0) Alpha = 0; MeshInst->SetSecondaryBlend(2, Alpha); break; case 'v': Alpha += 0.02; if (Alpha > 1) Alpha = 1; MeshInst->SetSecondaryBlend(2, Alpha); break; /* case 'u'|KEY_CTRL: MeshInst->LoopAnim("Gesture_Taunt02", 1, 0, 1); MeshInst->SetBlendParams(1, 1.0f, "Bip01 Spine1"); MeshInst->LoopAnim("WalkF", 1, 0, 2); MeshInst->SetBlendParams(2, 1.0f, "Bip01 R Thigh"); MeshInst->LoopAnim("AssSmack", 1, 0, 4); MeshInst->SetBlendParams(4, 1.0f, "Bip01 L UpperArm"); break; */ #endif // TEST_ANIMS case 'a'|KEY_CTRL: { const CAnimSet *PrevAnim = MeshInst->GetAnim(); // find next animation set (code is similar to PAGEDOWN handler) int looped = 0; int ObjIndex = -1; bool found = (PrevAnim == NULL); // whether previous AnimSet was found; NULL -> any while (true) { ObjIndex++; if (ObjIndex >= UObject::GObjObjects.Num()) { ObjIndex = 0; looped++; if (looped > 1) break; // no other objects } const UObject *Obj = UObject::GObjObjects[ObjIndex]; const CAnimSet *Anim = GetAnimSet(Obj); if (!Anim) continue; if (Anim == PrevAnim) { if (found) break; // loop detected found = true; continue; } if (found && Anim) { // found desired animation set MeshInst->SetAnim(Anim); // will rebind mesh to new animation set for (int i = 0; i < Meshes.Num(); i++) Meshes[i]->SetAnim(Anim); AnimIndex = -1; appPrintf("Bound %s'%s' to %s'%s'\n", Object->GetClassName(), Object->Name, Obj->GetClassName(), Obj->Name); break; } } } break; case 't'|KEY_CTRL: { CSkelMeshInstance *SkelInst = new CSkelMeshInstance(); SkelInst->SetMesh(MeshInst->pMesh); TagMesh(SkelInst); } break; case 'r'|KEY_CTRL: { int mode = MeshInst->RotationMode + 1; if (mode > EARO_ForceDisabled) mode = 0; MeshInst->RotationMode = (EAnimRotationOnly)mode; for (int i = 0; i < Meshes.Num(); i++) Meshes[i]->RotationMode = (EAnimRotationOnly)mode; } break; case 'u'|KEY_CTRL: ShowUV = !ShowUV; break; case 'f': IsFollowingMesh = true; break; default: CMeshViewer::ProcessKey(key); } unguard; }