forked from FWGS/Paranoia2
378 lines
14 KiB
C++
378 lines
14 KiB
C++
/*
|
|
bs_desf.h - Bone Setup defines
|
|
Copyright (C) 2015 Uncle Mike
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
*/
|
|
|
|
#ifndef BS_DEFS_H
|
|
#define BS_DEFS_H
|
|
|
|
#include <alert.h>
|
|
|
|
struct ikcontextikrule_t;
|
|
class CIKContext;
|
|
|
|
/*
|
|
====================
|
|
CStudioBoneSetup
|
|
|
|
====================
|
|
*/
|
|
class CStudioBoneSetup
|
|
{
|
|
public:
|
|
CStudioBoneSetup()
|
|
{
|
|
InitBoneWeights();
|
|
m_pStudioHeader = NULL;
|
|
m_flBoneControllers = NULL;
|
|
m_flPoseParams = NULL;
|
|
m_iBoneMask = 0;
|
|
}
|
|
//protected:
|
|
const mstudioanimvalue_t *pAnimvalue( const mstudioanim_t *panim, int dof )
|
|
{
|
|
if( !panim || panim->offset[dof] == 0 )
|
|
return NULL;
|
|
return (mstudioanimvalue_t *)((byte *)panim + panim->offset[dof]);
|
|
}
|
|
|
|
const mstudioanimvalue_t *pAnimvalue( const mstudioikerror_t *panim, int dof )
|
|
{
|
|
if( !panim || panim->offset[dof] == 0 )
|
|
return NULL;
|
|
return (mstudioanimvalue_t *)((byte *)panim + panim->offset[dof]);
|
|
}
|
|
|
|
const mstudiomovement_t *pMovement( const mstudioanimdesc_t *panim, int movement )
|
|
{
|
|
if( !panim || panim->nummovements <= 0 )
|
|
return NULL;
|
|
return (mstudiomovement_t *)((byte *)m_pStudioHeader + panim->movementindex) + movement;
|
|
}
|
|
|
|
const mstudioikrule_t *pIKRule( const mstudioanimdesc_t *panim, int iRule )
|
|
{
|
|
if( !panim || panim->numikrules <= 0 )
|
|
return NULL;
|
|
return (mstudioikrule_t *)((byte *)m_pStudioHeader + panim->ikruleindex) + iRule;
|
|
}
|
|
|
|
const mstudioikchain_t *pIKChain( int chain )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && chain >= 0 && chain < phdr2->numikchains )
|
|
return (mstudioikchain_t *)((byte *)m_pStudioHeader + phdr2->ikchainindex) + chain;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const mstudioiklock_t *pIKAutoplayLock( int lock )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && lock >= 0 && lock < phdr2->numikautoplaylocks )
|
|
return (mstudioiklock_t *)((byte *)m_pStudioHeader + phdr2->ikautoplaylockindex) + lock;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const mstudioiklink_t *pIKLink( const mstudioikchain_t *pchain, int link )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && link >= 0 && link < pchain->numlinks )
|
|
return (mstudioiklink_t *)((byte *)m_pStudioHeader + pchain->linkindex) + link;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const mstudioiklock_t *pIKLock( const mstudioseqdesc_t *pseqdesc, int lock )
|
|
{
|
|
if( !pseqdesc || pseqdesc->iklockindex <= 0 )
|
|
return NULL;
|
|
return (mstudioiklock_t *)((byte *)m_pStudioHeader + pseqdesc->iklockindex) + lock;
|
|
}
|
|
|
|
const mstudioikerror_t *pCompressedError( const mstudioikrule_t *pRule )
|
|
{
|
|
if( !pRule || pRule->ikerrorindex <= 0 )
|
|
return NULL;
|
|
return (mstudioikerror_t *)((byte *)m_pStudioHeader + pRule->ikerrorindex);
|
|
}
|
|
|
|
const float *pBoneweight( const mstudioseqdesc_t *pseqdesc )
|
|
{
|
|
if( !pseqdesc || pseqdesc->weightlistindex <= 0 )
|
|
{
|
|
if( m_flCustomBoneWeight != NULL )
|
|
return m_flCustomBoneWeight;
|
|
return m_flDefaultBoneWeight;
|
|
}
|
|
return (float *)((byte *)m_pStudioHeader + pseqdesc->weightlistindex);
|
|
}
|
|
|
|
const mstudioposeparamdesc_t *pPoseParameter( int iPose )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numposeparameters > iPose )
|
|
return (mstudioposeparamdesc_t *)((byte *)m_pStudioHeader + phdr2->poseparamindex) + iPose;
|
|
|
|
return NULL; // poseparams is missed
|
|
}
|
|
|
|
// look up hitbox set by index
|
|
mstudiohitboxset_t *pHitboxSet( int i ) const
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numhitboxsets > i )
|
|
return (mstudiohitboxset_t *)((byte *)m_pStudioHeader + phdr2->hitboxsetindex) + i;
|
|
|
|
return NULL; // hitbox set is missed
|
|
}
|
|
|
|
// calls through to hitbox to determine size of specified set
|
|
inline mstudiobbox_t *pHitbox( int set, int i ) const
|
|
{
|
|
mstudiohitboxset_t const *s = pHitboxSet( set );
|
|
if( !s ) return NULL;
|
|
|
|
if( s->numhitboxes > i )
|
|
return (mstudiobbox_t *)((byte *)m_pStudioHeader + s->hitboxindex) + i;
|
|
return NULL;
|
|
}
|
|
|
|
inline mstudiobbox_t *pHitbox( int i ) const
|
|
{
|
|
if( m_pStudioHeader->numhitboxes > i )
|
|
return (mstudiobbox_t *)((byte *)m_pStudioHeader + m_pStudioHeader->hitboxindex) + i;
|
|
return NULL;
|
|
}
|
|
|
|
const char *pKeyValuesBuffer( size_t *size = NULL ) const
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
if( size ) *size = 0;
|
|
|
|
if( phdr2 && phdr2->keyvaluesize > 0 )
|
|
{
|
|
if( size ) *size = phdr2->keyvaluesize;
|
|
return (const char *)((byte *)m_pStudioHeader + phdr2->keyvalueindex);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int FindAttachment( const char *pAttachmentName )
|
|
{
|
|
mstudioattachment_t *pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex);
|
|
|
|
for( int i = 0; i < m_pStudioHeader->numattachments; i++, pattachment++ )
|
|
{
|
|
if( !Q_stricmp( pAttachmentName, pattachment->name ))
|
|
return i + 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CountPoseParameters( void )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numposeparameters > 0 )
|
|
return phdr2->numposeparameters;
|
|
return 0; // poseparams is missed
|
|
}
|
|
|
|
int GetNumIKChains( void )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numikchains > 0 )
|
|
return phdr2->numikchains;
|
|
return 0; // no IK chains
|
|
}
|
|
|
|
int GetNumIKAutoplayLocks( void )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numikautoplaylocks > 0 )
|
|
return phdr2->numikautoplaylocks;
|
|
return 0; // no IK autoplay locks
|
|
}
|
|
|
|
int GetNumHitboxSets( void )
|
|
{
|
|
studiohdr2_t *phdr2 = NULL;
|
|
|
|
if( m_pStudioHeader->studiohdr2index > 0 && m_pStudioHeader->studiohdr2index < m_pStudioHeader->length )
|
|
phdr2 = (studiohdr2_t *)((byte *)m_pStudioHeader + m_pStudioHeader->studiohdr2index);
|
|
|
|
if( phdr2 && phdr2->numhitboxsets > 0 )
|
|
return phdr2->numhitboxsets;
|
|
return 0; // no hitbox sets
|
|
}
|
|
|
|
const float flPoseKey( const mstudioseqdesc_t *pseqdesc, int iParam, int iAnim )
|
|
{
|
|
float *poseKey = (float *)((byte *)m_pStudioHeader + pseqdesc->posekeyindex);
|
|
return poseKey[iParam * pseqdesc->groupsize[0] + iAnim];
|
|
}
|
|
|
|
int iAnimBlend( const mstudioseqdesc_t *pseqdesc, int x, int y )
|
|
{
|
|
if( x >= pseqdesc->groupsize[0] )
|
|
x = pseqdesc->groupsize[0] - 1;
|
|
|
|
if( y >= pseqdesc->groupsize[1] )
|
|
y = pseqdesc->groupsize[1] - 1;
|
|
|
|
return (x + pseqdesc->groupsize[0] * y); // animations[blend]
|
|
}
|
|
|
|
bool IsBoneUsed( mstudiobone_t *pbone )
|
|
{
|
|
if( m_iBoneMask )
|
|
return (FBitSet( pbone->flags, m_iBoneMask )) ? true : false;
|
|
return true;
|
|
}
|
|
|
|
bool IsBoneUsed( int iBone )
|
|
{
|
|
mstudiobone_t *pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
|
|
|
|
if( iBone != -1 && m_iBoneMask != 0 )
|
|
return (FBitSet( pbone[iBone].flags, m_iBoneMask )) ? true : false;
|
|
return true;
|
|
}
|
|
private:
|
|
void InitBoneWeights( void ) { for( int i = 0; i < MAXSTUDIOBONES; i++ ) m_flDefaultBoneWeight[i] = 1.0f; }
|
|
void ExtractAnimValue( int frame, const mstudioanimvalue_t *panimvalue, float scale, float &v1, float &v2 );
|
|
void ExtractAnimValue( int frame, const mstudioanimvalue_t *panimvalue, float scale, float &v1 );
|
|
Vector4D CalcBoneQuaternion( int frame, float s, int flags, mstudiobone_t *pbone, mstudioboneinfo_t *pboneinfo, mstudioanim_t *panim );
|
|
Vector CalcBonePosition( int frame, float s, int flags, mstudiobone_t *pbone, mstudioanim_t *panim );
|
|
void AdjustBoneAngles( mstudiobone_t *pbone, Radian &angles1, Radian &angles2 );
|
|
void AdjustBoneOrigin( mstudiobone_t *pbone, Vector &origin );
|
|
void CalcIKError( const mstudioikerror_t *pIKError, int frame, float s, Vector &pos, Vector4D &q );
|
|
mstudioanim_t *FetchAnimation( mstudioseqdesc_t *pseqdesc, int animation );
|
|
mstudioanimdesc_t *FetchAnimDesc( mstudioseqdesc_t *pseqdesc, int animation );
|
|
void CalcAnimation( Vector pos[], Vector4D q[], mstudioseqdesc_t *seqdesc, int animation, float cycle );
|
|
void BlendBones( Vector4D q1[], Vector pos1[], mstudioseqdesc_t *pseqdesc, const Vector4D q2[], const Vector pos2[], float s );
|
|
void SlerpBones( Vector4D q1[], Vector pos1[], mstudioseqdesc_t *pseqdesc, const Vector4D q2[], const Vector pos2[], float s );
|
|
void BuildBoneChain( const matrix3x4 &root, const Vector pos[], const Vector4D q[], int iBone, matrix3x4 *pBoneToWorld, byte *pSet = NULL );
|
|
void WorldSpaceSlerp( Vector4D q1[], Vector pos1[], mstudioseqdesc_t *pseqdesc, const Vector4D q2[], const Vector pos2[], float s );
|
|
void Calc9WayBlendIndices( int i0, int i1, float s0, float s1, const mstudioseqdesc_t *pseqdesc, int *pAnimIndices, float *pWeight );
|
|
void AddSequenceLayers( CIKContext *pContext, Vector pos[], Vector4D q[], int sequence, float cycle, float flWeight );
|
|
void AddLocalLayers( CIKContext *pContext, Vector pos[], Vector4D q[], int sequence, float cycle, float flWeight );
|
|
void SolveBone( int iBone, matrix3x4 *pBoneToWorld, Vector pos[], Vector4D q[] );
|
|
bool SolveIK( const mstudioikchain_t *pikchain, Vector &targetFoot, matrix3x4 *pBoneToWorld );
|
|
bool SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, matrix3x4 *pBoneToWorld );
|
|
bool SolveIK( int iThigh, int iKnee, int iFoot, Vector &targetFoot, Vector &targetKneePos, Vector &targetKneeDir, matrix3x4 *pBoneToWorld );
|
|
void CalcPoseSingle( Vector pos[], Vector4D q[], int sequence, float cycle );
|
|
void AlignIKMatrix( matrix3x4 &mMat, const Vector &vAlignTo );
|
|
|
|
// private routines
|
|
void LocalPoseParameter( mstudioseqdesc_t *pseqdesc, int iLocalIndex, float &flSetting, int &index );
|
|
bool IKAnimError( const mstudioikrule_t *pRule, mstudioanimdesc_t *panim, float flCycle, Vector &pos, Vector4D &q, float &flWeight );
|
|
float IKTail( ikcontextikrule_t *ikRule, float flCycle );
|
|
bool IKSequenceError( int iSequence, float flCycle, int iRule, mstudioanimdesc_t *panim[4], float weight[4], ikcontextikrule_t *ikRule );
|
|
float IKRuleWeight( const mstudioikrule_t *ikRule, const mstudioanimdesc_t *panim, float flCycle, int &iFrame, float &fraq );
|
|
float IKRuleWeight( ikcontextikrule_t *ikRule, float flCycle );
|
|
bool IKShouldLatch( ikcontextikrule_t *ikRule, float flCycle );
|
|
|
|
float m_flDefaultBoneWeight[MAXSTUDIOBONES]; // compatibility issues
|
|
float *m_flCustomBoneWeight; // user boneweights
|
|
const float *m_flBoneControllers;
|
|
const float *m_flPoseParams;
|
|
int m_iBoneMask;
|
|
float m_flTime; // realtime
|
|
|
|
// intermediate matrices
|
|
matrix3x4 srcBoneToWorld[MAXSTUDIOBONES];
|
|
matrix3x4 dstBoneToWorld[MAXSTUDIOBONES];
|
|
matrix3x4 targetBoneToWorld[MAXSTUDIOBONES];
|
|
public:
|
|
// import table
|
|
virtual void debugMsg( char *szFmt, ... ) {}
|
|
virtual mstudioanim_t *GetAnimSourceData( mstudioseqdesc_t *pseqdesc );
|
|
virtual void debugLine( const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest = false, float duration = 0.0f ) {}
|
|
|
|
// export table
|
|
void InitPose( Vector pos[], Vector4D q[] );
|
|
void AccumulatePose( CIKContext *pContext, Vector pos[], Vector4D q[], int sequence, float cycle, float flWeight );
|
|
void CalcBoneAdj( Vector pos[], Vector4D q[], const byte controllers[], byte mouthopen );
|
|
void CalcBoneAdj( float adj[], const byte controllers[], byte mouthopen );
|
|
void CalcAutoplaySequences( CIKContext *pContext, Vector pos[], Vector4D q[] );
|
|
void SetStudioPointers( studiohdr_t *pStudioHdr, const float *pPoseParams ) { m_pStudioHeader = pStudioHdr; m_flPoseParams = pPoseParams; }
|
|
void SetBoneControllers( float *pNewList ) { m_flBoneControllers = pNewList; }
|
|
void SetBoneWeights( float *pNewList ) { m_flCustomBoneWeight = pNewList; }
|
|
void SetBoneMask( int iBoneMask ) { m_iBoneMask = iBoneMask; }
|
|
void UpdateRealTime( float flTime ) { m_flTime = flTime; }
|
|
void CalcDefaultPoseParameters( float flPoseParams[] );
|
|
|
|
// shared routines
|
|
float GetController( int iController, float ctlValue );
|
|
float SetController( int iController, float flValue, float &ctlValue );
|
|
float GetPoseParameter( int iParameter, float ctlValue );
|
|
float SetPoseParameter( int iParameter, float flValue, float &ctlValue );
|
|
void LocalSeqAnims( int sequence, mstudioanimdesc_t *panim[4], float *weight );
|
|
int LocalMaxFrame( int iSequence );
|
|
float LocalDuration( int sequence );
|
|
float LocalFPS( int sequence );
|
|
float LocalCPS( int sequence );
|
|
|
|
// movement routines
|
|
bool AnimPosition( mstudioanimdesc_t *panim, float flCycle, Vector &vecPos, Vector &vecAngle );
|
|
bool AnimVelocity( mstudioanimdesc_t *panim, float flCycle, Vector &vecVelocity );
|
|
bool AnimMovement( mstudioanimdesc_t *panim, float flCycleFrom, float flCycleTo, Vector &deltaPos, Vector &deltaAngle );
|
|
float FindAnimDistance( mstudioanimdesc_t *panim, float flDist );
|
|
bool SeqMovement( int sequence, float flCycleFrom, float flCycleTo, Vector &deltaPos, Vector &deltaAngles );
|
|
bool SeqVelocity( int iSequence, float flCycle, Vector &vecVelocity );
|
|
float FindSeqDistance( int sequence, float flDist );
|
|
|
|
studiohdr_t *m_pStudioHeader;
|
|
friend class CIKContext;
|
|
};
|
|
|
|
#endif//BS_DEFS_H
|