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_barnacle.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_barnacle.cpp')
| -rw-r--r-- | game/client/hl2/c_barnacle.cpp | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/game/client/hl2/c_barnacle.cpp b/game/client/hl2/c_barnacle.cpp new file mode 100644 index 0000000..344ac0e --- /dev/null +++ b/game/client/hl2/c_barnacle.cpp @@ -0,0 +1,313 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "c_ai_basenpc.h" +#include "engine/ivmodelinfo.h" +#include "rope_physics.h" +#include "materialsystem/imaterialsystem.h" +#include "fx_line.h" +#include "engine/ivdebugoverlay.h" +#include "bone_setup.h" +#include "model_types.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define BARNACLE_TONGUE_POINTS 7 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_NPC_Barnacle : public C_AI_BaseNPC +{ +public: + + DECLARE_CLASS( C_NPC_Barnacle, C_AI_BaseNPC ); + DECLARE_CLIENTCLASS(); + + C_NPC_Barnacle( void ); + + virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs ) + { + BaseClass::GetRenderBounds( theMins, theMaxs ); + + // Extend our bounding box downwards the length of the tongue + theMins -= Vector( 0, 0, m_flAltitude ); + } + + // Purpose: Initialize absmin & absmax to the appropriate box + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) + { + // Extend our bounding box downwards the length of the tongue + CollisionProp()->WorldSpaceAABB( pVecWorldMins, pVecWorldMaxs ); + + // We really care about the tongue tip. The altitude is not really relevant. + VectorMin( *pVecWorldMins, m_vecTip, *pVecWorldMins ); + VectorMax( *pVecWorldMaxs, m_vecTip, *pVecWorldMaxs ); + +// pVecWorldMins->z -= m_flAltitude; + } + + void OnDataChanged( DataUpdateType_t updateType ); + void InitTonguePhysics( void ); + void ClientThink( void ); + void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + + void SetVecTip( const float *pPosition ); + void SetAltitude( float flAltitude ); + + // Purpose: + void ComputeVisualTipPoint( Vector *pTip ); + +protected: + Vector m_vecTipPrevious; + Vector m_vecRoot; + Vector m_vecTip; + Vector m_vecTipDrawOffset; + +private: + // Tongue points + float m_flAltitude; + Vector m_vecTonguePoints[BARNACLE_TONGUE_POINTS]; + CRopePhysics<BARNACLE_TONGUE_POINTS> m_TonguePhysics; + + // Tongue physics delegate + class CBarnaclePhysicsDelegate : public CSimplePhysics::IHelper + { + public: + virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ); + virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ); + + C_NPC_Barnacle *m_pBarnacle; + }; + friend class CBarnaclePhysicsDelegate; + CBarnaclePhysicsDelegate m_PhysicsDelegate; + +private: + C_NPC_Barnacle( const C_NPC_Barnacle & ); // not defined, not accessible +}; + +static void RecvProxy_VecTip( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + ((C_NPC_Barnacle*)pStruct)->SetVecTip( pData->m_Value.m_Vector ); +} + +IMPLEMENT_CLIENTCLASS_DT( C_NPC_Barnacle, DT_Barnacle, CNPC_Barnacle ) + RecvPropFloat( RECVINFO( m_flAltitude ) ), + RecvPropVector( RECVINFO( m_vecRoot ) ), + RecvPropVector( RECVINFO( m_vecTip ), 0, RecvProxy_VecTip ), + RecvPropVector( RECVINFO( m_vecTipDrawOffset ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_NPC_Barnacle::C_NPC_Barnacle( void ) +{ + m_PhysicsDelegate.m_pBarnacle = this; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + InitTonguePhysics(); + + // We want to think every frame. + SetNextClientThink( CLIENT_THINK_ALWAYS ); + return; + } +} + + +//----------------------------------------------------------------------------- +// Sets the tongue altitude +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::SetAltitude( float flAltitude ) +{ + m_flAltitude = flAltitude; +} + +void C_NPC_Barnacle::SetVecTip( const float *pPosition ) +{ + Vector vecNewTip; + vecNewTip.Init( pPosition[0], pPosition[1], pPosition[2] ); + if ( vecNewTip != m_vecTip ) + { + m_vecTip = vecNewTip; + CollisionProp()->MarkSurroundingBoundsDirty(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::InitTonguePhysics( void ) +{ + // Init tongue spline + // First point is at the top + m_TonguePhysics.SetupSimulation( m_flAltitude / (BARNACLE_TONGUE_POINTS-1), &m_PhysicsDelegate ); + m_TonguePhysics.Restart(); + + // Initialize the positions of the nodes. + m_TonguePhysics.GetFirstNode()->m_vPos = m_vecRoot; + m_TonguePhysics.GetFirstNode()->m_vPrevPos = m_TonguePhysics.GetFirstNode()->m_vPos; + float flAltitude = m_flAltitude; + for( int i = 1; i < m_TonguePhysics.NumNodes(); i++ ) + { + flAltitude *= 0.5; + CSimplePhysics::CNode *pNode = m_TonguePhysics.GetNode( i ); + pNode->m_vPos = m_TonguePhysics.GetNode(i-1)->m_vPos - Vector(0,0,flAltitude); + pNode->m_vPrevPos = pNode->m_vPos; + + // Set the length of the node's spring + //m_TonguePhysics.ResetNodeSpringLength( i-1, flAltitude ); + } + + m_vecTipPrevious = m_vecTip; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::ClientThink( void ) +{ + m_TonguePhysics.Simulate( gpGlobals->frametime ); + + // Set the spring's length to that of the tongue's extension + m_TonguePhysics.ResetSpringLength( m_flAltitude / (BARNACLE_TONGUE_POINTS-1) ); + + // Necessary because ComputeVisualTipPoint depends on m_vecTipPrevious + Vector vecTemp; + ComputeVisualTipPoint( &vecTemp ); + m_vecTipPrevious = vecTemp; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) +{ + BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); + + if ( !hdr ) + return; + + int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" ); + + Vector vecPrevRight; + GetVectors( NULL, &vecPrevRight, NULL ); + + Vector vecPrev = pos[Studio_BoneIndexByName( hdr, "Barnacle.base" )]; + Vector vecCurr = vec3_origin; + Vector vecForward; + for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ ) + { + // We double up the bones at the last node. + if ( i == BARNACLE_TONGUE_POINTS ) + { + vecCurr = m_TonguePhysics.GetLastNode()->m_vPos; + } + else + { + vecCurr = m_TonguePhysics.GetNode(i)->m_vPos; + } + + //debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 ); + + // Fill out the positions in local space + VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] ); + vecCurr = pos[firstBone+i]; + + // Disallow twist in the tongue visually + // Forward vector has to follow the tongue, right + up have to minimize twist from + // the previous bone + + // Fill out the angles + if ( i != BARNACLE_TONGUE_POINTS ) + { + vecForward = (vecCurr - vecPrev); + if ( VectorNormalize( vecForward ) < 1e-3 ) + { + vecForward.Init( 0, 0, 1 ); + } + } + + // Project the previous vecRight into a plane perpendicular to vecForward + // that's the vector closest to what we want... + Vector vecRight, vecUp; + VectorMA( vecPrevRight, -DotProduct( vecPrevRight, vecForward ), vecForward, vecRight ); + VectorNormalize( vecRight ); + CrossProduct( vecForward, vecRight, vecUp ); + + BasisToQuaternion( vecForward, vecRight, vecUp, q[firstBone+i] ); + + vecPrev = vecCurr; + vecPrevRight = vecRight; + } +} + +//=============================================================================================================================== +// BARNACLE TONGUE PHYSICS +//=============================================================================================================================== +#define TONGUE_GRAVITY 0, 0, -1000 +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::CBarnaclePhysicsDelegate::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel ) +{ + // Gravity. + pAccel->Init( TONGUE_GRAVITY ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +#define TIP_SNAP_FACTOR 200 +// Todo: this really ought to be SIMD. +void C_NPC_Barnacle::ComputeVisualTipPoint( Vector *pTip ) +{ + float flTipMove = TIP_SNAP_FACTOR * gpGlobals->frametime; + Vector tipIdeal; + VectorAdd(m_vecTip, m_vecTipDrawOffset, tipIdeal); + if ( tipIdeal.DistToSqr( m_vecTipPrevious ) > (flTipMove * flTipMove) ) + { + // Inch the visual tip toward the actual tip + VectorSubtract( tipIdeal, m_vecTipPrevious, *pTip ); + VectorNormalize( *pTip ); + *pTip *= flTipMove; + *pTip += m_vecTipPrevious; + } + else + { + *pTip = tipIdeal; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_NPC_Barnacle::CBarnaclePhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes ) +{ + // Startpoint always stays at the root + pNodes[0].m_vPos = m_pBarnacle->m_vecRoot; + + // Endpoint always stays at the tip + m_pBarnacle->ComputeVisualTipPoint( &pNodes[nNodes-1].m_vPos ); +} |