Paranoia2/game_shared/bs_defs.h
2020-08-31 19:50:41 +03:00

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