Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

548 lines
16 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Controls the pose parameters of a model
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "point_posecontroller.h"
  8. #ifndef CLIENT_DLL
  9. #include "baseanimating.h"
  10. #include "props.h"
  11. #endif
  12. // NOTE: This has to be the last file included!
  13. #include "tier0/memdbgon.h"
  14. #ifndef CLIENT_DLL
  15. //-----------------------------------------------------------------------------
  16. // SERVER CLASS
  17. //-----------------------------------------------------------------------------
  18. #define MAX_POSE_INTERPOLATION_TIME 10.0f
  19. #define MAX_POSE_CYCLE_FREQUENCY 10.0f
  20. #define MAX_POSE_FMOD_RATE 10.0f
  21. #define MAX_POSE_FMOD_AMPLITUDE 10.0f
  22. LINK_ENTITY_TO_CLASS( point_posecontroller, CPoseController );
  23. BEGIN_DATADESC( CPoseController )
  24. DEFINE_AUTO_ARRAY( m_hProps, FIELD_EHANDLE ),
  25. DEFINE_AUTO_ARRAY( m_chPoseIndex, FIELD_CHARACTER ),
  26. DEFINE_FIELD( m_bDisablePropLookup, FIELD_BOOLEAN ),
  27. DEFINE_FIELD( m_bPoseValueParity, FIELD_BOOLEAN ),
  28. // Keys
  29. DEFINE_KEYFIELD( m_iszPropName, FIELD_STRING, "PropName" ),
  30. DEFINE_KEYFIELD( m_iszPoseParameterName, FIELD_STRING, "PoseParameterName" ),
  31. DEFINE_KEYFIELD( m_fPoseValue, FIELD_FLOAT, "PoseValue" ),
  32. DEFINE_KEYFIELD( m_fInterpolationTime, FIELD_FLOAT, "InterpolationTime" ),
  33. DEFINE_KEYFIELD( m_bInterpolationWrap, FIELD_BOOLEAN, "InterpolationWrap" ),
  34. DEFINE_KEYFIELD( m_fCycleFrequency, FIELD_FLOAT, "CycleFrequency" ),
  35. DEFINE_KEYFIELD( m_nFModType, FIELD_INTEGER, "FModType" ),
  36. DEFINE_KEYFIELD( m_fFModTimeOffset, FIELD_FLOAT, "FModTimeOffset" ),
  37. DEFINE_KEYFIELD( m_fFModRate, FIELD_FLOAT, "FModRate" ),
  38. DEFINE_KEYFIELD( m_fFModAmplitude, FIELD_FLOAT, "FModAmplitude" ),
  39. // Functions
  40. DEFINE_FUNCTION( Think ),
  41. // Inputs
  42. DEFINE_INPUTFUNC( FIELD_STRING, "SetPoseParameterName", InputSetPoseParameterName ),
  43. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPoseValue", InputSetPoseValue ),
  44. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetInterpolationTime", InputSetInterpolationTime ),
  45. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetCycleFrequency", InputSetCycleFrequency ),
  46. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFModType", InputSetFModType ),
  47. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFModTimeOffset", InputSetFModTimeOffset ),
  48. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFModRate", InputSetFModRate ),
  49. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFModAmplitude", InputSetFModAmplitude ),
  50. DEFINE_INPUTFUNC( FIELD_FLOAT, "RandomizeFMod", InputRandomizeFMod ),
  51. DEFINE_INPUTFUNC( FIELD_VOID, "GetFMod", InputGetFMod ),
  52. END_DATADESC()
  53. IMPLEMENT_SERVERCLASS_ST(CPoseController, DT_PoseController)
  54. SendPropArray3( SENDINFO_ARRAY3(m_hProps), SendPropEHandle( SENDINFO_ARRAY(m_hProps) ) ),
  55. SendPropArray3( SENDINFO_ARRAY3(m_chPoseIndex), SendPropInt( SENDINFO_ARRAY(m_chPoseIndex), 5, SPROP_UNSIGNED ) ), // bits sent must be enough to represent MAXSTUDIOPOSEPARAM
  56. SendPropBool( SENDINFO(m_bPoseValueParity) ),
  57. SendPropFloat( SENDINFO(m_fPoseValue), 11, 0, 0.0f, 1.0f ),
  58. SendPropFloat( SENDINFO(m_fInterpolationTime), 11, 0, 0.0f, MAX_POSE_INTERPOLATION_TIME ),
  59. SendPropBool( SENDINFO(m_bInterpolationWrap) ),
  60. SendPropFloat( SENDINFO(m_fCycleFrequency), 11, 0, -MAX_POSE_CYCLE_FREQUENCY, MAX_POSE_CYCLE_FREQUENCY ),
  61. SendPropInt( SENDINFO(m_nFModType), 3, SPROP_UNSIGNED ),
  62. SendPropFloat( SENDINFO(m_fFModTimeOffset), 11, 0, -1.0f, 1.0f ),
  63. SendPropFloat( SENDINFO(m_fFModRate), 11, 0, -MAX_POSE_FMOD_RATE, MAX_POSE_FMOD_RATE ),
  64. SendPropFloat( SENDINFO(m_fFModAmplitude), 11, 0, 0.0f, MAX_POSE_FMOD_AMPLITUDE ),
  65. END_SEND_TABLE()
  66. void CPoseController::Spawn( void )
  67. {
  68. BaseClass::Spawn();
  69. // Talk to the client class when data changes
  70. AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  71. // Think to refresh the list of models
  72. SetThink( &CPoseController::Think );
  73. SetNextThink( gpGlobals->curtime + 1.0 );
  74. }
  75. void CPoseController::Think( void )
  76. {
  77. if ( !m_bDisablePropLookup )
  78. {
  79. // Refresh the list of models
  80. BuildPropList();
  81. SetCurrentPose( m_fPoseValue );
  82. m_bDisablePropLookup = true;
  83. SetNextThink( gpGlobals->curtime + 1.0 );
  84. }
  85. }
  86. void CPoseController::BuildPropList( void )
  87. {
  88. int iPropNum = 0;
  89. CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, m_iszPropName );
  90. while ( pEnt && iPropNum < MAX_POSE_CONTROLLED_PROPS )
  91. {
  92. CBaseAnimating *pProp = dynamic_cast<CBaseAnimating*>( pEnt );
  93. if ( pProp )
  94. {
  95. CDynamicProp *pDynamicProp = dynamic_cast<CDynamicProp*>( pProp );
  96. if ( pDynamicProp )
  97. pDynamicProp->PropSetSequence( 0 );
  98. if ( m_hProps[ iPropNum ] != pProp )
  99. {
  100. // Only set new handles (to avoid network spam)
  101. m_hProps.Set( iPropNum, pProp );
  102. }
  103. // Update the pose parameter index
  104. SetPoseIndex( iPropNum, pProp->LookupPoseParameter( m_iszPoseParameterName.ToCStr() ) );
  105. ++iPropNum;
  106. }
  107. // Get the next entity with specified targetname
  108. pEnt = gEntList.FindEntityByName( pEnt, m_iszPropName );
  109. }
  110. // Nullify the remaining handles
  111. while ( iPropNum < MAX_POSE_CONTROLLED_PROPS )
  112. {
  113. if ( m_hProps[ iPropNum ] != NULL )
  114. m_hProps.Set( iPropNum, INVALID_EHANDLE );
  115. ++iPropNum;
  116. }
  117. SetNextThink( gpGlobals->curtime + 1.0 );
  118. }
  119. void CPoseController::BuildPoseIndexList( void )
  120. {
  121. for ( int iPropNum = 0; iPropNum < MAX_POSE_CONTROLLED_PROPS; ++iPropNum )
  122. {
  123. CBaseAnimating *pProp = dynamic_cast<CBaseAnimating*>( m_hProps[ iPropNum ].Get() );
  124. if ( pProp )
  125. {
  126. // Update the pose parameter index
  127. SetPoseIndex( iPropNum, pProp->LookupPoseParameter( m_iszPoseParameterName.ToCStr() ) );
  128. }
  129. }
  130. }
  131. void CPoseController::SetPoseIndex( int i, int iValue )
  132. {
  133. if ( iValue == -1 )
  134. {
  135. // Using this as invalid lets us network less bits
  136. iValue = MAXSTUDIOPOSEPARAM;
  137. }
  138. if ( m_chPoseIndex[ i ] != iValue )
  139. {
  140. // Only set a new index (to avoid network spam)
  141. m_chPoseIndex.Set( i, iValue );
  142. }
  143. }
  144. float CPoseController::GetPoseValue( void )
  145. {
  146. return m_fPoseValue;
  147. }
  148. void CPoseController::SetProp( CBaseAnimating *pProp )
  149. {
  150. // Control a prop directly by pointer
  151. if ( m_hProps[ 0 ] != pProp )
  152. {
  153. // Only set new handles (to avoid network spam)
  154. m_hProps.Set( 0, pProp );
  155. }
  156. // Update the pose parameter index
  157. SetPoseIndex( 0, pProp->LookupPoseParameter( m_iszPoseParameterName.ToCStr() ) );
  158. // Nullify the remaining handles
  159. for ( int iPropNum = 1; iPropNum < MAX_POSE_CONTROLLED_PROPS; ++iPropNum )
  160. {
  161. if ( m_hProps[ iPropNum ] != NULL )
  162. m_hProps.Set( iPropNum, INVALID_EHANDLE );
  163. }
  164. m_bDisablePropLookup = false;
  165. }
  166. void CPoseController::SetPropName( const char *pName )
  167. {
  168. m_iszPropName = MAKE_STRING( pName );
  169. BuildPropList();
  170. }
  171. void CPoseController::SetPoseParameterName( const char *pName )
  172. {
  173. m_iszPoseParameterName = MAKE_STRING( pName );
  174. BuildPoseIndexList();
  175. }
  176. void CPoseController::SetPoseValue( float fValue )
  177. {
  178. m_fPoseValue = clamp( fValue, 0.0f, 1.0f );
  179. // Force the client to set the current pose
  180. m_bPoseValueParity = !m_bPoseValueParity;
  181. SetCurrentPose( m_fPoseValue );
  182. }
  183. void CPoseController::SetInterpolationTime( float fValue )
  184. {
  185. m_fInterpolationTime = clamp( fValue, 0.0f, MAX_POSE_INTERPOLATION_TIME );
  186. }
  187. void CPoseController::SetInterpolationWrap( bool bWrap )
  188. {
  189. m_bInterpolationWrap = bWrap;
  190. }
  191. void CPoseController::SetCycleFrequency( float fValue )
  192. {
  193. m_fCycleFrequency = clamp( fValue, -MAX_POSE_CYCLE_FREQUENCY, MAX_POSE_CYCLE_FREQUENCY );
  194. }
  195. void CPoseController::SetFModType( int nType )
  196. {
  197. if ( nType < 0 || nType >= POSECONTROLLER_FMODTYPE_TOTAL )
  198. return;
  199. m_nFModType = static_cast<PoseController_FModType_t>(nType);
  200. }
  201. void CPoseController::SetFModTimeOffset( float fValue )
  202. {
  203. m_fFModTimeOffset = clamp( fValue, -1.0f, 1.0f );
  204. }
  205. void CPoseController::SetFModRate( float fValue )
  206. {
  207. m_fFModRate = clamp( fValue, -MAX_POSE_FMOD_RATE, MAX_POSE_FMOD_RATE );
  208. }
  209. void CPoseController::SetFModAmplitude( float fValue )
  210. {
  211. m_fFModAmplitude = clamp( fValue, 0.0f, MAX_POSE_FMOD_AMPLITUDE );
  212. }
  213. void CPoseController::RandomizeFMod( float fExtremeness )
  214. {
  215. fExtremeness = clamp( fExtremeness, 0.0f, 1.0f );
  216. SetFModType( RandomInt( 1, POSECONTROLLER_FMODTYPE_TOTAL - 1 ) );
  217. SetFModTimeOffset( RandomFloat( -1.0, 1.0f ) );
  218. SetFModRate( RandomFloat( fExtremeness * -MAX_POSE_FMOD_RATE, fExtremeness * MAX_POSE_FMOD_RATE ) );
  219. SetFModAmplitude( RandomFloat( 0.0f, fExtremeness * MAX_POSE_FMOD_AMPLITUDE ) );
  220. }
  221. void CPoseController::InputSetPoseParameterName( inputdata_t &inputdata )
  222. {
  223. SetPoseParameterName( inputdata.value.String() );
  224. }
  225. void CPoseController::InputSetPoseValue( inputdata_t &inputdata )
  226. {
  227. SetPoseValue( inputdata.value.Float() );
  228. }
  229. void CPoseController::InputSetInterpolationTime( inputdata_t &inputdata )
  230. {
  231. SetInterpolationTime( inputdata.value.Float() );
  232. }
  233. void CPoseController::InputSetCycleFrequency( inputdata_t &inputdata )
  234. {
  235. SetCycleFrequency( inputdata.value.Float() );
  236. }
  237. void CPoseController::InputSetFModType( inputdata_t &inputdata )
  238. {
  239. SetFModType( inputdata.value.Int() );
  240. }
  241. void CPoseController::InputSetFModTimeOffset( inputdata_t &inputdata )
  242. {
  243. SetFModTimeOffset( inputdata.value.Float() );
  244. }
  245. void CPoseController::InputSetFModRate( inputdata_t &inputdata )
  246. {
  247. SetFModRate( inputdata.value.Float() );
  248. }
  249. void CPoseController::InputSetFModAmplitude( inputdata_t &inputdata )
  250. {
  251. SetFModAmplitude( inputdata.value.Float() );
  252. }
  253. void CPoseController::InputRandomizeFMod( inputdata_t &inputdata )
  254. {
  255. RandomizeFMod( inputdata.value.Float() );
  256. }
  257. void CPoseController::InputGetFMod( inputdata_t &inputdata )
  258. {
  259. DevMsg( "FMod values for pose controller %s\nTYPE: %i\nTIME OFFSET: %f\nRATE: %f\nAMPLITUDE: %f\n",
  260. STRING(GetEntityName()),
  261. m_nFModType.Get(),
  262. m_fFModTimeOffset.Get(),
  263. m_fFModRate.Get(),
  264. m_fFModAmplitude.Get() );
  265. }
  266. #else //#ifndef CLIENT_DLL
  267. //-----------------------------------------------------------------------------
  268. // CLIENT CLASS
  269. //-----------------------------------------------------------------------------
  270. IMPLEMENT_CLIENTCLASS_DT( C_PoseController, DT_PoseController, CPoseController )
  271. RecvPropArray3( RECVINFO_ARRAY(m_hProps), RecvPropEHandle( RECVINFO(m_hProps[0]) ) ),
  272. RecvPropArray3( RECVINFO_ARRAY(m_chPoseIndex), RecvPropInt( RECVINFO(m_chPoseIndex[0]) ) ),
  273. RecvPropBool( RECVINFO(m_bPoseValueParity) ),
  274. RecvPropFloat( RECVINFO(m_fPoseValue) ),
  275. RecvPropFloat( RECVINFO(m_fInterpolationTime) ),
  276. RecvPropBool( RECVINFO(m_bInterpolationWrap) ),
  277. RecvPropFloat( RECVINFO(m_fCycleFrequency) ),
  278. RecvPropInt( RECVINFO(m_nFModType) ),
  279. RecvPropFloat( RECVINFO(m_fFModTimeOffset) ),
  280. RecvPropFloat( RECVINFO(m_fFModRate) ),
  281. RecvPropFloat( RECVINFO(m_fFModAmplitude) ),
  282. END_RECV_TABLE()
  283. void C_PoseController::Spawn( void )
  284. {
  285. SetThink( &C_PoseController::ClientThink );
  286. SetNextClientThink( CLIENT_THINK_ALWAYS );
  287. m_fCurrentFMod = 0.0f;
  288. m_PoseTransitionValue.Init( 0.0f, 0.0f, 0.0f );
  289. BaseClass::Spawn();
  290. }
  291. void C_PoseController::OnDataChanged( DataUpdateType_t updateType )
  292. {
  293. BaseClass::OnDataChanged( updateType );
  294. if ( updateType == DATA_UPDATE_CREATED )
  295. {
  296. // Start thinking (Baseclass stops it)
  297. SetNextClientThink( CLIENT_THINK_ALWAYS );
  298. m_bOldPoseValueParity = m_bPoseValueParity;
  299. m_fCurrentPoseValue = m_fPoseValue;
  300. SetCurrentPose( m_fCurrentPoseValue );
  301. }
  302. if ( m_bOldPoseValueParity != m_bPoseValueParity )
  303. {
  304. // If the pose value was set directly set the actual pose value
  305. float fClientPoseValue = m_fCurrentPoseValue + m_PoseTransitionValue.Interp( gpGlobals->curtime );
  306. if ( fClientPoseValue < 0.0f )
  307. fClientPoseValue += 1.0f;
  308. else if ( fClientPoseValue > 1.0f )
  309. fClientPoseValue -= 1.0f;
  310. float fInterpForward = fClientPoseValue - m_fPoseValue;
  311. if ( m_bInterpolationWrap )
  312. {
  313. float fInterpBackward = ( fClientPoseValue + ( ( fClientPoseValue < 0.5f ) ? ( 1.0f ) : ( -1.0f ) ) ) - m_fPoseValue;
  314. m_PoseTransitionValue.Init( ( ( fabsf( fInterpForward ) < fabsf( fInterpBackward ) ) ? ( fInterpForward ) : ( fInterpBackward ) ), 0.0f, m_fInterpolationTime );
  315. }
  316. else
  317. {
  318. m_PoseTransitionValue.Init( fInterpForward, 0.0f, m_fInterpolationTime );
  319. }
  320. m_bOldPoseValueParity = m_bPoseValueParity;
  321. m_fCurrentPoseValue = m_fPoseValue;
  322. }
  323. }
  324. void C_PoseController::ClientThink( void )
  325. {
  326. UpdateModulation();
  327. UpdatePoseCycle( m_fCycleFrequency + m_fCurrentFMod );
  328. }
  329. void C_PoseController::UpdateModulation( void )
  330. {
  331. switch ( m_nFModType )
  332. {
  333. case POSECONTROLLER_FMODTYPE_NONE:
  334. {
  335. // No modulation
  336. m_fCurrentFMod = 0.0f;
  337. break;
  338. }
  339. case POSECONTROLLER_FMODTYPE_SINE:
  340. {
  341. float fCycleTime = m_fFModRate * ( gpGlobals->curtime + m_fFModTimeOffset );
  342. m_fCurrentFMod = m_fFModAmplitude * sinf( fCycleTime * ( 2.0f * M_PI ) );
  343. break;
  344. }
  345. case POSECONTROLLER_FMODTYPE_SQUARE:
  346. {
  347. float fCycleTime = fabsf( m_fFModRate * 2.0f * ( gpGlobals->curtime + m_fFModTimeOffset ) );
  348. // Separate the current time into integer and decimal
  349. int iIntegerPortion = static_cast<int>( fCycleTime );
  350. // Find if it's going up or down
  351. if ( ( iIntegerPortion % 2 ) == 0 )
  352. m_fCurrentFMod = m_fFModAmplitude;
  353. else
  354. m_fCurrentFMod = -m_fFModAmplitude;
  355. break;
  356. }
  357. case POSECONTROLLER_FMODTYPE_TRIANGLE:
  358. {
  359. float fCycleTime = fabsf( m_fFModRate * 4.0f * ( gpGlobals->curtime + m_fFModTimeOffset ) );
  360. // Separate the current time into integer and decimal
  361. int iIntegerPortion = static_cast<int>( fCycleTime );
  362. float fDecimalPortion = fCycleTime - static_cast<float>( iIntegerPortion );
  363. // Find if it's going up from 0, down from 1, down from 0, or up from -1
  364. switch ( iIntegerPortion % 4 )
  365. {
  366. case 0:
  367. m_fCurrentFMod = fDecimalPortion * m_fFModAmplitude;
  368. break;
  369. case 1:
  370. m_fCurrentFMod = ( 1.0f - fDecimalPortion ) * m_fFModAmplitude;
  371. break;
  372. case 2:
  373. m_fCurrentFMod = -fDecimalPortion * m_fFModAmplitude;
  374. break;
  375. case 3:
  376. m_fCurrentFMod = ( -1.0f + fDecimalPortion ) * m_fFModAmplitude;
  377. break;
  378. }
  379. break;
  380. }
  381. case POSECONTROLLER_FMODTYPE_SAWTOOTH:
  382. {
  383. float fCycleTime = fabsf( m_fFModRate * 2.0f * ( gpGlobals->curtime + m_fFModTimeOffset ) );
  384. // Separate the current time into integer and decimal
  385. int iIntegerPortion = static_cast<int>( fCycleTime );
  386. float fDecimalPortion = fCycleTime - static_cast<float>( iIntegerPortion );
  387. // Find if it's going up from 0 or up from -1
  388. if ( ( iIntegerPortion % 2 ) == 0 )
  389. m_fCurrentFMod = fDecimalPortion * m_fFModAmplitude;
  390. else
  391. m_fCurrentFMod = ( -1.0f + fDecimalPortion ) * m_fFModAmplitude;
  392. break;
  393. }
  394. case POSECONTROLLER_FMODTYPE_NOISE:
  395. {
  396. // Randomly increase or decrease by the rate
  397. if ( RandomInt( 0, 1 ) == 0 )
  398. m_fCurrentFMod += m_fFModRate * gpGlobals->frametime;
  399. else
  400. m_fCurrentFMod -= m_fFModRate * gpGlobals->frametime;
  401. m_fCurrentFMod = clamp( m_fCurrentFMod, -m_fFModAmplitude, m_fFModAmplitude );
  402. break;
  403. }
  404. }
  405. }
  406. void C_PoseController::UpdatePoseCycle( float fCycleAmount )
  407. {
  408. m_fCurrentPoseValue += fCycleAmount * gpGlobals->frametime;
  409. float fNewPoseValue = m_fCurrentPoseValue + m_PoseTransitionValue.Interp( gpGlobals->curtime );
  410. if ( fNewPoseValue < 0.0f )
  411. fNewPoseValue += 1.0f;
  412. else if ( fNewPoseValue > 1.0f )
  413. fNewPoseValue -= 1.0f;
  414. SetCurrentPose( fNewPoseValue );
  415. }
  416. #define CPoseController C_PoseController
  417. #define CBaseAnimating C_BaseAnimating
  418. #endif //#ifndef CLIENT_DLL
  419. void CPoseController::SetCurrentPose( float fCurrentPoseValue )
  420. {
  421. for ( int iPropNum = 0; iPropNum < MAX_POSE_CONTROLLED_PROPS; ++iPropNum )
  422. {
  423. // Control each model's pose parameter
  424. CBaseAnimating *pProp = dynamic_cast<CBaseAnimating*>( m_hProps[ iPropNum ].Get() );
  425. if ( pProp )
  426. {
  427. float fPoseValueMin;
  428. float fPoseValueMax;
  429. // Map to the pose parameter's range
  430. pProp->GetPoseParameterRange( m_chPoseIndex[ iPropNum ], fPoseValueMin, fPoseValueMax );
  431. pProp->SetPoseParameter( m_chPoseIndex[ iPropNum ], fPoseValueMin + fCurrentPoseValue * ( fPoseValueMax - fPoseValueMin ) );
  432. }
  433. }
  434. }