From f03b4eec4c37eab75a5bd639279cfcc615105b01 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 23 Apr 2020 22:25:18 +0200 Subject: implemented skinned peds, no cutscene hands yet --- src/animation/AnimBlendClumpData.h | 4 +- src/animation/Bones.cpp | 52 ++++++++ src/animation/Bones.h | 24 ++++ src/animation/FrameUpdate.cpp | 243 +++++++++++++++++++++++++++++++++---- src/animation/RpAnimBlend.cpp | 114 ++++++++++++++--- src/animation/RpAnimBlend.h | 5 +- 6 files changed, 399 insertions(+), 43 deletions(-) create mode 100644 src/animation/Bones.cpp create mode 100644 src/animation/Bones.h (limited to 'src/animation') diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h index 1c8c391d..a537425a 100644 --- a/src/animation/AnimBlendClumpData.h +++ b/src/animation/AnimBlendClumpData.h @@ -18,7 +18,7 @@ struct AnimBlendFrameData #ifdef PED_SKIN union { RwFrame *frame; - RpHAnimStdKeyFrame *hanimframe; + RpHAnimStdKeyFrame *hanimFrame; }; int32 nodeID; #else @@ -50,4 +50,6 @@ public: #endif void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg); }; +#ifndef PED_SKIN static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error"); +#endif diff --git a/src/animation/Bones.cpp b/src/animation/Bones.cpp new file mode 100644 index 00000000..1608449d --- /dev/null +++ b/src/animation/Bones.cpp @@ -0,0 +1,52 @@ +#include "common.h" +#include "PedModelInfo.h" +#include "Bones.h" + +#ifdef PED_SKIN + +int +ConvertPedNode2BoneTag(int node) +{ + switch(node){ + case PED_TORSO: return BONE_waist; + case PED_MID: return BONE_torso; // this is what Xbox/Mobile use + // return BONE_mid; // this is what PS2/PC use + case PED_HEAD: return BONE_head; + case PED_UPPERARML: return BONE_upperarml; + case PED_UPPERARMR: return BONE_upperarmr; + case PED_HANDL: return BONE_Lhand; + case PED_HANDR: return BONE_Rhand; + case PED_UPPERLEGL: return BONE_upperlegl; + case PED_UPPERLEGR: return BONE_upperlegr; + case PED_FOOTL: return BONE_footl; + case PED_FOOTR: return BONE_footr; + case PED_LOWERLEGR: return BONE_lowerlegl; + } + return -1; +} + +const char* +ConvertBoneTag2BoneName(int tag) +{ + switch(tag){ + case BONE_waist: return "Swaist"; + case BONE_upperlegr: return "Supperlegr"; + case BONE_lowerlegr: return "Slowerlegr"; + case BONE_footr: return "Sfootr"; + case BONE_upperlegl: return "Supperlegl"; + case BONE_lowerlegl: return "Slowerlegl"; + case BONE_footl: return "Sfootl"; + case BONE_mid: return "Smid"; + case BONE_torso: return "Storso"; + case BONE_head: return "Shead"; + case BONE_upperarmr: return "Supperarmr"; + case BONE_lowerarmr: return "Slowerarmr"; + case BONE_Rhand: return "SRhand"; + case BONE_upperarml: return "Supperarml"; + case BONE_lowerarml: return "Slowerarml"; + case BONE_Lhand: return "SLhand"; + } + return nil; +} + +#endif diff --git a/src/animation/Bones.h b/src/animation/Bones.h new file mode 100644 index 00000000..38d91ba3 --- /dev/null +++ b/src/animation/Bones.h @@ -0,0 +1,24 @@ +#pragma once + +enum BoneTag +{ + BONE_waist, + BONE_upperlegr, + BONE_lowerlegr, + BONE_footr, + BONE_upperlegl, + BONE_lowerlegl, + BONE_footl, + BONE_mid, + BONE_torso, + BONE_head, + BONE_upperarmr, + BONE_lowerarmr, + BONE_Rhand, + BONE_upperarml, + BONE_lowerarml, + BONE_Lhand, +}; + +int ConvertPedNode2BoneTag(int node); +const char *ConvertBoneTag2BoneName(int tag); diff --git a/src/animation/FrameUpdate.cpp b/src/animation/FrameUpdate.cpp index df45bfb5..a38ebc74 100644 --- a/src/animation/FrameUpdate.cpp +++ b/src/animation/FrameUpdate.cpp @@ -8,12 +8,18 @@ CAnimBlendClumpData *gpAnimBlendClump; -void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg); -void FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); -void FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); +// PS2 names without "NonSkinned" +void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); + +void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg); + void -FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -25,9 +31,9 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity){ if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) - FrameUpdateCallBackWith3dVelocityExtraction(frame, arg); + FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(frame, arg); else - FrameUpdateCallBackWithVelocityExtraction(frame, arg); + FrameUpdateCallBackNonSkinnedWithVelocityExtraction(frame, arg); return; } @@ -48,12 +54,7 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -69,7 +70,7 @@ FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg) } void -FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -122,12 +123,7 @@ FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -154,7 +150,7 @@ FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) // original code uses do loops? void -FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) +FrameUpdateCallBackNonSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) { CVector vec, pos(0.0f, 0.0f, 0.0f); CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); @@ -201,12 +197,7 @@ FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ RwMatrixSetIdentity(mat); - - float norm = rot.MagnitudeSqr(); - if(norm == 0.0f) - rot.w = 1.0f; - else - rot *= 1.0f/Sqrt(norm); + rot.Normalise(); rot.Get(mat); } @@ -220,3 +211,203 @@ FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg } RwMatrixUpdate(mat); } + +#ifdef PED_SKIN + +void +FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && + gpAnimBlendClump->velocity){ + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D) + FrameUpdateCallBackSkinnedWith3dVelocityExtraction(frame, arg); + else + FrameUpdateCallBackSkinnedWithVelocityExtraction(frame, arg); + return; + } + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + (*node)->Update(vec, q, 1.0f-totalBlendAmount); + if((*node)->sequence->HasTranslation()) + pos += vec; + rot += q; + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + xform->t.x = pos.x; + xform->t.y = pos.y; + xform->t.z = pos.z; + xform->t.x += frame->resetPos.x; + xform->t.y += frame->resetPos.y; + xform->t.z += frame->resetPos.z; + } +} + +void +FrameUpdateCallBackSkinnedWithVelocityExtraction(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + float transx = 0.0f, transy = 0.0f; + float curx = 0.0f, cury = 0.0f; + float endx = 0.0f, endy = 0.0f; + bool looped = false; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount); + cury += vec.y; + if((*node)->association->HasXTranslation()) + curx += vec.x; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount); + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + transy += vec.y; + if((*node)->association->HasXTranslation()) + transx += vec.x; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount); + endy += vec.y; + if((*node)->association->HasXTranslation()) + endx += vec.x; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + gpAnimBlendClump->velocity->x = transx - curx; + gpAnimBlendClump->velocity->y = transy - cury; + if(looped){ + gpAnimBlendClump->velocity->x += endx; + gpAnimBlendClump->velocity->y += endy; + } + xform->t.x = pos.x - transx; + xform->t.y = pos.y - transy; + xform->t.z = pos.z; + if(xform->t.z >= -0.8f) + if(xform->t.z < -0.4f) + xform->t.z += (2.5f * xform->t.z + 2.0f) * frame->resetPos.z; + else + xform->t.z += frame->resetPos.z; + xform->t.x += frame->resetPos.x; + xform->t.y += frame->resetPos.y; + } +} + +void +FrameUpdateCallBackSkinnedWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + CVector trans(0.0f, 0.0f, 0.0f); + CVector cur(0.0f, 0.0f, 0.0f); + CVector end(0.0f, 0.0f, 0.0f); + bool looped = false; + RpHAnimStdKeyFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount); + cur += vec; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount); + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + trans += vec; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount); + end += vec; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + *gpAnimBlendClump->velocity = trans - cur; + if(looped) + *gpAnimBlendClump->velocity += end; + xform->t.x = (pos - trans).x + frame->resetPos.x; + xform->t.y = (pos - trans).y + frame->resetPos.y; + xform->t.z = (pos - trans).z + frame->resetPos.z; + } +} + +#endif diff --git a/src/animation/RpAnimBlend.cpp b/src/animation/RpAnimBlend.cpp index 20290666..d3e10889 100644 --- a/src/animation/RpAnimBlend.cpp +++ b/src/animation/RpAnimBlend.cpp @@ -1,12 +1,17 @@ #include "common.h" +#include "RwHelper.h" #include "General.h" #include "NodeName.h" #include "VisibilityPlugins.h" +#include "Bones.h" #include "AnimBlendClumpData.h" #include "AnimBlendHierarchy.h" #include "AnimBlendAssociation.h" #include "RpAnimBlend.h" +#ifdef PED_SKIN +#include "PedModelInfo.h" +#endif RwInt32 ClumpOffset; @@ -122,19 +127,59 @@ FrameForAllChildrenFillFrameArrayCallBack(RwFrame *frame, void *data) return frame; } +// FrameInitCallBack on PS2 void -FrameInitCallBack(AnimBlendFrameData *frameData, void*) +FrameInitCBnonskin(AnimBlendFrameData *frameData, void*) { frameData->flag = 0; frameData->resetPos = *RwMatrixGetPos(RwFrameGetMatrix(frameData->frame)); } void -RpAnimBlendClumpInit(RpClump *clump) +FrameInitCBskin(AnimBlendFrameData *frameData, void*) { + frameData->flag = 0; +} + #ifdef PED_SKIN - TODO -#else +void +RpAnimBlendClumpInitSkinned(RpClump *clump) +{ + int i; + RwV3d boneTab[64]; + CAnimBlendClumpData *clumpData; + RpAtomic *atomic; + RpSkin *skin; + RpHAnimHierarchy *hier; + int numBones; + + RpAnimBlendAllocateData(clump); + clumpData = *RPANIMBLENDCLUMPDATA(clump); + atomic = IsClumpSkinned(clump); + assert(atomic); + skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)); + assert(skin); + numBones = RpSkinGetNumBones(skin); + clumpData->SetNumberOfBones(numBones); + hier = GetAnimHierarchyFromSkinClump(clump); + assert(hier); + memset(boneTab, 0, sizeof(boneTab)); + SkinGetBonePositionsToTable(clump, boneTab); + + AnimBlendFrameData *frames = clumpData->frames; + for(i = 0; i < numBones; i++){ + frames[i].nodeID = HIERNODEID(hier, i); + frames[i].resetPos = boneTab[i]; + frames[i].hanimFrame = (RpHAnimStdKeyFrame*)rpHANIMHIERARCHYGETINTERPFRAME(hier, i); + } + clumpData->ForAllFrames(FrameInitCBskin, nil); + clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION; +} +#endif + +void +RpAnimBlendClumpInitNotSkinned(RpClump *clump) +{ int numFrames = 0; CAnimBlendClumpData *clumpData; RwFrame *root; @@ -147,9 +192,19 @@ RpAnimBlendClumpInit(RpClump *clump) clumpData->SetNumberOfFrames(numFrames); frames = clumpData->frames; RwFrameForAllChildren(root, FrameForAllChildrenFillFrameArrayCallBack, &frames); - clumpData->ForAllFrames(FrameInitCallBack, nil); + clumpData->ForAllFrames(FrameInitCBnonskin, nil); clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION; +} + +void +RpAnimBlendClumpInit(RpClump *clump) +{ +#ifdef PED_SKIN + if(IsClumpSkinned(clump)) + RpAnimBlendClumpInitSkinned(clump); + else #endif + RpAnimBlendClumpInitNotSkinned(clump); } bool @@ -298,42 +353,68 @@ RpAnimBlendClumpGetFirstAssociation(RpClump *clump) return CAnimBlendAssociation::FromLink(clumpData->link.next); } +// FillFrameArrayCallBack on PS2 void -FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg) +FillFrameArrayCBnonskin(AnimBlendFrameData *frame, void *arg) { AnimBlendFrameData **frames = (AnimBlendFrameData**)arg; frames[CVisibilityPlugins::GetFrameHierarchyId(frame->frame)] = frame; } +#ifdef PED_SKIN +void +RpAnimBlendClumpFillFrameArraySkin(RpClump *clump, AnimBlendFrameData **frames) +{ + int i; + CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump); + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump); + for(i = PED_MID; i < PED_NODE_MAX; i++) + frames[i] = &clumpData->frames[RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(i))]; +} +#endif + void RpAnimBlendClumpFillFrameArray(RpClump *clump, AnimBlendFrameData **frames) { #ifdef PED_SKIN - TODO -#else - (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCallBack, frames); + if(IsClumpSkinned(clump)) + RpAnimBlendClumpFillFrameArraySkin(clump, frames); + else #endif + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCBnonskin, frames); } AnimBlendFrameData *pFrameDataFound; +// FrameFindCallBack on PS2 void -FrameFindCallBack(AnimBlendFrameData *frame, void *arg) +FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg) { char *nodename = GetFrameNodeName(frame->frame); if(!CGeneral::faststricmp(nodename, (char*)arg)) pFrameDataFound = frame; } +#ifdef PED_SKIN +void +FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg) +{ + const char *name = ConvertBoneTag2BoneName(frame->nodeID); + if(name && CGeneral::faststricmp(name, (char*)arg) == 0) + pFrameDataFound = frame; +} +#endif + AnimBlendFrameData* RpAnimBlendClumpFindFrame(RpClump *clump, const char *name) { pFrameDataFound = nil; #ifdef PED_SKIN - TODO -#else - (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindCallBack, (void*)name); + if(IsClumpSkinned(clump)) + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBskin, (void*)name); + else #endif + (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBnonskin, (void*)name); return pFrameDataFound; } @@ -369,7 +450,12 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta) } updateData.nodes[i] = nil; - clumpData->ForAllFrames(FrameUpdateCallBack, &updateData); +#ifdef PED_SKIN + if(IsClumpSkinned(clump)) + clumpData->ForAllFrames(FrameUpdateCallBackSkinned, &updateData); + else +#endif + clumpData->ForAllFrames(FrameUpdateCallBackNonSkinned, &updateData); for(link = clumpData->link.next; link; link = link->next){ CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link); diff --git a/src/animation/RpAnimBlend.h b/src/animation/RpAnimBlend.h index ccfa5872..838c8816 100644 --- a/src/animation/RpAnimBlend.h +++ b/src/animation/RpAnimBlend.h @@ -7,7 +7,7 @@ struct AnimBlendFrameData; struct AnimBlendFrameUpdateData { - int foobar; + int foobar; // TODO: figure out what this actually means CAnimBlendNode *nodes[16]; }; @@ -38,4 +38,5 @@ void RpAnimBlendClumpUpdateAnimations(RpClump* clump, float timeDelta); extern CAnimBlendClumpData *gpAnimBlendClump; -void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); -- cgit v1.2.3