From cf473289f25d88aa177ec14114d495251c0250cc Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 10 Nov 2024 23:48:05 +0300 Subject: [PATCH] Move skeleton building and blending to engine --- src/engine/client/cg_msgdef.h | 26 ++++++++++-- src/engine/renderer/tr_animation.cpp | 27 +++++++++++++ src/engine/renderer/tr_local.h | 1 + src/engine/renderer/tr_main.cpp | 59 +++++++++++++++++++++++++++- src/engine/renderer/tr_types.h | 21 ++++++++++ src/shared/client/cg_api.cpp | 3 +- 6 files changed, 130 insertions(+), 7 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 2f62dcda66..69d0183ac5 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -96,18 +96,36 @@ namespace Util { } }; + template<> struct SerializeTraits> { + static void Write( Writer& stream, const std::vector& boneMods ) { + stream.WriteSize( boneMods.size() ); + stream.WriteData( boneMods.data(), boneMods.size() * sizeof( BoneMod ) ); + } + + static std::vector Read( Reader& stream ) { + std::vector boneMods; + const size_t size = stream.ReadSize(); + boneMods.resize( size ); + stream.ReadData( boneMods.data(), size * sizeof( BoneMod ) ); + return boneMods; + } + }; + // Use that bone optimization for refEntity_t template<> struct SerializeTraits { static void Write(Writer& stream, const refEntity_t& ent) { - stream.WriteData(&ent, offsetof(refEntity_t, skeleton)); - stream.Write(ent.skeleton); + stream.WriteData(&ent, offsetof(refEntity_t, boneMods)); + stream.Write>( ent.boneMods ); + // stream.Write(ent.skeleton); } + static refEntity_t Read(Reader& stream) { refEntity_t ent; - stream.ReadData(&ent, offsetof(refEntity_t, skeleton)); - ent.skeleton = stream.Read(); + stream.ReadData(&ent, offsetof(refEntity_t, boneMods)); + ent.boneMods = stream.Read>(); + // ent.skeleton = stream.Read(); return ent; } }; diff --git a/src/engine/renderer/tr_animation.cpp b/src/engine/renderer/tr_animation.cpp index 491fc233ad..be1a3e4e71 100644 --- a/src/engine/renderer/tr_animation.cpp +++ b/src/engine/renderer/tr_animation.cpp @@ -1313,6 +1313,32 @@ static int IQMBuildSkeleton( refSkeleton_t *skel, skelAnimation_t *skelAnim, return true; } +void R_TransformSkeleton( refSkeleton_t* skel, const float scale ) { + skel->scale = scale; + + switch ( skel->type ) { + case refSkeletonType_t::SK_INVALID: + case refSkeletonType_t::SK_ABSOLUTE: + return; + + default: + break; + } + + // calculate absolute transforms + for ( refBone_t* bone = &skel->bones[0]; bone < &skel->bones[skel->numBones]; bone++ ) { + if ( bone->parentIndex >= 0 ) { + refBone_t* parent; + + parent = &skel->bones[bone->parentIndex]; + + TransCombine( &bone->t, &parent->t, &bone->t ); + } + } + + skel->type = refSkeletonType_t::SK_ABSOLUTE; +} + /* ============== RE_BuildSkeleton @@ -1468,6 +1494,7 @@ int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t hAnim, int startFrame, int } // FIXME: clear existing bones and bounds? + skel->numBones = 0; return false; } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index b44fc3e0cc..f3c2eb98cf 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -3730,6 +3730,7 @@ inline bool checkGLErrors() int RE_CheckSkeleton( refSkeleton_t *skel, qhandle_t hModel, qhandle_t hAnim ); int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac, bool clearOrigin ); + void R_TransformSkeleton( refSkeleton_t* skel, const float scale ); int RE_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float frac ); int RE_AnimNumFrames( qhandle_t hAnim ); int RE_AnimFrameRate( qhandle_t hAnim ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 1c9e785dbd..3d1da023b2 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -2095,19 +2095,74 @@ void R_AddEntitySurfaces() } else { - switch ( tr.currentModel->type ) - { + switch ( tr.currentModel->type ) { case modtype_t::MOD_MESH: R_AddMDVSurfaces( ent ); break; case modtype_t::MOD_MD5: + /* Log::Warn("%i %s: old: %i-%i %f new: %i-%i %f | %f %f", ent->e.animationHandle, + R_GetAnimationByHandle( ent->e.animationHandle )->name, ent->e.startFrame, + ent->e.endFrame, ent->e.lerp, ent->e.startFrame2, ent->e.endFrame2, ent->e.lerp2, + ent->e.blendLerp, ent->e.scale ); */ + if ( ent->e.scale == 0 ) { + ent->e.scale = 1; + } + if ( ent->e.animationHandle == 0 ) { + ent->e.animationHandle = ent->e.animationHandle2; + } else if ( ent->e.animationHandle2 == 0 ) { + ent->e.animationHandle2 = ent->e.animationHandle; + } + + RE_BuildSkeleton( &ent->e.skeleton, ent->e.animationHandle, ent->e.startFrame, ent->e.endFrame, + ent->e.lerp, ent->e.clearOrigin ); + ent->e.skeleton.scale = ent->e.scale; + if ( ent->e.blendLerp > 0.0 ) { + refSkeleton_t skel; + RE_BuildSkeleton( &skel, ent->e.animationHandle2, ent->e.startFrame2, ent->e.endFrame2, + ent->e.lerp2, ent->e.clearOrigin2 ); + RE_BlendSkeleton( &ent->e.skeleton, &skel, ent->e.blendLerp ); + } + + for ( const BoneMod& boneMod : ent->e.boneMods ) { + QuatMultiply2( ent->e.skeleton.bones[boneMod.index].t.rot, boneMod.rotation ); + } R_AddMD5Surfaces( ent ); break; case modtype_t::MOD_IQM: + { + /* Log::Warn("%i %s: old: %i-%i %f new: %i-%i %f | %f %f", ent->e.animationHandle, + R_GetAnimationByHandle( ent->e.animationHandle )->name, ent->e.startFrame, + ent->e.endFrame, ent->e.lerp, ent->e.startFrame2, ent->e.endFrame2, ent->e.lerp2, + ent->e.blendLerp, ent->e.scale ); */ + bool transform = true; + if ( ent->e.scale == 0 ) { + ent->e.scale = 1; + } + if ( ent->e.animationHandle == 0 ) { + ent->e.animationHandle = ent->e.animationHandle2; + } else if ( ent->e.animationHandle2 == 0 ) { + ent->e.animationHandle2 = ent->e.animationHandle; + } + + ent->e.skeleton.scale = ent->e.scale; + RE_BuildSkeleton( &ent->e.skeleton, ent->e.animationHandle, ent->e.startFrame, ent->e.endFrame, + ent->e.lerp, ent->e.clearOrigin ); + if ( ent->e.blendLerp > 0.0 ) { + refSkeleton_t skel; + RE_BuildSkeleton( &skel, ent->e.animationHandle2, ent->e.startFrame2, ent->e.endFrame2, + ent->e.lerp2, ent->e.clearOrigin2 ); + RE_BlendSkeleton( &ent->e.skeleton, &skel, ent->e.blendLerp ); + } + + for ( const BoneMod& boneMod : ent->e.boneMods ) { + QuatMultiply2( ent->e.skeleton.bones[boneMod.index].t.rot, boneMod.rotation ); + } + R_TransformSkeleton( &ent->e.skeleton, ent->e.scale ); R_AddIQMSurfaces( ent ); break; + } case modtype_t::MOD_BSP: R_AddBSPModelSurfaces( ent ); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index e00a2cd016..094418ef4a 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -156,6 +156,12 @@ enum class refSkeletonType_t SK_ABSOLUTE }; +struct BoneMod { + int index; + vec3_t translation; + quat_t rotation; +}; + struct alignas(16) refSkeleton_t { refSkeletonType_t type; // skeleton has been reset @@ -211,6 +217,21 @@ struct refEntity_t int altShaderIndex; + qhandle_t animationHandle; + int startFrame; + int endFrame; + float lerp; + int clearOrigin; + qhandle_t animationHandle2; + int startFrame2; + int endFrame2; + float lerp2; + int clearOrigin2; + float blendLerp; + float scale; + + std::vector boneMods; + // KEEP SKELETON AT THE END OF THE STRUCTURE // it is to make a serialization hack for refEntity_t easier // by memcpying up to skeleton and then serializing skeleton diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index c0df4cca4a..880b8c8566 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -448,6 +448,7 @@ qhandle_t trap_R_RegisterAnimation( const char *name ) int trap_R_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac, bool clearOrigin ) { int result; + skel->numBones = 0; VM::SendMsg(anim, startFrame, endFrame, frac, clearOrigin, *skel, result); return result; } @@ -460,7 +461,7 @@ int trap_R_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float if ( skel->numBones != blend->numBones ) { - Log::Warn("trap_R_BlendSkeleton: different number of bones %d != %d", skel->numBones, blend->numBones); + // Log::Warn("trap_R_BlendSkeleton: different number of bones %d != %d", skel->numBones, blend->numBones); return false; }