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.

586 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "SpriteTrail.h"
  8. #ifdef CLIENT_DLL
  9. #include "clientsideeffects.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "materialsystem/imesh.h"
  12. #include "mathlib/vmatrix.h"
  13. #include "view.h"
  14. #include "beamdraw.h"
  15. #include "enginesprite.h"
  16. #include "tier0/vprof.h"
  17. extern CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode );
  18. #endif // CLIENT_DLL
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // constants
  23. //-----------------------------------------------------------------------------
  24. #define SCREEN_SPACE_TRAILS 0
  25. //-----------------------------------------------------------------------------
  26. // Save/Restore
  27. //-----------------------------------------------------------------------------
  28. #if defined( CLIENT_DLL )
  29. BEGIN_SIMPLE_DATADESC( TrailPoint_t )
  30. // DEFINE_FIELD( m_vecScreenPos, FIELD_CLASSCHECK_IGNORE ) // do this or else we get a warning about multiply-defined fields
  31. #if SCREEN_SPACE_TRAILS
  32. DEFINE_FIELD( m_vecScreenPos, FIELD_VECTOR ),
  33. #else
  34. DEFINE_FIELD( m_vecScreenPos, FIELD_POSITION_VECTOR ),
  35. #endif
  36. DEFINE_FIELD( m_flDieTime, FIELD_TIME ),
  37. DEFINE_FIELD( m_flTexCoord, FIELD_FLOAT ),
  38. DEFINE_FIELD( m_flWidthVariance,FIELD_FLOAT ),
  39. END_DATADESC()
  40. #endif
  41. BEGIN_DATADESC( CSpriteTrail )
  42. DEFINE_KEYFIELD( m_flLifeTime, FIELD_FLOAT, "lifetime" ),
  43. DEFINE_KEYFIELD( m_flStartWidth, FIELD_FLOAT, "startwidth" ),
  44. DEFINE_KEYFIELD( m_flEndWidth, FIELD_FLOAT, "endwidth" ),
  45. DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "spritename" ),
  46. DEFINE_KEYFIELD( m_bAnimate, FIELD_BOOLEAN, "animate" ),
  47. DEFINE_FIELD( m_flStartWidthVariance, FIELD_FLOAT ),
  48. DEFINE_FIELD( m_flTextureRes, FIELD_FLOAT ),
  49. DEFINE_FIELD( m_flMinFadeLength, FIELD_FLOAT ),
  50. DEFINE_FIELD( m_vecSkyboxOrigin, FIELD_POSITION_VECTOR ),
  51. DEFINE_FIELD( m_flSkyboxScale, FIELD_FLOAT ),
  52. // These are client-only
  53. #if defined( CLIENT_DLL )
  54. DEFINE_EMBEDDED_AUTO_ARRAY( m_vecSteps ),
  55. DEFINE_FIELD( m_nFirstStep, FIELD_INTEGER ),
  56. DEFINE_FIELD( m_nStepCount, FIELD_INTEGER ),
  57. DEFINE_FIELD( m_flUpdateTime, FIELD_TIME ),
  58. DEFINE_FIELD( m_vecPrevSkyboxOrigin, FIELD_POSITION_VECTOR ),
  59. DEFINE_FIELD( m_flPrevSkyboxScale, FIELD_FLOAT ),
  60. DEFINE_FIELD( m_vecRenderMins, FIELD_VECTOR ),
  61. DEFINE_FIELD( m_vecRenderMaxs, FIELD_VECTOR ),
  62. #endif
  63. END_DATADESC()
  64. //-----------------------------------------------------------------------------
  65. // Networking
  66. //-----------------------------------------------------------------------------
  67. IMPLEMENT_NETWORKCLASS_ALIASED( SpriteTrail, DT_SpriteTrail );
  68. BEGIN_NETWORK_TABLE( CSpriteTrail, DT_SpriteTrail )
  69. #if !defined( CLIENT_DLL )
  70. SendPropFloat( SENDINFO(m_flLifeTime), 0, SPROP_NOSCALE ),
  71. SendPropFloat( SENDINFO(m_flStartWidth), 0, SPROP_NOSCALE ),
  72. SendPropFloat( SENDINFO(m_flEndWidth), 0, SPROP_NOSCALE ),
  73. SendPropFloat( SENDINFO(m_flStartWidthVariance), 0, SPROP_NOSCALE ),
  74. SendPropFloat( SENDINFO(m_flTextureRes), 0, SPROP_NOSCALE ),
  75. SendPropFloat( SENDINFO(m_flMinFadeLength), 0, SPROP_NOSCALE ),
  76. SendPropVector( SENDINFO(m_vecSkyboxOrigin),0, SPROP_NOSCALE ),
  77. SendPropFloat( SENDINFO(m_flSkyboxScale), 0, SPROP_NOSCALE ),
  78. #else
  79. RecvPropFloat( RECVINFO(m_flLifeTime)),
  80. RecvPropFloat( RECVINFO(m_flStartWidth)),
  81. RecvPropFloat( RECVINFO(m_flEndWidth)),
  82. RecvPropFloat( RECVINFO(m_flStartWidthVariance)),
  83. RecvPropFloat( RECVINFO(m_flTextureRes)),
  84. RecvPropFloat( RECVINFO(m_flMinFadeLength)),
  85. RecvPropVector( RECVINFO(m_vecSkyboxOrigin)),
  86. RecvPropFloat( RECVINFO(m_flSkyboxScale)),
  87. #endif
  88. END_NETWORK_TABLE()
  89. LINK_ENTITY_TO_CLASS_ALIASED( env_spritetrail, SpriteTrail );
  90. //-----------------------------------------------------------------------------
  91. // Prediction
  92. //-----------------------------------------------------------------------------
  93. BEGIN_PREDICTION_DATA( CSpriteTrail )
  94. END_PREDICTION_DATA()
  95. //-----------------------------------------------------------------------------
  96. // Constructor
  97. //-----------------------------------------------------------------------------
  98. CSpriteTrail::CSpriteTrail( void )
  99. {
  100. #ifdef CLIENT_DLL
  101. m_nFirstStep = 0;
  102. m_nStepCount = 0;
  103. #endif
  104. m_flStartWidthVariance = 0;
  105. m_vecSkyboxOrigin.Init( 0, 0, 0 );
  106. m_flSkyboxScale = 1.0f;
  107. m_flEndWidth = -1.0f;
  108. }
  109. void CSpriteTrail::Spawn( void )
  110. {
  111. #ifdef CLIENT_DLL
  112. BaseClass::Spawn();
  113. #else
  114. if ( GetModelName() != NULL_STRING )
  115. {
  116. BaseClass::Spawn();
  117. return;
  118. }
  119. SetModelName( m_iszSpriteName );
  120. BaseClass::Spawn();
  121. SetSolid( SOLID_NONE );
  122. SetMoveType( MOVETYPE_NOCLIP );
  123. SetCollisionBounds( vec3_origin, vec3_origin );
  124. TurnOn();
  125. #endif
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Sets parameters of the sprite trail
  129. //-----------------------------------------------------------------------------
  130. void CSpriteTrail::Precache( void )
  131. {
  132. BaseClass::Precache();
  133. if ( m_iszSpriteName != NULL_STRING )
  134. {
  135. PrecacheModel( STRING(m_iszSpriteName) );
  136. }
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Sets parameters of the sprite trail
  140. //-----------------------------------------------------------------------------
  141. void CSpriteTrail::SetLifeTime( float time )
  142. {
  143. m_flLifeTime = time;
  144. }
  145. void CSpriteTrail::SetStartWidth( float flStartWidth )
  146. {
  147. m_flStartWidth = flStartWidth;
  148. m_flStartWidth /= m_flSkyboxScale;
  149. }
  150. void CSpriteTrail::SetStartWidthVariance( float flStartWidthVariance )
  151. {
  152. m_flStartWidthVariance = flStartWidthVariance;
  153. m_flStartWidthVariance /= m_flSkyboxScale;
  154. }
  155. void CSpriteTrail::SetEndWidth( float flEndWidth )
  156. {
  157. m_flEndWidth = flEndWidth;
  158. m_flEndWidth /= m_flSkyboxScale;
  159. }
  160. void CSpriteTrail::SetTextureResolution( float flTexelsPerInch )
  161. {
  162. m_flTextureRes = flTexelsPerInch;
  163. m_flTextureRes *= m_flSkyboxScale;
  164. }
  165. void CSpriteTrail::SetMinFadeLength( float flMinFadeLength )
  166. {
  167. m_flMinFadeLength = flMinFadeLength;
  168. m_flMinFadeLength /= m_flSkyboxScale;
  169. }
  170. void CSpriteTrail::SetSkybox( const Vector &vecSkyboxOrigin, float flSkyboxScale )
  171. {
  172. m_flTextureRes /= m_flSkyboxScale;
  173. m_flMinFadeLength *= m_flSkyboxScale;
  174. m_flStartWidth *= m_flSkyboxScale;
  175. m_flEndWidth *= m_flSkyboxScale;
  176. m_flStartWidthVariance *= m_flSkyboxScale;
  177. m_vecSkyboxOrigin = vecSkyboxOrigin;
  178. m_flSkyboxScale = flSkyboxScale;
  179. m_flTextureRes *= m_flSkyboxScale;
  180. m_flMinFadeLength /= m_flSkyboxScale;
  181. m_flStartWidth /= m_flSkyboxScale;
  182. m_flEndWidth /= m_flSkyboxScale;
  183. m_flStartWidthVariance /= m_flSkyboxScale;
  184. if ( IsInSkybox() )
  185. {
  186. AddEFlags( EFL_IN_SKYBOX );
  187. }
  188. else
  189. {
  190. RemoveEFlags( EFL_IN_SKYBOX );
  191. }
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Is the trail in the skybox?
  195. //-----------------------------------------------------------------------------
  196. bool CSpriteTrail::IsInSkybox() const
  197. {
  198. return (m_flSkyboxScale != 1.0f) || (m_vecSkyboxOrigin != vec3_origin);
  199. }
  200. #ifdef CLIENT_DLL
  201. //-----------------------------------------------------------------------------
  202. // On data update
  203. //-----------------------------------------------------------------------------
  204. void CSpriteTrail::OnPreDataChanged( DataUpdateType_t updateType )
  205. {
  206. BaseClass::OnPreDataChanged( updateType );
  207. m_vecPrevSkyboxOrigin = m_vecSkyboxOrigin;
  208. m_flPrevSkyboxScale = m_flSkyboxScale;
  209. }
  210. void CSpriteTrail::OnDataChanged( DataUpdateType_t updateType )
  211. {
  212. BaseClass::OnDataChanged( updateType );
  213. if ( updateType == DATA_UPDATE_CREATED )
  214. {
  215. SetNextClientThink( CLIENT_THINK_ALWAYS );
  216. }
  217. else
  218. {
  219. if ((m_flPrevSkyboxScale != m_flSkyboxScale) || (m_vecPrevSkyboxOrigin != m_vecSkyboxOrigin))
  220. {
  221. ConvertSkybox();
  222. }
  223. }
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Compute position + bounding box
  227. //-----------------------------------------------------------------------------
  228. void CSpriteTrail::ClientThink()
  229. {
  230. // Update the trail + bounding box
  231. UpdateTrail();
  232. UpdateBoundingBox();
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Render bounds
  236. //-----------------------------------------------------------------------------
  237. void CSpriteTrail::GetRenderBounds( Vector& mins, Vector& maxs )
  238. {
  239. mins = m_vecRenderMins;
  240. maxs = m_vecRenderMaxs;
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Converts the trail when it changes skyboxes
  244. //-----------------------------------------------------------------------------
  245. void CSpriteTrail::ConvertSkybox()
  246. {
  247. for ( int i = 0; i < m_nStepCount; ++i )
  248. {
  249. // This makes it so that we're always drawing to the current location
  250. TrailPoint_t *pPoint = GetTrailPoint(i);
  251. VectorSubtract( pPoint->m_vecScreenPos, m_vecPrevSkyboxOrigin, pPoint->m_vecScreenPos );
  252. pPoint->m_vecScreenPos *= m_flPrevSkyboxScale / m_flSkyboxScale;
  253. VectorSubtract( pPoint->m_vecScreenPos, m_vecSkyboxOrigin, pPoint->m_vecScreenPos );
  254. pPoint->m_flWidthVariance *= m_flPrevSkyboxScale / m_flSkyboxScale;
  255. }
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Gets at the nth item in the list
  259. //-----------------------------------------------------------------------------
  260. TrailPoint_t *CSpriteTrail::GetTrailPoint( int n )
  261. {
  262. Assert( n < MAX_SPRITE_TRAIL_POINTS );
  263. COMPILE_TIME_ASSERT( (MAX_SPRITE_TRAIL_POINTS & (MAX_SPRITE_TRAIL_POINTS-1)) == 0 );
  264. int nIndex = (n + m_nFirstStep) & MAX_SPRITE_TRAIL_MASK;
  265. return &m_vecSteps[nIndex];
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Purpose:
  269. //-----------------------------------------------------------------------------
  270. void CSpriteTrail::ComputeScreenPosition( Vector *pScreenPos )
  271. {
  272. #if SCREEN_SPACE_TRAILS
  273. VMatrix viewMatrix;
  274. materials->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  275. *pScreenPos = viewMatrix * GetRenderOrigin();
  276. #else
  277. *pScreenPos = GetRenderOrigin();
  278. #endif
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Compute position + bounding box
  282. //-----------------------------------------------------------------------------
  283. void CSpriteTrail::UpdateBoundingBox( void )
  284. {
  285. Vector vecRenderOrigin = GetRenderOrigin();
  286. m_vecRenderMins = vecRenderOrigin;
  287. m_vecRenderMaxs = vecRenderOrigin;
  288. float flMaxWidth = m_flStartWidth;
  289. if (( m_flEndWidth >= 0.0f ) && ( m_flEndWidth > m_flStartWidth ))
  290. {
  291. flMaxWidth = m_flEndWidth;
  292. }
  293. Vector mins, maxs;
  294. for ( int i = 0; i < m_nStepCount; ++i )
  295. {
  296. TrailPoint_t *pPoint = GetTrailPoint(i);
  297. float flActualWidth = (flMaxWidth + pPoint->m_flWidthVariance) * 0.5f;
  298. Vector size( flActualWidth, flActualWidth, flActualWidth );
  299. VectorSubtract( pPoint->m_vecScreenPos, size, mins );
  300. VectorAdd( pPoint->m_vecScreenPos, size, maxs );
  301. VectorMin( m_vecRenderMins, mins, m_vecRenderMins );
  302. VectorMax( m_vecRenderMaxs, maxs, m_vecRenderMaxs );
  303. }
  304. m_vecRenderMins -= vecRenderOrigin;
  305. m_vecRenderMaxs -= vecRenderOrigin;
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Purpose:
  309. //-----------------------------------------------------------------------------
  310. void CSpriteTrail::UpdateTrail( void )
  311. {
  312. // Can't update too quickly
  313. if ( m_flUpdateTime > gpGlobals->curtime )
  314. return;
  315. Vector screenPos;
  316. ComputeScreenPosition( &screenPos );
  317. TrailPoint_t *pLast = m_nStepCount ? GetTrailPoint( m_nStepCount-1 ) : NULL;
  318. if ( ( pLast == NULL ) || ( pLast->m_vecScreenPos.DistToSqr( screenPos ) > 4.0f ) )
  319. {
  320. // If we're over our limit, steal the last point and put it up front
  321. if ( m_nStepCount >= MAX_SPRITE_TRAIL_POINTS )
  322. {
  323. --m_nStepCount;
  324. ++m_nFirstStep;
  325. }
  326. // Save off its screen position, not its world position
  327. TrailPoint_t *pNewPoint = GetTrailPoint( m_nStepCount );
  328. pNewPoint->m_vecScreenPos = screenPos;
  329. pNewPoint->m_flDieTime = gpGlobals->curtime + m_flLifeTime;
  330. pNewPoint->m_flWidthVariance = random->RandomFloat( -m_flStartWidthVariance, m_flStartWidthVariance );
  331. if (pLast)
  332. {
  333. pNewPoint->m_flTexCoord = pLast->m_flTexCoord + pLast->m_vecScreenPos.DistTo( screenPos ) * m_flTextureRes;
  334. }
  335. else
  336. {
  337. pNewPoint->m_flTexCoord = 0.0f;
  338. }
  339. ++m_nStepCount;
  340. }
  341. // Don't update again for a bit
  342. m_flUpdateTime = gpGlobals->curtime + ( m_flLifeTime / (float) MAX_SPRITE_TRAIL_POINTS );
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose:
  346. //-----------------------------------------------------------------------------
  347. int CSpriteTrail::DrawModel( int flags, const RenderableInstance_t &instance )
  348. {
  349. VPROF_BUDGET( "CSpriteTrail::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  350. // Must have at least one point
  351. if ( m_nStepCount < 1 )
  352. return 1;
  353. //See if we should draw
  354. if ( !IsVisible() || ( m_bReadyToDraw == false ) )
  355. return 0;
  356. CEngineSprite *pSprite = Draw_SetSpriteTexture( GetModel(), m_flFrame, GetRenderMode() );
  357. if ( pSprite == NULL )
  358. return 0;
  359. // Specify all the segments.
  360. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  361. CBeamSegDraw segDraw;
  362. segDraw.Start( pRenderContext, m_nStepCount + 1, pSprite->GetMaterial( GetRenderMode() ) );
  363. // Setup the first point, always emanating from the attachment point
  364. TrailPoint_t *pLast = GetTrailPoint( m_nStepCount-1 );
  365. TrailPoint_t currentPoint;
  366. currentPoint.m_flDieTime = gpGlobals->curtime + m_flLifeTime;
  367. ComputeScreenPosition( &currentPoint.m_vecScreenPos );
  368. currentPoint.m_flTexCoord = pLast->m_flTexCoord + currentPoint.m_vecScreenPos.DistTo(pLast->m_vecScreenPos) * m_flTextureRes;
  369. currentPoint.m_flWidthVariance = 0.0f;
  370. #if SCREEN_SPACE_TRAILS
  371. VMatrix viewMatrix;
  372. materials->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  373. viewMatrix = viewMatrix.InverseTR();
  374. #endif
  375. TrailPoint_t *pPrevPoint = NULL;
  376. float flTailAlphaDist = m_flMinFadeLength;
  377. for ( int i = 0; i <= m_nStepCount; ++i )
  378. {
  379. // This makes it so that we're always drawing to the current location
  380. TrailPoint_t *pPoint = (i != m_nStepCount) ? GetTrailPoint(i) : &currentPoint;
  381. float flLifePerc = (pPoint->m_flDieTime - gpGlobals->curtime) / m_flLifeTime;
  382. flLifePerc = clamp( flLifePerc, 0.0f, 1.0f );
  383. color24 c = GetRenderColor();
  384. BeamSeg_t curSeg;
  385. curSeg.m_color.r = c.r; curSeg.m_color.g = c.g; curSeg.m_color.b = c.b;
  386. float flAlphaFade = flLifePerc;
  387. if ( flTailAlphaDist > 0.0f )
  388. {
  389. if ( pPrevPoint )
  390. {
  391. float flDist = pPoint->m_vecScreenPos.DistTo( pPrevPoint->m_vecScreenPos );
  392. flTailAlphaDist -= flDist;
  393. }
  394. if ( flTailAlphaDist > 0.0f )
  395. {
  396. float flTailFade = Lerp( (m_flMinFadeLength - flTailAlphaDist) / m_flMinFadeLength, 0.0f, 1.0f );
  397. if ( flTailFade < flAlphaFade )
  398. {
  399. flAlphaFade = flTailFade;
  400. }
  401. }
  402. }
  403. curSeg.m_color.a = GetRenderBrightness() * flAlphaFade;
  404. #if SCREEN_SPACE_TRAILS
  405. curSeg.m_vPos = viewMatrix * pPoint->m_vecScreenPos;
  406. #else
  407. curSeg.m_vPos = pPoint->m_vecScreenPos;
  408. #endif
  409. if ( m_flEndWidth >= 0.0f )
  410. {
  411. curSeg.m_flWidth = Lerp( flLifePerc, m_flEndWidth.Get(), m_flStartWidth.Get() );
  412. }
  413. else
  414. {
  415. curSeg.m_flWidth = m_flStartWidth.Get();
  416. }
  417. curSeg.m_flWidth += pPoint->m_flWidthVariance;
  418. if ( curSeg.m_flWidth < 0.0f )
  419. {
  420. curSeg.m_flWidth = 0.0f;
  421. }
  422. curSeg.m_flTexCoord = pPoint->m_flTexCoord;
  423. segDraw.NextSeg( &curSeg );
  424. // See if we're done with this bad boy
  425. if ( pPoint->m_flDieTime <= gpGlobals->curtime )
  426. {
  427. // Push this back onto the top for use
  428. ++m_nFirstStep;
  429. --i;
  430. --m_nStepCount;
  431. }
  432. pPrevPoint = pPoint;
  433. }
  434. segDraw.End();
  435. return 1;
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose:
  439. // Output : Vector const&
  440. //-----------------------------------------------------------------------------
  441. const Vector &CSpriteTrail::GetRenderOrigin( void )
  442. {
  443. static Vector vOrigin;
  444. vOrigin = GetAbsOrigin();
  445. if ( m_hAttachedToEntity )
  446. {
  447. C_BaseEntity *ent = m_hAttachedToEntity->GetBaseEntity();
  448. if ( ent )
  449. {
  450. QAngle dummyAngles;
  451. ent->GetAttachment( m_nAttachment, vOrigin, dummyAngles );
  452. }
  453. }
  454. return vOrigin;
  455. }
  456. const QAngle &CSpriteTrail::GetRenderAngles( void )
  457. {
  458. return vec3_angle;
  459. }
  460. #endif //CLIENT_DLL
  461. #if !defined( CLIENT_DLL )
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. // Input : *pSpriteName -
  465. // &origin -
  466. // animate -
  467. // Output : CSpriteTrail
  468. //-----------------------------------------------------------------------------
  469. CSpriteTrail *CSpriteTrail::SpriteTrailCreate( const char *pSpriteName, const Vector &origin, bool animate )
  470. {
  471. CSpriteTrail *pSprite = CREATE_ENTITY( CSpriteTrail, "env_spritetrail" );
  472. pSprite->SpriteInit( pSpriteName, origin );
  473. pSprite->SetSolid( SOLID_NONE );
  474. pSprite->SetMoveType( MOVETYPE_NOCLIP );
  475. UTIL_SetSize( pSprite, vec3_origin, vec3_origin );
  476. if ( animate )
  477. {
  478. pSprite->TurnOn();
  479. }
  480. return pSprite;
  481. }
  482. #endif //CLIENT_DLL == false