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.

1509 lines
45 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "view.h"
  9. #include "viewrender.h"
  10. #include "c_tracer.h"
  11. #include "dlight.h"
  12. #include "precache_register.h"
  13. #include "fx_sparks.h"
  14. #include "iefx.h"
  15. #include "c_te_effect_dispatch.h"
  16. #include "tier0/vprof.h"
  17. #include "fx_quad.h"
  18. #include "fx.h"
  19. #include "c_pixel_visibility.h"
  20. #include "particles_ez.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. //Precahce the effects
  24. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectSparks )
  25. #ifndef DOTA_DLL
  26. PRECACHE( MATERIAL, "effects/spark" )
  27. PRECACHE( MATERIAL, "effects/energysplash" )
  28. PRECACHE( MATERIAL, "effects/energyball" )
  29. PRECACHE( MATERIAL, "sprites/rico1" )
  30. PRECACHE( MATERIAL, "sprites/rico1_noz" )
  31. PRECACHE( MATERIAL, "sprites/blueflare1" )
  32. PRECACHE( MATERIAL, "effects/yellowflare" )
  33. PRECACHE( MATERIAL, "effects/combinemuzzle1_nocull" )
  34. PRECACHE( MATERIAL, "effects/combinemuzzle2_nocull" )
  35. PRECACHE( MATERIAL, "effects/yellowflare_noz" )
  36. #endif
  37. PRECACHE_REGISTER_END()
  38. PMaterialHandle g_Material_Spark = NULL;
  39. static ConVar fx_drawmetalspark( "fx_drawmetalspark", "1", FCVAR_DEVELOPMENTONLY, "Draw metal spark effects." );
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. // Input : &pos -
  43. // Output : Returns true on success, false on failure.
  44. //-----------------------------------------------------------------------------
  45. bool EffectOccluded( const Vector &pos, pixelvis_handle_t *queryHandle )
  46. {
  47. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  48. if ( !queryHandle )
  49. {
  50. // NOTE: This is called by networking code before the current view is set up.
  51. // so use the main view instead
  52. trace_t tr;
  53. UTIL_TraceLine( pos, MainViewOrigin(nSlot), MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr );
  54. return ( tr.fraction < 1.0f ) ? true : false;
  55. }
  56. pixelvis_queryparams_t params;
  57. params.Init(pos);
  58. return PixelVisibility_FractionVisible( params, queryHandle ) > 0.0f ? false : true;
  59. }
  60. CSimpleGlowEmitter::CSimpleGlowEmitter( const char *pDebugName, const Vector &sortOrigin, float flDeathTime )
  61. : CSimpleEmitter( pDebugName )
  62. {
  63. SetSortOrigin( sortOrigin );
  64. m_queryHandle = 0;
  65. m_wasTested = 0;
  66. m_isVisible = 0;
  67. m_startTime = gpGlobals->curtime;
  68. m_flDeathTime = flDeathTime;
  69. }
  70. CSimpleGlowEmitter *CSimpleGlowEmitter::Create( const char *pDebugName, const Vector &sortOrigin, float flDeathTime )
  71. {
  72. return new CSimpleGlowEmitter( pDebugName, sortOrigin, flDeathTime );
  73. }
  74. void CSimpleGlowEmitter::SimulateParticles( CParticleSimulateIterator *pIterator )
  75. {
  76. if ( gpGlobals->curtime > m_flDeathTime )
  77. {
  78. pIterator->RemoveAllParticles();
  79. return;
  80. }
  81. if ( !WasTestedInView(1<<0) )
  82. return;
  83. BaseClass::SimulateParticles( pIterator );
  84. }
  85. bool CSimpleGlowEmitter::WasTestedInView( unsigned char viewMask )
  86. {
  87. return (m_wasTested & viewMask) ? true : false;
  88. }
  89. bool CSimpleGlowEmitter::IsVisibleInView( unsigned char viewMask )
  90. {
  91. return (m_isVisible & viewMask) ? true : false;
  92. }
  93. void CSimpleGlowEmitter::SetTestedInView( unsigned char viewMask, bool bTested )
  94. {
  95. m_wasTested &= ~viewMask;
  96. if ( bTested )
  97. {
  98. m_wasTested |= viewMask;
  99. }
  100. }
  101. void CSimpleGlowEmitter::SetVisibleInView( unsigned char viewMask, bool bVisible )
  102. {
  103. m_isVisible &= ~viewMask;
  104. if ( bVisible )
  105. {
  106. m_isVisible |= viewMask;
  107. }
  108. }
  109. unsigned char CSimpleGlowEmitter::CurrentViewMask() const
  110. {
  111. int viewId = (int)CurrentViewID();
  112. viewId = clamp(viewId, 0, 7);
  113. return 1<<viewId;
  114. }
  115. void CSimpleGlowEmitter::RenderParticles( CParticleRenderIterator *pIterator )
  116. {
  117. unsigned char viewMask = CurrentViewMask();
  118. if ( !WasTestedInView(CurrentViewMask()) )
  119. {
  120. pixelvis_queryparams_t params;
  121. params.Init(GetSortOrigin());
  122. float visible = PixelVisibility_FractionVisible( params, &m_queryHandle );
  123. if ( visible == 0.0f )
  124. {
  125. if ( (gpGlobals->curtime - m_startTime) <= 0.1f )
  126. return;
  127. SetVisibleInView(viewMask, false);
  128. }
  129. else
  130. {
  131. SetVisibleInView(viewMask, true);
  132. }
  133. SetTestedInView(viewMask, true);
  134. }
  135. if ( !IsVisibleInView(viewMask) )
  136. return;
  137. BaseClass::RenderParticles( pIterator );
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Constructor
  141. //-----------------------------------------------------------------------------
  142. CTrailParticles::CTrailParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName )
  143. {
  144. m_fFlags = 0;
  145. m_flVelocityDampen = 0.0f;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose: Test for surrounding collision surfaces for quick collision testing for the particle system
  149. // Input : &origin - starting position
  150. // *dir - direction of movement (if NULL, will do a point emission test in four directions)
  151. // angularSpread - looseness of the spread
  152. // minSpeed - minimum speed
  153. // maxSpeed - maximum speed
  154. // gravity - particle gravity for the sytem
  155. // dampen - dampening amount on collisions
  156. // flags - extra information
  157. //-----------------------------------------------------------------------------
  158. void CTrailParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags, bool bNotCollideable )
  159. {
  160. //Take the flags
  161. if ( !bNotCollideable )
  162. {
  163. SetFlag( (flags|bitsPARTICLE_TRAIL_COLLIDE) ); //Force this if they've called this function
  164. }
  165. else
  166. {
  167. SetFlag( flags );
  168. }
  169. //See if we've specified a direction
  170. m_ParticleCollision.Setup( origin, direction, angularSpread, minSpeed, maxSpeed, gravity, dampen );
  171. }
  172. void CTrailParticles::RenderParticles( CParticleRenderIterator *pIterator )
  173. {
  174. const TrailParticle *pParticle = (const TrailParticle*)pIterator->GetFirst();
  175. while ( pParticle )
  176. {
  177. //Get our remaining time
  178. float lifePerc = 1.0f - ( pParticle->m_flLifetime / pParticle->m_flDieTime );
  179. float scale = (pParticle->m_flLength*lifePerc);
  180. if ( scale < 0.01f )
  181. scale = 0.01f;
  182. Vector start, delta;
  183. //NOTE: We need to do everything in screen space
  184. TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, start );
  185. float sortKey = start.z;
  186. Vector3DMultiply( ParticleMgr()->GetModelView(), pParticle->m_vecVelocity, delta );
  187. float color[4];
  188. float ramp = 1.0;
  189. // Fade in for the first few frames
  190. if ( pParticle->m_flLifetime <= 0.3 && m_fFlags & bitsPARTICLE_TRAIL_FADE_IN )
  191. {
  192. ramp = pParticle->m_flLifetime;
  193. }
  194. else if ( m_fFlags & bitsPARTICLE_TRAIL_FADE )
  195. {
  196. ramp = ( 1.0f - ( pParticle->m_flLifetime / pParticle->m_flDieTime ) );
  197. }
  198. color[0] = pParticle->m_color.r * ramp * (1.0f / 255.0f);
  199. color[1] = pParticle->m_color.g * ramp * (1.0f / 255.0f);
  200. color[2] = pParticle->m_color.b * ramp * (1.0f / 255.0f);
  201. color[3] = pParticle->m_color.a * ramp * (1.0f / 255.0f);
  202. float flLength = (pParticle->m_vecVelocity * scale).Length();//( delta - pos ).Length();
  203. float flWidth = ( flLength < pParticle->m_flWidth ) ? flLength : pParticle->m_flWidth;
  204. //See if we should fade
  205. Tracer_Draw( pIterator->GetParticleDraw(), start, (delta*scale), flWidth, color );
  206. pParticle = (const TrailParticle*)pIterator->GetNext( sortKey );
  207. }
  208. }
  209. void CTrailParticles::SimulateParticles( CParticleSimulateIterator *pIterator )
  210. {
  211. //Turn off collision if we're not told to do it
  212. if (( m_fFlags & bitsPARTICLE_TRAIL_COLLIDE )==false)
  213. {
  214. m_ParticleCollision.ClearActivePlanes();
  215. }
  216. TrailParticle *pParticle = (TrailParticle*)pIterator->GetFirst();
  217. while ( pParticle )
  218. {
  219. const float timeDelta = pIterator->GetTimeDelta();
  220. //Simulate the movement with collision
  221. trace_t trace;
  222. m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, NULL, timeDelta, &trace );
  223. //Laterally dampen if asked to do so
  224. if ( m_fFlags & bitsPARTICLE_TRAIL_VELOCITY_DAMPEN )
  225. {
  226. float attenuation = 1.0f - (timeDelta * m_flVelocityDampen);
  227. if ( attenuation < 0.0f )
  228. attenuation = 0.0f;
  229. //Laterally dampen
  230. pParticle->m_vecVelocity[0] *= attenuation;
  231. pParticle->m_vecVelocity[1] *= attenuation;
  232. pParticle->m_vecVelocity[2] *= attenuation;
  233. }
  234. //Should this particle die?
  235. pParticle->m_flLifetime += timeDelta;
  236. if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
  237. pIterator->RemoveParticle( pParticle );
  238. pParticle = (TrailParticle*)pIterator->GetNext();
  239. }
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose: Electric spark
  243. // Input : &pos - origin point of effect
  244. //-----------------------------------------------------------------------------
  245. #define SPARK_ELECTRIC_SPREAD 0.0f
  246. #define SPARK_ELECTRIC_MINSPEED 64.0f
  247. #define SPARK_ELECTRIC_MAXSPEED 300.0f
  248. #define SPARK_ELECTRIC_GRAVITY 800.0f
  249. #define SPARK_ELECTRIC_DAMPEN 0.3f
  250. void FX_ElectricSpark( const Vector &pos, int nMagnitude, int nTrailLength, const Vector *vecDir )
  251. {
  252. VPROF_BUDGET( "FX_ElectricSpark", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  253. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_ElectricSpark 1" );
  254. if ( !pSparkEmitter )
  255. {
  256. Assert(0);
  257. return;
  258. }
  259. if ( g_Material_Spark == NULL )
  260. {
  261. g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
  262. }
  263. //Setup our collision information
  264. pSparkEmitter->Setup( (Vector &) pos,
  265. NULL,
  266. SPARK_ELECTRIC_SPREAD,
  267. SPARK_ELECTRIC_MINSPEED,
  268. SPARK_ELECTRIC_MAXSPEED,
  269. SPARK_ELECTRIC_GRAVITY,
  270. SPARK_ELECTRIC_DAMPEN,
  271. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  272. pSparkEmitter->SetSortOrigin( pos );
  273. //
  274. // Big sparks.
  275. //
  276. Vector dir;
  277. int numSparks = nMagnitude * nMagnitude * random->RandomFloat( 2, 4 );
  278. int i;
  279. TrailParticle *pParticle;
  280. for ( i = 0; i < numSparks; i++ )
  281. {
  282. pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );
  283. if ( pParticle == NULL )
  284. return;
  285. pParticle->m_flLifetime = 0.0f;
  286. pParticle->m_flDieTime = nMagnitude * random->RandomFloat( 1.0f, 2.0f );
  287. dir.Random( -1.0f, 1.0f );
  288. dir[2] = random->RandomFloat( 0.5f, 1.0f );
  289. if ( vecDir )
  290. {
  291. dir += 2 * (*vecDir);
  292. VectorNormalize( dir );
  293. }
  294. pParticle->m_flWidth = random->RandomFloat( 2.0f, 5.0f );
  295. pParticle->m_flLength = nTrailLength * random->RandomFloat( 0.02, 0.05f );
  296. pParticle->m_vecVelocity = dir * random->RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED );
  297. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  298. }
  299. //
  300. // Little sparks
  301. //
  302. CSmartPtr<CTrailParticles> pSparkEmitter2 = CTrailParticles::Create( "FX_ElectricSpark 2" );
  303. if ( !pSparkEmitter2 )
  304. {
  305. Assert(0);
  306. return;
  307. }
  308. pSparkEmitter2->SetSortOrigin( pos );
  309. pSparkEmitter2->m_ParticleCollision.SetGravity( 400.0f );
  310. pSparkEmitter2->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  311. numSparks = nMagnitude * random->RandomInt( 16, 32 );
  312. // Dump out sparks
  313. for ( i = 0; i < numSparks; i++ )
  314. {
  315. pParticle = (TrailParticle *) pSparkEmitter2->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );
  316. if ( pParticle == NULL )
  317. return;
  318. pParticle->m_flLifetime = 0.0f;
  319. dir.Random( -1.0f, 1.0f );
  320. if ( vecDir )
  321. {
  322. dir += *vecDir;
  323. VectorNormalize( dir );
  324. }
  325. pParticle->m_flWidth = random->RandomFloat( 2.0f, 4.0f );
  326. pParticle->m_flLength = nTrailLength * random->RandomFloat( 0.02f, 0.03f );
  327. pParticle->m_flDieTime = nMagnitude * random->RandomFloat( 0.1f, 0.2f );
  328. pParticle->m_vecVelocity = dir * random->RandomFloat( 128, 256 );
  329. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  330. }
  331. //
  332. // Caps
  333. //
  334. CSmartPtr<CSimpleGlowEmitter> pSimple = CSimpleGlowEmitter::Create( "FX_ElectricSpark 3", pos, gpGlobals->curtime + 0.2 );
  335. // NOTE: None of these will render unless the effect is visible!
  336. //
  337. // Inner glow
  338. //
  339. SimpleParticle *sParticle;
  340. sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/yellowflare_noz" ), pos );
  341. if ( sParticle == NULL )
  342. return;
  343. sParticle->m_flLifetime = 0.0f;
  344. sParticle->m_flDieTime = 0.2f;
  345. sParticle->m_vecVelocity.Init();
  346. sParticle->m_uchColor[0] = 255;
  347. sParticle->m_uchColor[1] = 255;
  348. sParticle->m_uchColor[2] = 255;
  349. sParticle->m_uchStartAlpha = 255;
  350. sParticle->m_uchEndAlpha = 255;
  351. sParticle->m_uchStartSize = nMagnitude * random->RandomInt( 4, 8 );
  352. sParticle->m_uchEndSize = 0;
  353. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  354. sParticle->m_flRollDelta = 0.0f;
  355. sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/yellowflare_noz" ), pos );
  356. if ( sParticle == NULL )
  357. return;
  358. sParticle->m_flLifetime = 0.0f;
  359. sParticle->m_flDieTime = 0.2f;
  360. sParticle->m_vecVelocity.Init();
  361. float fColor = random->RandomInt( 32, 64 );
  362. sParticle->m_uchColor[0] = fColor;
  363. sParticle->m_uchColor[1] = fColor;
  364. sParticle->m_uchColor[2] = fColor;
  365. sParticle->m_uchStartAlpha = fColor;
  366. sParticle->m_uchEndAlpha = 0;
  367. sParticle->m_uchStartSize = nMagnitude * random->RandomInt( 32, 64 );
  368. sParticle->m_uchEndSize = 0;
  369. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  370. sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
  371. //
  372. // Smoke
  373. //
  374. Vector sOffs;
  375. sOffs[0] = pos[0] + random->RandomFloat( -4.0f, 4.0f );
  376. sOffs[1] = pos[1] + random->RandomFloat( -4.0f, 4.0f );
  377. sOffs[2] = pos[2];
  378. sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], sOffs );
  379. if ( sParticle == NULL )
  380. return;
  381. sParticle->m_flLifetime = 0.0f;
  382. sParticle->m_flDieTime = 1.0f;
  383. sParticle->m_vecVelocity.Init();
  384. sParticle->m_vecVelocity[2] = 16.0f;
  385. sParticle->m_vecVelocity[0] = random->RandomFloat( -16.0f, 16.0f );
  386. sParticle->m_vecVelocity[1] = random->RandomFloat( -16.0f, 16.0f );
  387. sParticle->m_uchColor[0] = 255;
  388. sParticle->m_uchColor[1] = 255;
  389. sParticle->m_uchColor[2] = 200;
  390. sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 );
  391. sParticle->m_uchEndAlpha = 0;
  392. sParticle->m_uchStartSize = random->RandomInt( 4, 8 );
  393. sParticle->m_uchEndSize = sParticle->m_uchStartSize*4.0f;
  394. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  395. sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  396. //
  397. // Dlight
  398. //
  399. /*
  400. dlight_t *dl= effects->CL_AllocDlight ( 0 );
  401. dl->origin = pos;
  402. dl->color.r = dl->color.g = dl->color.b = 250;
  403. dl->radius = random->RandomFloat(16,32);
  404. dl->die = gpGlobals->curtime + 0.001;
  405. */
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose: Sparks created by scraping metal
  409. // Input : &position - start
  410. // &normal - direction of spark travel
  411. //-----------------------------------------------------------------------------
  412. #define METAL_SCRAPE_MINSPEED 128.0f
  413. #define METAL_SCRAPE_MAXSPEED 512.0f
  414. #define METAL_SCRAPE_SPREAD 0.3f
  415. #define METAL_SCRAPE_GRAVITY 800.0f
  416. #define METAL_SCRAPE_DAMPEN 0.4f
  417. void FX_MetalScrape( Vector &position, Vector &normal )
  418. {
  419. VPROF_BUDGET( "FX_MetalScrape", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  420. Vector offset = position + ( normal * 1.0f );
  421. CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MetalScrape 1" );
  422. if ( !sparkEmitter )
  423. return;
  424. sparkEmitter->SetSortOrigin( offset );
  425. //Setup our collision information
  426. sparkEmitter->Setup( offset,
  427. &normal,
  428. METAL_SCRAPE_SPREAD,
  429. METAL_SCRAPE_MINSPEED,
  430. METAL_SCRAPE_MAXSPEED,
  431. METAL_SCRAPE_GRAVITY,
  432. METAL_SCRAPE_DAMPEN,
  433. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  434. int numSparks = random->RandomInt( 4, 8 );
  435. if ( g_Material_Spark == NULL )
  436. {
  437. g_Material_Spark = sparkEmitter->GetPMaterial( "effects/spark" );
  438. }
  439. Vector dir;
  440. TrailParticle *pParticle;
  441. float length = 0.06f;
  442. //Dump out sparks
  443. for ( int i = 0; i < numSparks; i++ )
  444. {
  445. pParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, offset );
  446. if ( pParticle == NULL )
  447. return;
  448. pParticle->m_flLifetime = 0.0f;
  449. float spreadOfs = random->RandomFloat( 0.0f, 2.0f );
  450. dir[0] = normal[0] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  451. dir[1] = normal[1] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  452. dir[2] = normal[2] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  453. pParticle->m_flWidth = random->RandomFloat( 2.0f, 5.0f );
  454. pParticle->m_flLength = random->RandomFloat( length*0.25f, length );
  455. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 2.0f );
  456. pParticle->m_vecVelocity = dir * random->RandomFloat( (METAL_SCRAPE_MINSPEED*(2.0f-spreadOfs)), (METAL_SCRAPE_MAXSPEED*(2.0f-spreadOfs)) );
  457. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  458. }
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose: Ricochet spark on metal
  462. // Input : &position - origin of effect
  463. // &normal - normal of the surface struck
  464. //-----------------------------------------------------------------------------
  465. #define METAL_SPARK_SPREAD 0.5f
  466. #define METAL_SPARK_MINSPEED 128.0f
  467. #define METAL_SPARK_MAXSPEED 512.0f
  468. #define METAL_SPARK_GRAVITY 400.0f
  469. #define METAL_SPARK_DAMPEN 0.25f
  470. void FX_MetalSpark( const Vector &position, const Vector &direction, const Vector &surfaceNormal, int iScale )
  471. {
  472. VPROF_BUDGET( "FX_MetalSpark", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  473. if ( !fx_drawmetalspark.GetBool() )
  474. return;
  475. //
  476. // Emitted particles
  477. //
  478. Vector offset = position + ( surfaceNormal * 1.0f );
  479. CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MetalSpark 1" );
  480. if ( sparkEmitter == NULL )
  481. return;
  482. //Setup our information
  483. sparkEmitter->SetSortOrigin( offset );
  484. sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  485. sparkEmitter->SetVelocityDampen( 8.0f );
  486. sparkEmitter->SetGravity( METAL_SPARK_GRAVITY );
  487. sparkEmitter->SetCollisionDamped( METAL_SPARK_DAMPEN );
  488. sparkEmitter->GetBinding().SetBBox( offset - Vector( 32, 32, 32 ), offset + Vector( 32, 32, 32 ) );
  489. int numSparks = random->RandomInt( 4, 8 ) * ( iScale * 2 );
  490. if ( g_Material_Spark == NULL )
  491. {
  492. g_Material_Spark = sparkEmitter->GetPMaterial( "effects/spark" );
  493. }
  494. TrailParticle *pParticle;
  495. Vector dir;
  496. float length = 0.1f;
  497. //Dump out sparks
  498. for ( int i = 0; i < numSparks; i++ )
  499. {
  500. pParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, offset );
  501. if ( pParticle == NULL )
  502. return;
  503. pParticle->m_flLifetime = 0.0f;
  504. if( iScale > 1 && i%3 == 0 )
  505. {
  506. // Every third spark goes flying far if we're having a big batch of sparks.
  507. pParticle->m_flDieTime = random->RandomFloat( 0.15f, 0.25f );
  508. }
  509. else
  510. {
  511. pParticle->m_flDieTime = random->RandomFloat( 0.05f, 0.1f );
  512. }
  513. float spreadOfs = random->RandomFloat( 0.0f, 2.0f );
  514. dir[0] = direction[0] + random->RandomFloat( -(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs) );
  515. dir[1] = direction[1] + random->RandomFloat( -(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs) );
  516. dir[2] = direction[2] + random->RandomFloat( -(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs) );
  517. VectorNormalize( dir );
  518. pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f );
  519. pParticle->m_flLength = random->RandomFloat( length*0.25f, length );
  520. pParticle->m_vecVelocity = dir * random->RandomFloat( (METAL_SPARK_MINSPEED*(2.0f-spreadOfs)), (METAL_SPARK_MAXSPEED*(2.0f-spreadOfs)) );
  521. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  522. }
  523. //
  524. // Impact point glow
  525. //
  526. FXQuadData_t data;
  527. data.SetMaterial( "effects/yellowflare" );
  528. data.SetColor( 1.0f, 1.0f, 1.0f );
  529. data.SetOrigin( offset );
  530. data.SetNormal( surfaceNormal );
  531. data.SetAlpha( 1.0f, 0.0f );
  532. data.SetLifeTime( 0.1f );
  533. data.SetYaw( random->RandomInt( 0, 360 ) );
  534. int scale = random->RandomInt( 24, 28 );
  535. data.SetScale( scale, 0 );
  536. FX_AddQuad( data );
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Purpose: Spark effect. Nothing but sparks.
  540. // Input : &pos - origin point of effect
  541. //-----------------------------------------------------------------------------
  542. #define SPARK_SPREAD 3.0f
  543. #define SPARK_GRAVITY 800.0f
  544. #define SPARK_DAMPEN 0.3f
  545. void FX_Sparks( const Vector &pos, int nMagnitude, int nTrailLength, const Vector &vecDir, float flWidth, float flMinSpeed, float flMaxSpeed, char *pSparkMaterial )
  546. {
  547. VPROF_BUDGET( "FX_Sparks", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  548. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_Sparks 1" );
  549. if ( !pSparkEmitter )
  550. {
  551. Assert(0);
  552. return;
  553. }
  554. PMaterialHandle hMaterial;
  555. if ( pSparkMaterial )
  556. {
  557. hMaterial = pSparkEmitter->GetPMaterial( pSparkMaterial );
  558. }
  559. else
  560. {
  561. if ( g_Material_Spark == NULL )
  562. {
  563. g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
  564. }
  565. hMaterial = g_Material_Spark;
  566. }
  567. //Setup our collision information
  568. pSparkEmitter->Setup( (Vector &) pos,
  569. NULL,
  570. SPARK_SPREAD,
  571. flMinSpeed,
  572. flMaxSpeed,
  573. SPARK_GRAVITY,
  574. SPARK_DAMPEN,
  575. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  576. pSparkEmitter->SetSortOrigin( pos );
  577. //
  578. // Big sparks.
  579. //
  580. Vector dir;
  581. int numSparks = nMagnitude * nMagnitude * random->RandomFloat( 2, 4 );
  582. int i;
  583. TrailParticle *pParticle;
  584. for ( i = 0; i < numSparks; i++ )
  585. {
  586. pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, pos );
  587. if ( pParticle == NULL )
  588. return;
  589. pParticle->m_flLifetime = 0.0f;
  590. pParticle->m_flDieTime = nMagnitude * random->RandomFloat( 1.0f, 2.0f );
  591. float spreadOfs = random->RandomFloat( 0.0f, 2.0f );
  592. dir[0] = vecDir[0] + random->RandomFloat( -(SPARK_SPREAD*spreadOfs), (SPARK_SPREAD*spreadOfs) );
  593. dir[1] = vecDir[1] + random->RandomFloat( -(SPARK_SPREAD*spreadOfs), (SPARK_SPREAD*spreadOfs) );
  594. dir[2] = vecDir[2] + random->RandomFloat( -(SPARK_SPREAD*spreadOfs), (SPARK_SPREAD*spreadOfs) );
  595. pParticle->m_vecVelocity = dir * random->RandomFloat( (flMinSpeed*(2.0f-spreadOfs)), (flMaxSpeed*(2.0f-spreadOfs)) );
  596. pParticle->m_flWidth = flWidth + random->RandomFloat( 0.0f, 0.5f );
  597. pParticle->m_flLength = nTrailLength * random->RandomFloat( 0.02, 0.05f );
  598. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  599. }
  600. //
  601. // Little sparks
  602. //
  603. CSmartPtr<CTrailParticles> pSparkEmitter2 = CTrailParticles::Create( "FX_ElectricSpark 2" );
  604. if ( !pSparkEmitter2 )
  605. {
  606. Assert(0);
  607. return;
  608. }
  609. if ( pSparkMaterial )
  610. {
  611. hMaterial = pSparkEmitter->GetPMaterial( pSparkMaterial );
  612. }
  613. else
  614. {
  615. if ( g_Material_Spark == NULL )
  616. {
  617. g_Material_Spark = pSparkEmitter2->GetPMaterial( "effects/spark" );
  618. }
  619. hMaterial = g_Material_Spark;
  620. }
  621. pSparkEmitter2->SetSortOrigin( pos );
  622. pSparkEmitter2->m_ParticleCollision.SetGravity( 400.0f );
  623. pSparkEmitter2->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  624. numSparks = nMagnitude * random->RandomInt( 4, 8 );
  625. // Dump out sparks
  626. for ( i = 0; i < numSparks; i++ )
  627. {
  628. pParticle = (TrailParticle *) pSparkEmitter2->AddParticle( sizeof(TrailParticle), hMaterial, pos );
  629. if ( pParticle == NULL )
  630. return;
  631. pParticle->m_flLifetime = 0.0f;
  632. dir.Random( -1.0f, 1.0f );
  633. dir += vecDir;
  634. VectorNormalize( dir );
  635. pParticle->m_flWidth = (flWidth * 0.25) + random->RandomFloat( 0.0f, 0.5f );
  636. pParticle->m_flLength = nTrailLength * random->RandomFloat( 0.02f, 0.03f );
  637. pParticle->m_flDieTime = nMagnitude * random->RandomFloat( 0.3f, 0.5f );
  638. pParticle->m_vecVelocity = dir * random->RandomFloat( flMinSpeed, flMaxSpeed );
  639. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  640. }
  641. }
  642. //-----------------------------------------------------------------------------
  643. // Purpose: Energy splash for plasma/beam weapon impacts
  644. // Input : &pos - origin point of effect
  645. //-----------------------------------------------------------------------------
  646. #define ENERGY_SPLASH_SPREAD 0.7f
  647. #define ENERGY_SPLASH_MINSPEED 128.0f
  648. #define ENERGY_SPLASH_MAXSPEED 160.0f
  649. #define ENERGY_SPLASH_GRAVITY 800.0f
  650. #define ENERGY_SPLASH_DAMPEN 0.3f
  651. void FX_EnergySplash( const Vector &pos, const Vector &normal, int nFlags )
  652. {
  653. VPROF_BUDGET( "FX_EnergySplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  654. Vector offset = pos + ( normal * 2.0f );
  655. // Quick flash
  656. FX_AddQuad( pos,
  657. normal,
  658. 64.0f,
  659. 0,
  660. 0.75f,
  661. 1.0f,
  662. 0.0f,
  663. 0.4f,
  664. random->RandomInt( 0, 360 ),
  665. 0,
  666. Vector( 1.0f, 1.0f, 1.0f ),
  667. 0.25f,
  668. "effects/combinemuzzle1_nocull",
  669. (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
  670. // Lingering burn
  671. FX_AddQuad( pos,
  672. normal,
  673. 16,
  674. 32,
  675. 0.75f,
  676. 1.0f,
  677. 0.0f,
  678. 0.4f,
  679. random->RandomInt( 0, 360 ),
  680. 0,
  681. Vector( 1.0f, 1.0f, 1.0f ),
  682. 0.5f,
  683. "effects/combinemuzzle2_nocull",
  684. (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
  685. SimpleParticle *sParticle;
  686. CSmartPtr<CSimpleEmitter> pEmitter;
  687. pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" );
  688. pEmitter->SetSortOrigin( pos );
  689. if ( g_Material_Spark == NULL )
  690. {
  691. g_Material_Spark = pEmitter->GetPMaterial( "effects/spark" );
  692. }
  693. // Anime ground effects
  694. for ( int j = 0; j < 8; j++ )
  695. {
  696. offset.x = random->RandomFloat( -8.0f, 8.0f );
  697. offset.y = random->RandomFloat( -8.0f, 8.0f );
  698. offset.z = random->RandomFloat( 0.0f, 4.0f );
  699. offset += pos;
  700. sParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, offset );
  701. if ( sParticle == NULL )
  702. return;
  703. sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) );
  704. sParticle->m_uchStartSize = random->RandomFloat( 2, 4 );
  705. sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.6f );
  706. sParticle->m_flLifetime = 0.0f;
  707. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  708. float alpha = 255;
  709. sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f );
  710. sParticle->m_uchColor[0] = alpha;
  711. sParticle->m_uchColor[1] = alpha;
  712. sParticle->m_uchColor[2] = alpha;
  713. sParticle->m_uchStartAlpha = alpha;
  714. sParticle->m_uchEndAlpha = 0;
  715. sParticle->m_uchEndSize = 0;
  716. }
  717. }
  718. //-----------------------------------------------------------------------------
  719. // Purpose: Micro-Explosion effect
  720. // Input : &position - origin of effect
  721. // &normal - normal of the surface struck
  722. //-----------------------------------------------------------------------------
  723. #define MICRO_EXPLOSION_MINSPEED 100.0f
  724. #define MICRO_EXPLOSION_MAXSPEED 150.0f
  725. #define MICRO_EXPLOSION_SPREAD 1.0f
  726. #define MICRO_EXPLOSION_GRAVITY 0.0f
  727. #define MICRO_EXPLOSION_DAMPEN 0.4f
  728. void FX_MicroExplosion( Vector &position, Vector &normal )
  729. {
  730. VPROF_BUDGET( "FX_MicroExplosion", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  731. Vector offset = position + ( normal * 2.0f );
  732. CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MicroExplosion 1" );
  733. if ( !sparkEmitter )
  734. return;
  735. sparkEmitter->SetSortOrigin( offset );
  736. //Setup our collision information
  737. sparkEmitter->Setup( offset,
  738. &normal,
  739. MICRO_EXPLOSION_SPREAD,
  740. MICRO_EXPLOSION_MINSPEED,
  741. MICRO_EXPLOSION_MAXSPEED,
  742. MICRO_EXPLOSION_GRAVITY,
  743. MICRO_EXPLOSION_DAMPEN,
  744. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  745. int numSparks = random->RandomInt( 8, 16 );
  746. if ( g_Material_Spark == NULL )
  747. {
  748. g_Material_Spark = sparkEmitter->GetPMaterial( "effects/spark" );
  749. }
  750. TrailParticle *pParticle;
  751. Vector dir, vOfs;
  752. float length = 0.2f;
  753. //Fast lines
  754. for ( int i = 0; i < numSparks; i++ )
  755. {
  756. pParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, offset );
  757. if ( pParticle )
  758. {
  759. pParticle->m_flLifetime = 0.0f;
  760. float ramp = ( (float) i / (float)numSparks );
  761. dir[0] = normal[0] + random->RandomFloat( -MICRO_EXPLOSION_SPREAD*ramp, MICRO_EXPLOSION_SPREAD*ramp );
  762. dir[1] = normal[1] + random->RandomFloat( -MICRO_EXPLOSION_SPREAD*ramp, MICRO_EXPLOSION_SPREAD*ramp );
  763. dir[2] = normal[2] + random->RandomFloat( -MICRO_EXPLOSION_SPREAD*ramp, MICRO_EXPLOSION_SPREAD*ramp );
  764. pParticle->m_flWidth = random->RandomFloat( 5.0f, 10.0f );
  765. pParticle->m_flLength = (length*((1.0f-ramp)*(1.0f-ramp)*0.5f));
  766. pParticle->m_flDieTime = 0.2f;
  767. pParticle->m_vecVelocity = dir * random->RandomFloat( MICRO_EXPLOSION_MINSPEED*(1.5f-ramp), MICRO_EXPLOSION_MAXSPEED*(1.5f-ramp) );
  768. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  769. }
  770. }
  771. //
  772. // Filler
  773. //
  774. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_MicroExplosion 2" );
  775. pSimple->SetSortOrigin( offset );
  776. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "sprites/rico1" ), offset );
  777. if ( sParticle )
  778. {
  779. sParticle->m_flLifetime = 0.0f;
  780. sParticle->m_flDieTime = 0.3f;
  781. sParticle->m_vecVelocity.Init();
  782. sParticle->m_uchColor[0] = 255;
  783. sParticle->m_uchColor[1] = 255;
  784. sParticle->m_uchColor[2] = 255;
  785. sParticle->m_uchStartAlpha = random->RandomInt( 128, 255 );
  786. sParticle->m_uchEndAlpha = 0;
  787. sParticle->m_uchStartSize = random->RandomInt( 12, 16 );
  788. sParticle->m_uchEndSize = sParticle->m_uchStartSize;
  789. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  790. sParticle->m_flRollDelta = 0.0f;
  791. }
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Purpose: Ugly prototype explosion effect
  795. //-----------------------------------------------------------------------------
  796. #define EXPLOSION_MINSPEED 300.0f
  797. #define EXPLOSION_MAXSPEED 300.0f
  798. #define EXPLOSION_SPREAD 0.8f
  799. #define EXPLOSION_GRAVITY 800.0f
  800. #define EXPLOSION_DAMPEN 0.4f
  801. #define EXPLOSION_FLECK_MIN_SPEED 150.0f
  802. #define EXPLOSION_FLECK_MAX_SPEED 350.0f
  803. #define EXPLOSION_FLECK_GRAVITY 800.0f
  804. #define EXPLOSION_FLECK_DAMPEN 0.3f
  805. #define EXPLOSION_FLECK_ANGULAR_SPRAY 0.8f
  806. void FX_Explosion( Vector& origin, Vector& normal, char materialType )
  807. {
  808. VPROF_BUDGET( "FX_Explosion", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  809. Vector offset = origin + ( normal * 2.0f );
  810. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_Explosion 1" );
  811. if ( !pSparkEmitter )
  812. return;
  813. // Get color data from our hit point
  814. IMaterial *pTraceMaterial;
  815. Vector diffuseColor, baseColor;
  816. pTraceMaterial = engine->TraceLineMaterialAndLighting( origin, normal * -16.0f, diffuseColor, baseColor );
  817. // Get final light value
  818. float r = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0];
  819. float g = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1];
  820. float b = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2];
  821. if ( g_Material_Spark == NULL )
  822. {
  823. g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
  824. }
  825. // Setup our collision information
  826. pSparkEmitter->Setup( offset,
  827. &normal,
  828. EXPLOSION_SPREAD,
  829. EXPLOSION_MINSPEED,
  830. EXPLOSION_MAXSPEED,
  831. EXPLOSION_GRAVITY,
  832. EXPLOSION_DAMPEN,
  833. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  834. pSparkEmitter->SetSortOrigin( offset );
  835. Vector dir;
  836. int numSparks = random->RandomInt( 8,16 );
  837. // Dump out sparks
  838. int i;
  839. for ( i = 0; i < numSparks; i++ )
  840. {
  841. TrailParticle *pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, offset );
  842. if ( pParticle == NULL )
  843. break;
  844. pParticle->m_flLifetime = 0.0f;
  845. pParticle->m_flWidth = random->RandomFloat( 5.0f, 10.0f );
  846. pParticle->m_flLength = random->RandomFloat( 0.05, 0.1f );
  847. pParticle->m_flDieTime = random->RandomFloat( 1.0f, 2.0f );
  848. dir[0] = normal[0] + random->RandomFloat( -EXPLOSION_SPREAD, EXPLOSION_SPREAD );
  849. dir[1] = normal[1] + random->RandomFloat( -EXPLOSION_SPREAD, EXPLOSION_SPREAD );
  850. dir[2] = normal[2] + random->RandomFloat( -EXPLOSION_SPREAD, EXPLOSION_SPREAD );
  851. pParticle->m_vecVelocity = dir * random->RandomFloat( EXPLOSION_MINSPEED, EXPLOSION_MAXSPEED );
  852. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  853. }
  854. // Chunks o'dirt
  855. // Only create dirt chunks on concrete/world
  856. if ( materialType == 'C' || materialType == 'W' )
  857. {
  858. CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_Explosion 10", offset, Vector(5,5,5) );
  859. if ( !fleckEmitter )
  860. return;
  861. // Setup our collision information
  862. fleckEmitter->m_ParticleCollision.Setup( offset, &normal, EXPLOSION_FLECK_ANGULAR_SPRAY, EXPLOSION_FLECK_MIN_SPEED, EXPLOSION_FLECK_MAX_SPEED, EXPLOSION_FLECK_GRAVITY, EXPLOSION_FLECK_DAMPEN );
  863. PMaterialHandle *hMaterialArray;
  864. switch ( materialType )
  865. {
  866. case 'C':
  867. case 'c':
  868. default:
  869. hMaterialArray = g_Mat_Fleck_Cement;
  870. break;
  871. }
  872. int numFlecks = random->RandomInt( 48, 64 );
  873. // Dump out flecks
  874. for ( i = 0; i < numFlecks; i++ )
  875. {
  876. FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterialArray[random->RandomInt(0,1)], offset );
  877. if ( pParticle == NULL )
  878. break;
  879. pParticle->m_flLifetime = 0.0f;
  880. pParticle->m_flDieTime = 3.0f;
  881. dir[0] = normal[0] + random->RandomFloat( -EXPLOSION_FLECK_ANGULAR_SPRAY, EXPLOSION_FLECK_ANGULAR_SPRAY );
  882. dir[1] = normal[1] + random->RandomFloat( -EXPLOSION_FLECK_ANGULAR_SPRAY, EXPLOSION_FLECK_ANGULAR_SPRAY );
  883. dir[2] = normal[2] + random->RandomFloat( -EXPLOSION_FLECK_ANGULAR_SPRAY, EXPLOSION_FLECK_ANGULAR_SPRAY );
  884. pParticle->m_uchSize = random->RandomInt( 2, 6 );
  885. pParticle->m_vecVelocity = dir * ( random->RandomFloat( EXPLOSION_FLECK_MIN_SPEED, EXPLOSION_FLECK_MAX_SPEED ) * ( 7 - pParticle->m_uchSize ) );
  886. pParticle->m_flRoll = random->RandomFloat( 0, 360 );
  887. pParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
  888. float colorRamp = random->RandomFloat( 0.75f, 1.5f );
  889. pParticle->m_uchColor[0] = MIN( 1.0f, r*colorRamp )*255.0f;
  890. pParticle->m_uchColor[1] = MIN( 1.0f, g*colorRamp )*255.0f;
  891. pParticle->m_uchColor[2] = MIN( 1.0f, b*colorRamp )*255.0f;
  892. }
  893. }
  894. // Large sphere bursts
  895. CSmartPtr<CSimpleEmitter> pSimpleEmitter = CSimpleEmitter::Create( "FX_Explosion 1" );
  896. PMaterialHandle hSphereMaterial = g_Mat_DustPuff[1];
  897. Vector vecBurstOrigin = offset + normal * 8.0;
  898. pSimpleEmitter->SetSortOrigin( vecBurstOrigin );
  899. SimpleParticle *pSphereParticle = (SimpleParticle *) pSimpleEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecBurstOrigin );
  900. if ( pSphereParticle )
  901. {
  902. pSphereParticle->m_flLifetime = 0.0f;
  903. pSphereParticle->m_flDieTime = 0.3f;
  904. pSphereParticle->m_uchStartAlpha = 150.0;
  905. pSphereParticle->m_uchEndAlpha = 64.0;
  906. pSphereParticle->m_uchStartSize = 0.0;
  907. pSphereParticle->m_uchEndSize = 255.0;
  908. pSphereParticle->m_vecVelocity = Vector(0,0,0);
  909. float colorRamp = random->RandomFloat( 0.75f, 1.5f );
  910. pSphereParticle->m_uchColor[0] = MIN( 1.0f, r*colorRamp )*255.0f;
  911. pSphereParticle->m_uchColor[1] = MIN( 1.0f, g*colorRamp )*255.0f;
  912. pSphereParticle->m_uchColor[2] = MIN( 1.0f, b*colorRamp )*255.0f;
  913. }
  914. // Throw some smoke balls out around the normal
  915. int numBalls = 12;
  916. Vector vecRight, vecForward, vecUp;
  917. QAngle vecAngles;
  918. VectorAngles( normal, vecAngles );
  919. AngleVectors( vecAngles, NULL, &vecRight, &vecUp );
  920. for ( i = 0; i < numBalls; i++ )
  921. {
  922. SimpleParticle *pParticle = (SimpleParticle *) pSimpleEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecBurstOrigin );
  923. if ( pParticle )
  924. {
  925. pParticle->m_flLifetime = 0.0f;
  926. pParticle->m_flDieTime = 0.25f;
  927. pParticle->m_uchStartAlpha = 128.0;
  928. pParticle->m_uchEndAlpha = 64.0;
  929. pParticle->m_uchStartSize = 16.0;
  930. pParticle->m_uchEndSize = 64.0;
  931. float flAngle = ((float)i * M_PI * 2) / numBalls;
  932. float x = cos( flAngle );
  933. float y = sin( flAngle );
  934. pParticle->m_vecVelocity = (vecRight*x + vecUp*y) * 1024.0;
  935. float colorRamp = random->RandomFloat( 0.75f, 1.5f );
  936. pParticle->m_uchColor[0] = MIN( 1.0f, r*colorRamp )*255.0f;
  937. pParticle->m_uchColor[1] = MIN( 1.0f, g*colorRamp )*255.0f;
  938. pParticle->m_uchColor[2] = MIN( 1.0f, b*colorRamp )*255.0f;
  939. }
  940. }
  941. // Create a couple of big, floating smoke clouds
  942. CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "FX_Explosion 2" );
  943. pSmokeEmitter->SetSortOrigin( offset );
  944. for ( i = 0; i < 2; i++ )
  945. {
  946. SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset );
  947. if ( pParticle == NULL )
  948. break;
  949. pParticle->m_flLifetime = 0.0f;
  950. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
  951. pParticle->m_uchStartSize = 64;
  952. pParticle->m_uchEndSize = 255;
  953. dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
  954. dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
  955. dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
  956. pParticle->m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
  957. pParticle->m_uchStartAlpha = 160;
  958. pParticle->m_uchEndAlpha = 0;
  959. pParticle->m_flRoll = random->RandomFloat( 180, 360 );
  960. pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
  961. float colorRamp = random->RandomFloat( 0.5f, 1.25f );
  962. pParticle->m_uchColor[0] = MIN( 1.0f, r*colorRamp )*255.0f;
  963. pParticle->m_uchColor[1] = MIN( 1.0f, g*colorRamp )*255.0f;
  964. pParticle->m_uchColor[2] = MIN( 1.0f, b*colorRamp )*255.0f;
  965. }
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose:
  969. // Input : origin -
  970. // normal -
  971. //-----------------------------------------------------------------------------
  972. void FX_ConcussiveExplosion( Vector &origin, Vector &normal )
  973. {
  974. VPROF_BUDGET( "FX_ConcussiveExplosion", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  975. Vector offset = origin + ( normal * 2.0f );
  976. Vector dir;
  977. int i;
  978. //
  979. // Smoke
  980. //
  981. CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "FX_ConcussiveExplosion 1" );
  982. pSmokeEmitter->SetSortOrigin( offset );
  983. //Quick moving sprites
  984. for ( i = 0; i < 16; i++ )
  985. {
  986. SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset );
  987. if ( pParticle == NULL )
  988. return;
  989. pParticle->m_flLifetime = 0.0f;
  990. pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
  991. pParticle->m_uchStartSize = random->RandomInt( 4, 8 );
  992. pParticle->m_uchEndSize = random->RandomInt( 32, 64 );
  993. dir[0] = random->RandomFloat( -1.0f, 1.0f );
  994. dir[1] = random->RandomFloat( -1.0f, 1.0f );
  995. dir[2] = random->RandomFloat( -1.0f, 1.0f );
  996. pParticle->m_vecVelocity = dir * random->RandomFloat( 64.0f, 128.0f );
  997. pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
  998. pParticle->m_uchEndAlpha = 0;
  999. pParticle->m_flRoll = random->RandomFloat( 180, 360 );
  1000. pParticle->m_flRollDelta = random->RandomFloat( -4, 4 );
  1001. int colorRamp = random->RandomFloat( 235, 255 );
  1002. pParticle->m_uchColor[0] = colorRamp;
  1003. pParticle->m_uchColor[1] = colorRamp;
  1004. pParticle->m_uchColor[2] = colorRamp;
  1005. }
  1006. //Slow lingering sprites
  1007. for ( i = 0; i < 2; i++ )
  1008. {
  1009. SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset );
  1010. if ( pParticle == NULL )
  1011. return;
  1012. pParticle->m_flLifetime = 0.0f;
  1013. pParticle->m_flDieTime = random->RandomFloat( 1.0f, 2.0f );
  1014. pParticle->m_uchStartSize = random->RandomInt( 32, 64 );
  1015. pParticle->m_uchEndSize = random->RandomInt( 100, 128 );
  1016. dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
  1017. dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
  1018. dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
  1019. pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f );
  1020. pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
  1021. pParticle->m_uchEndAlpha = 0;
  1022. pParticle->m_flRoll = random->RandomFloat( 180, 360 );
  1023. pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
  1024. int colorRamp = random->RandomFloat( 235, 255 );
  1025. pParticle->m_uchColor[0] = colorRamp;
  1026. pParticle->m_uchColor[1] = colorRamp;
  1027. pParticle->m_uchColor[2] = colorRamp;
  1028. }
  1029. //
  1030. // Quick sphere
  1031. //
  1032. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_ConcussiveExplosion 2" );
  1033. pSimple->SetSortOrigin( offset );
  1034. SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), pSimple->GetPMaterial( "effects/blueflare1" ), offset );
  1035. if ( pParticle )
  1036. {
  1037. pParticle->m_flLifetime = 0.0f;
  1038. pParticle->m_flDieTime = 0.1f;
  1039. pParticle->m_vecVelocity.Init();
  1040. pParticle->m_flRoll = random->RandomFloat( 180, 360 );
  1041. pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
  1042. pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 128;
  1043. pParticle->m_uchStartAlpha = 255;
  1044. pParticle->m_uchEndAlpha = 0;
  1045. pParticle->m_uchStartSize = 16;
  1046. pParticle->m_uchEndSize = 64;
  1047. }
  1048. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), pSimple->GetPMaterial( "effects/blueflare1" ), offset );
  1049. if ( pParticle )
  1050. {
  1051. pParticle->m_flLifetime = 0.0f;
  1052. pParticle->m_flDieTime = 0.2f;
  1053. pParticle->m_vecVelocity.Init();
  1054. pParticle->m_flRoll = random->RandomFloat( 180, 360 );
  1055. pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
  1056. pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 32;
  1057. pParticle->m_uchStartAlpha = 64;
  1058. pParticle->m_uchEndAlpha = 0;
  1059. pParticle->m_uchStartSize = 64;
  1060. pParticle->m_uchEndSize = 128;
  1061. }
  1062. //
  1063. // Dlight
  1064. //
  1065. dlight_t *dl= effects->CL_AllocDlight ( 0 );
  1066. dl->origin = offset;
  1067. dl->color.r = dl->color.g = dl->color.b = 64;
  1068. dl->radius = random->RandomFloat(128,256);
  1069. dl->die = gpGlobals->curtime + 0.1;
  1070. //
  1071. // Moving lines
  1072. //
  1073. TrailParticle *pTrailParticle;
  1074. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_ConcussiveExplosion 3" );
  1075. PMaterialHandle hMaterial;
  1076. int numSparks;
  1077. if ( pSparkEmitter.IsValid() )
  1078. {
  1079. hMaterial= pSparkEmitter->GetPMaterial( "effects/blueflare1" );
  1080. pSparkEmitter->SetSortOrigin( offset );
  1081. pSparkEmitter->m_ParticleCollision.SetGravity( 0.0f );
  1082. numSparks = random->RandomInt( 16, 32 );
  1083. //Dump out sparks
  1084. for ( i = 0; i < numSparks; i++ )
  1085. {
  1086. pTrailParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  1087. if ( pTrailParticle == NULL )
  1088. return;
  1089. pTrailParticle->m_flLifetime = 0.0f;
  1090. dir.Random( -1.0f, 1.0f );
  1091. pTrailParticle->m_flWidth = random->RandomFloat( 1.0f, 2.0f );
  1092. pTrailParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
  1093. pTrailParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.2f );
  1094. pTrailParticle->m_vecVelocity = dir * random->RandomFloat( 800, 1000 );
  1095. float colorRamp = random->RandomFloat( 0.75f, 1.0f );
  1096. FloatToColor32( pTrailParticle->m_color, colorRamp, colorRamp, 1.0f, 1.0f );
  1097. }
  1098. }
  1099. //Moving particles
  1100. CSmartPtr<CTrailParticles> pCollisionEmitter = CTrailParticles::Create( "FX_ConcussiveExplosion 4" );
  1101. if ( pCollisionEmitter.IsValid() )
  1102. {
  1103. //Setup our collision information
  1104. pCollisionEmitter->Setup( (Vector &) offset,
  1105. NULL,
  1106. SPARK_ELECTRIC_SPREAD,
  1107. SPARK_ELECTRIC_MINSPEED*6,
  1108. SPARK_ELECTRIC_MAXSPEED*6,
  1109. -400,
  1110. SPARK_ELECTRIC_DAMPEN,
  1111. bitsPARTICLE_TRAIL_FADE );
  1112. pCollisionEmitter->SetSortOrigin( offset );
  1113. numSparks = random->RandomInt( 8, 16 );
  1114. hMaterial = pCollisionEmitter->GetPMaterial( "effects/blueflare1" );
  1115. //Dump out sparks
  1116. for ( i = 0; i < numSparks; i++ )
  1117. {
  1118. pTrailParticle = (TrailParticle *) pCollisionEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  1119. if ( pTrailParticle == NULL )
  1120. return;
  1121. pTrailParticle->m_flLifetime = 0.0f;
  1122. dir.Random( -1.0f, 1.0f );
  1123. dir[2] = random->RandomFloat( 0.0f, 0.75f );
  1124. pTrailParticle->m_flWidth = random->RandomFloat( 1.0f, 2.0f );
  1125. pTrailParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
  1126. pTrailParticle->m_flDieTime = random->RandomFloat( 0.2f, 1.0f );
  1127. pTrailParticle->m_vecVelocity = dir * random->RandomFloat( 128, 512 );
  1128. float colorRamp = random->RandomFloat( 0.75f, 1.0f );
  1129. FloatToColor32( pTrailParticle->m_color, colorRamp, colorRamp, 1.0f, 1.0f );
  1130. }
  1131. }
  1132. }
  1133. void FX_SparkFan( Vector &position, Vector &normal )
  1134. {
  1135. Vector offset = position + ( normal * 1.0f );
  1136. CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MetalScrape 1" );
  1137. if ( !sparkEmitter )
  1138. return;
  1139. sparkEmitter->SetSortOrigin( offset );
  1140. //Setup our collision information
  1141. sparkEmitter->Setup( offset,
  1142. &normal,
  1143. METAL_SCRAPE_SPREAD,
  1144. METAL_SCRAPE_MINSPEED,
  1145. METAL_SCRAPE_MAXSPEED,
  1146. METAL_SCRAPE_GRAVITY,
  1147. METAL_SCRAPE_DAMPEN,
  1148. bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  1149. if ( g_Material_Spark == NULL )
  1150. {
  1151. g_Material_Spark = sparkEmitter->GetPMaterial( "effects/spark" );
  1152. }
  1153. TrailParticle *pParticle;
  1154. Vector dir;
  1155. float length = 0.06f;
  1156. //Dump out sparks
  1157. for ( int i = 0; i < 35; i++ )
  1158. {
  1159. pParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, offset );
  1160. if ( pParticle == NULL )
  1161. return;
  1162. pParticle->m_flLifetime = 0.0f;
  1163. float spreadOfs = random->RandomFloat( 0.0f, 2.0f );
  1164. dir[0] = normal[0] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  1165. dir[1] = normal[1] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  1166. dir[2] = normal[2] + random->RandomFloat( -(METAL_SCRAPE_SPREAD*spreadOfs), (METAL_SCRAPE_SPREAD*spreadOfs) );
  1167. pParticle->m_flWidth = random->RandomFloat( 2.0f, 5.0f );
  1168. pParticle->m_flLength = random->RandomFloat( length*0.25f, length );
  1169. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 2.0f );
  1170. pParticle->m_vecVelocity = dir * random->RandomFloat( (METAL_SCRAPE_MINSPEED*(2.0f-spreadOfs)), (METAL_SCRAPE_MAXSPEED*(2.0f-spreadOfs)) );
  1171. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  1172. }
  1173. }
  1174. void ManhackSparkCallback( const CEffectData & data )
  1175. {
  1176. Vector vecNormal;
  1177. Vector vecPosition;
  1178. QAngle angles;
  1179. vecPosition = data.m_vOrigin;
  1180. vecNormal = data.m_vNormal;
  1181. angles = data.m_vAngles;
  1182. FX_SparkFan( vecPosition, vecNormal );
  1183. }
  1184. DECLARE_CLIENT_EFFECT( ManhackSparks, ManhackSparkCallback );