diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/hl2/c_npc_hydra.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/hl2/c_npc_hydra.cpp')
| -rw-r--r-- | game/client/hl2/c_npc_hydra.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/game/client/hl2/c_npc_hydra.cpp b/game/client/hl2/c_npc_hydra.cpp new file mode 100644 index 0000000..271c775 --- /dev/null +++ b/game/client/hl2/c_npc_hydra.cpp @@ -0,0 +1,386 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "bone_setup.h" +#include "c_ai_basenpc.h" +#include "engine/ivdebugoverlay.h" +#include "tier0/vprof.h" +#include "soundinfo.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_NPC_Hydra : public C_AI_BaseNPC +{ +public: + DECLARE_CLASS( C_NPC_Hydra, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + DECLARE_INTERPOLATION(); + + C_NPC_Hydra(); + virtual ~C_NPC_Hydra(); + + // model specific + virtual void OnLatchInterpolatedVariables( int flags ); + virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual void StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + void CalcBoneChain( Vector pos[], const Vector chain[] ); + void CalcBoneAngles( const Vector pos[], Quaternion q[] ); + + virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); + + virtual void ResetLatched(); + +#define CHAIN_LINKS 32 + + bool m_bNewChain; + int m_fLatchFlags; + Vector m_vecChain[CHAIN_LINKS]; + + Vector m_vecHeadDir; + CInterpolatedVar< Vector > m_iv_vecHeadDir; + + //Vector m_vecInterpHeadDir; + + float m_flRelaxedLength; + + Vector *m_vecPos; // current animation + CInterpolatedVar< Vector > *m_iv_vecPos; + + int m_numHydraBones; + float *m_boneLength; + + float m_maxPossibleLength; + +private: + C_NPC_Hydra( const C_NPC_Hydra & ); // not defined, not accessible +}; + +IMPLEMENT_CLIENTCLASS_DT(C_NPC_Hydra, DT_NPC_Hydra, CNPC_Hydra) + RecvPropVector ( RECVINFO( m_vecChain[0] ) ), + RecvPropVector ( RECVINFO( m_vecChain[1] ) ), + RecvPropVector ( RECVINFO( m_vecChain[2] ) ), + RecvPropVector ( RECVINFO( m_vecChain[3] ) ), + RecvPropVector ( RECVINFO( m_vecChain[4] ) ), + RecvPropVector ( RECVINFO( m_vecChain[5] ) ), + RecvPropVector ( RECVINFO( m_vecChain[6] ) ), + RecvPropVector ( RECVINFO( m_vecChain[7] ) ), + RecvPropVector ( RECVINFO( m_vecChain[8] ) ), + RecvPropVector ( RECVINFO( m_vecChain[9] ) ), + RecvPropVector ( RECVINFO( m_vecChain[10] ) ), + RecvPropVector ( RECVINFO( m_vecChain[11] ) ), + RecvPropVector ( RECVINFO( m_vecChain[12] ) ), + RecvPropVector ( RECVINFO( m_vecChain[13] ) ), + RecvPropVector ( RECVINFO( m_vecChain[14] ) ), + RecvPropVector ( RECVINFO( m_vecChain[15] ) ), + RecvPropVector ( RECVINFO( m_vecChain[16] ) ), + RecvPropVector ( RECVINFO( m_vecChain[17] ) ), + RecvPropVector ( RECVINFO( m_vecChain[18] ) ), + RecvPropVector ( RECVINFO( m_vecChain[19] ) ), + RecvPropVector ( RECVINFO( m_vecChain[20] ) ), + RecvPropVector ( RECVINFO( m_vecChain[21] ) ), + RecvPropVector ( RECVINFO( m_vecChain[22] ) ), + RecvPropVector ( RECVINFO( m_vecChain[23] ) ), + RecvPropVector ( RECVINFO( m_vecChain[24] ) ), + RecvPropVector ( RECVINFO( m_vecChain[25] ) ), + RecvPropVector ( RECVINFO( m_vecChain[26] ) ), + RecvPropVector ( RECVINFO( m_vecChain[27] ) ), + RecvPropVector ( RECVINFO( m_vecChain[28] ) ), + RecvPropVector ( RECVINFO( m_vecChain[29] ) ), + RecvPropVector ( RECVINFO( m_vecChain[30] ) ), + RecvPropVector ( RECVINFO( m_vecChain[31] ) ), + RecvPropVector ( RECVINFO( m_vecHeadDir ) ), + RecvPropFloat ( RECVINFO( m_flRelaxedLength ) ), +END_RECV_TABLE() + +C_NPC_Hydra::C_NPC_Hydra() : m_iv_vecHeadDir( "C_NPC_Hydra::m_iv_vecHeadDir" ) +{ + AddVar( &m_vecHeadDir, &m_iv_vecHeadDir, LATCH_ANIMATION_VAR ); + + m_numHydraBones = 0; + m_boneLength = NULL; + m_maxPossibleLength = 1; + m_vecPos = NULL; + m_iv_vecPos = NULL; +} + + +C_NPC_Hydra::~C_NPC_Hydra() +{ + delete m_boneLength; + delete m_vecPos; + delete[] m_iv_vecPos; + m_iv_vecPos = NULL; +} + +void C_NPC_Hydra::OnLatchInterpolatedVariables( int flags ) +{ + m_bNewChain = true; + m_fLatchFlags = flags; + + BaseClass::OnLatchInterpolatedVariables( flags ); +} + +void C_NPC_Hydra::ResetLatched() +{ + for (int i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Reset(); + } + + BaseClass::ResetLatched(); +} + +bool C_NPC_Hydra::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) +{ + return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ); +} + + +void C_NPC_Hydra::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) +{ + VPROF( "C_NPC_Hydra::StandardBlendingRules" ); + + studiohdr_t *hdr = GetModelPtr(); + if ( !hdr ) + { + return; + } + + int i; + + // check for changing model memory requirements + bool bNewlyInited = false; + if (m_numHydraBones != hdr->numbones) + { + m_numHydraBones = hdr->numbones; + + // build root animation + float poseparam[MAXSTUDIOPOSEPARAM]; + for (i = 0; i < hdr->GetNumPoseParameters(); i++) + { + poseparam[i] = 0; + } + CalcPose( hdr, NULL, pos, q, 0.0f, 0.0f, poseparam, BONE_USED_BY_ANYTHING ); + + // allocate arrays + if (m_boneLength) + { + delete[] m_boneLength; + } + m_boneLength = new float [m_numHydraBones]; + + if (m_vecPos) + { + delete[] m_vecPos; + } + m_vecPos = new Vector [m_numHydraBones]; + + if (m_iv_vecPos) + { + delete m_iv_vecPos; + } + m_iv_vecPos = new CInterpolatedVar< Vector >[m_numHydraBones]; + for ( i = 0; i < m_numHydraBones; i++ ) + { + m_iv_vecPos[ i ].Setup( &m_vecPos[ i ], LATCH_SIMULATION_VAR | EXCLUDE_AUTO_LATCH | EXCLUDE_AUTO_INTERPOLATE ); + } + + // calc models bone lengths + m_maxPossibleLength = 0; + for (i = 0; i < m_numHydraBones-1; i++) + { + m_boneLength[i] = (pos[i+1] - pos[i]).Length(); + m_maxPossibleLength += m_boneLength[i]; + } + m_boneLength[i] = 0.0f; + + bNewlyInited = true; + } + + // calc new bone setup if networked. + if (m_bNewChain) + { + CalcBoneChain( m_vecPos, m_vecChain ); + for (i = 0; i < m_numHydraBones; i++) + { + // debugoverlay->AddLineOverlay( m_vecPos[i], m_vecPos[i<m_numHydraBones-1?i+1:m_numHydraBones-1], 0, 255, 0, false, 0.1 ); + m_vecPos[i] = m_vecPos[i] - GetAbsOrigin(); + + if ( m_fLatchFlags & LATCH_SIMULATION_VAR ) + { + m_iv_vecPos[i].NoteChanged( currentTime, true ); + } + } + m_bNewChain = false; + } + + // if just allocated, initialize bones + if (bNewlyInited) + { + + for (i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Reset(); + } + } + + for (i = 0; i < m_numHydraBones; i++) + { + m_iv_vecPos[i].Interpolate( currentTime ); + pos[ i ] = m_vecPos[ i ]; + } + + // calculate bone angles + CalcBoneAngles( pos, q ); + + // rotate the last bone of the hydra 90 degrees since it's oriented differently than the others + Quaternion qTmp; + AngleQuaternion( QAngle( 0, -90, 0) , qTmp ); + QuaternionMult( q[m_numHydraBones - 1], qTmp, q[m_numHydraBones - 1] ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Fits skeleton of hydra to the variable segment length "chain" array +// Adjusts overall hydra so that "m_flRelaxedLength" of texture fits over +// the actual length of the chain +//----------------------------------------------------------------------------- + +void C_NPC_Hydra::CalcBoneChain( Vector pos[], const Vector chain[] ) +{ + int i, j; + + // Find the dist chain link that's not zero length + i = CHAIN_LINKS-1; + while (i > 0) + { + if ((chain[i] - chain[i-1]).LengthSqr() > 0.0) + { + break; + } + i--; + } + + // initialize the last bone to the last bone + j = m_numHydraBones - 1; + + // clamp length + float totalLength = 0; + for (int k = i; k > 0; k--) + { + // debugoverlay->AddLineOverlay( chain[k], chain[k-1], 255, 255, 255, false, 0 ); + totalLength += (chain[k] - chain[k-1]).Length(); + } + totalLength = clamp( totalLength, 1.0, m_maxPossibleLength ); + float scale = m_flRelaxedLength / totalLength; + + // starting from the head, fit the hydra skeleton onto the chain spline + float dist = -16; + while (j >= 0 && i > 0) + { + // debugoverlay->AddLineOverlay( chain[i], chain[i-1], 255, 255, 255, false, 0 ); + float dt = (chain[i] - chain[i-1]).Length() * scale; + float dx = dt; + while (j >= 0 && dist + dt >= m_boneLength[j]) + { + float s = (dx - (dt - (m_boneLength[j] - dist))) / dx; + + if (s < 0 || s > 1.) + s = 0; + // pos[j] = chain[i] * (1 - s) + chain[i-1] * s; + Catmull_Rom_Spline( chain[(i<CHAIN_LINKS-1)?i+1:CHAIN_LINKS-1], chain[i], chain[(i>0)?i-1:0], chain[(i>1)?i-2:0], s, pos[j] ); + // debugoverlay->AddLineOverlay( pos[j], chain[i], 0, 255, 0, false, 0 ); + // debugoverlay->AddLineOverlay( pos[j], chain[i-1], 0, 255, 0, false, 0 ); + + dt = dt - (m_boneLength[j] - dist); + j--; + dist = 0; + } + dist += dt; + i--; + } + + while (j >= 0) + { + pos[j] = chain[0]; + j--; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Minimize the amount of twist between bone segments +//----------------------------------------------------------------------------- + +void C_NPC_Hydra::CalcBoneAngles( const Vector pos[], Quaternion q[] ) +{ + int i; + matrix3x4_t bonematrix; + + for (i = m_numHydraBones - 1; i >= 0; i--) + { + Vector forward; + Vector left2; + + if (i != m_numHydraBones - 1) + { + QuaternionMatrix( q[i+1], bonematrix ); + MatrixGetColumn( bonematrix, 1, left2 ); + + forward = (pos[i+1] - pos[i]) /* + (pos[i] - pos[i-1])*/; + float length = VectorNormalize( forward ); + if (length == 0.0) + { + q[i] = q[i+1]; + continue; + } + } + else + { + forward = m_vecHeadDir; + VectorNormalize( forward ); + + VectorMatrix( forward, bonematrix ); + MatrixGetColumn( bonematrix, 1, left2 ); + } + + Vector up = CrossProduct( forward, left2 ); + VectorNormalize( up ); + + Vector left = CrossProduct( up, forward ); + + MatrixSetColumn( forward, 0, bonematrix ); + MatrixSetColumn( left, 1, bonematrix ); + MatrixSetColumn( up, 2, bonematrix ); + + // MatrixQuaternion( bonematrix, q[i] ); + QAngle angles; + MatrixAngles( bonematrix, angles ); + AngleQuaternion( angles, q[i] ); + } +} + +bool C_NPC_Hydra::GetSoundSpatialization( SpatializationInfo_t& info ) +{ + bool bret = BaseClass::GetSoundSpatialization( info ); + // Default things it's audible, put it at a better spot? + if ( bret ) + { + // TODO: Note, this is where you could override the sound position and orientation and use + // an attachment points position as the sound source + // You might have to issue C_BaseAnimating::AllowBoneAccess( true, false ); to allow + // bone setup during sound spatialization if you run into asserts... + } + + return bret; +} + |