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.

1527 lines
43 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "beamdraw.h"
  9. #include "enginesprite.h"
  10. #include "iviewrender_beams.h"
  11. #include "view.h"
  12. #include "iviewrender.h"
  13. #include "engine/ivmodelinfo.h"
  14. #include "fx_line.h"
  15. #include "materialsystem/imaterialvar.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. extern ConVar r_drawsprites;
  19. extern ConVar r_DrawBeams;
  20. static IMaterial *g_pBeamWireframeMaterial;
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Retrieve sprite object and set it up for rendering
  23. // Input : *pSpriteModel -
  24. // frame -
  25. // rendermode -
  26. // Output : CEngineSprite
  27. //-----------------------------------------------------------------------------
  28. CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode )
  29. {
  30. CEngineSprite *psprite;
  31. IMaterial *material;
  32. psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( pSpriteModel );
  33. Assert( psprite );
  34. material = psprite->GetMaterial( (RenderMode_t)rendermode, frame );
  35. if( !material )
  36. return NULL;
  37. CMatRenderContextPtr pRenderContext( materials );
  38. if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 )
  39. {
  40. if ( !g_pBeamWireframeMaterial )
  41. g_pBeamWireframeMaterial = materials->FindMaterial( "debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER );
  42. pRenderContext->Bind( g_pBeamWireframeMaterial, NULL );
  43. return psprite;
  44. }
  45. pRenderContext->Bind( material );
  46. return psprite;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. // Input : pMaterial -
  51. // source -
  52. // color -
  53. //-----------------------------------------------------------------------------
  54. void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale )
  55. {
  56. static unsigned int nHDRColorScaleCache = 0;
  57. Vector point, screen;
  58. if( pMaterial )
  59. {
  60. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  61. if( pHDRColorScaleVar )
  62. {
  63. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  64. }
  65. }
  66. CMatRenderContextPtr pRenderContext( materials );
  67. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  68. CMeshBuilder meshBuilder;
  69. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  70. // Transform source into screen space
  71. ScreenTransform( source, screen );
  72. meshBuilder.Color3fv (color);
  73. meshBuilder.TexCoord2f (0, 0, 1);
  74. VectorMA (source, -scale, CurrentViewUp(), point);
  75. VectorMA (point, -scale, CurrentViewRight(), point);
  76. meshBuilder.Position3fv (point.Base());
  77. meshBuilder.AdvanceVertex();
  78. meshBuilder.Color3fv (color);
  79. meshBuilder.TexCoord2f (0, 0, 0);
  80. VectorMA (source, scale, CurrentViewUp(), point);
  81. VectorMA (point, -scale, CurrentViewRight(), point);
  82. meshBuilder.Position3fv (point.Base());
  83. meshBuilder.AdvanceVertex();
  84. meshBuilder.Color3fv (color);
  85. meshBuilder.TexCoord2f (0, 1, 0);
  86. VectorMA (source, scale, CurrentViewUp(), point);
  87. VectorMA (point, scale, CurrentViewRight(), point);
  88. meshBuilder.Position3fv (point.Base());
  89. meshBuilder.AdvanceVertex();
  90. meshBuilder.Color3fv (color);
  91. meshBuilder.TexCoord2f (0, 1, 1);
  92. VectorMA (source, -scale, CurrentViewUp(), point);
  93. VectorMA (point, scale, CurrentViewRight(), point);
  94. meshBuilder.Position3fv (point.Base());
  95. meshBuilder.AdvanceVertex();
  96. meshBuilder.End();
  97. pMesh->Draw();
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Assumes the material has already been bound
  101. //-----------------------------------------------------------------------------
  102. void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
  103. {
  104. unsigned char pColor[4] = { color.r, color.g, color.b, color.a };
  105. // Generate half-widths
  106. flWidth *= 0.5f;
  107. flHeight *= 0.5f;
  108. // Compute direction vectors for the sprite
  109. Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 );
  110. VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd );
  111. float flDist = VectorNormalize( fwd );
  112. if (flDist >= 1e-3)
  113. {
  114. CrossProduct( CurrentViewUp(), fwd, right );
  115. flDist = VectorNormalize( right );
  116. if (flDist >= 1e-3)
  117. {
  118. CrossProduct( fwd, right, up );
  119. }
  120. else
  121. {
  122. // In this case, fwd == g_vecVUp, it's right above or
  123. // below us in screen space
  124. CrossProduct( fwd, CurrentViewRight(), up );
  125. VectorNormalize( up );
  126. CrossProduct( up, fwd, right );
  127. }
  128. }
  129. CMeshBuilder meshBuilder;
  130. Vector point;
  131. CMatRenderContextPtr pRenderContext( materials );
  132. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  133. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  134. meshBuilder.Color4ubv (pColor);
  135. meshBuilder.TexCoord2f (0, 0, 1);
  136. VectorMA (vecOrigin, -flHeight, up, point);
  137. VectorMA (point, -flWidth, right, point);
  138. meshBuilder.Position3fv (point.Base());
  139. meshBuilder.AdvanceVertex();
  140. meshBuilder.Color4ubv (pColor);
  141. meshBuilder.TexCoord2f (0, 0, 0);
  142. VectorMA (vecOrigin, flHeight, up, point);
  143. VectorMA (point, -flWidth, right, point);
  144. meshBuilder.Position3fv (point.Base());
  145. meshBuilder.AdvanceVertex();
  146. meshBuilder.Color4ubv (pColor);
  147. meshBuilder.TexCoord2f (0, 1, 0);
  148. VectorMA (vecOrigin, flHeight, up, point);
  149. VectorMA (point, flWidth, right, point);
  150. meshBuilder.Position3fv (point.Base());
  151. meshBuilder.AdvanceVertex();
  152. meshBuilder.Color4ubv (pColor);
  153. meshBuilder.TexCoord2f (0, 1, 1);
  154. VectorMA (vecOrigin, -flHeight, up, point);
  155. VectorMA (point, flWidth, right, point);
  156. meshBuilder.Position3fv (point.Base());
  157. meshBuilder.AdvanceVertex();
  158. meshBuilder.End();
  159. pMesh->Draw();
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Compute vectors perpendicular to the beam
  163. //-----------------------------------------------------------------------------
  164. static void ComputeBeamPerpendicular( const Vector &vecBeamDelta, Vector *pPerp )
  165. {
  166. // Direction in worldspace of the center of the beam
  167. Vector vecBeamCenter = vecBeamDelta;
  168. VectorNormalize( vecBeamCenter );
  169. CrossProduct( CurrentViewForward(), vecBeamCenter, *pPerp );
  170. VectorNormalize( *pPerp );
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose:
  174. // Input : noise_divisions -
  175. // *prgNoise -
  176. // *spritemodel -
  177. // frame -
  178. // rendermode -
  179. // source -
  180. // delta -
  181. // flags -
  182. // *color -
  183. // fadescale -
  184. //-----------------------------------------------------------------------------
  185. void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  186. float frame, int rendermode, const Vector& source, const Vector& delta,
  187. float startWidth, float endWidth, float scale, float freq, float speed, int segments,
  188. int flags, float* color, float fadeLength, float flHDRColorScale )
  189. {
  190. int i, noiseIndex, noiseStep;
  191. float div, length, fraction, factor, vLast, vStep, brightness;
  192. Assert( fadeLength >= 0.0f );
  193. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  194. if ( !pSprite )
  195. return;
  196. if ( segments < 2 )
  197. return;
  198. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  199. if( pMaterial )
  200. {
  201. static unsigned int nHDRColorScaleCache = 0;
  202. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  203. if( pHDRColorScaleVar )
  204. {
  205. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  206. }
  207. }
  208. length = VectorLength( delta );
  209. float flMaxWidth = MAX(startWidth, endWidth) * 0.5f;
  210. div = 1.0 / (segments-1);
  211. if ( length*div < flMaxWidth * 1.414 )
  212. {
  213. // Here, we have too many segments; we could get overlap... so lets have less segments
  214. segments = (int)(length / (flMaxWidth * 1.414)) + 1;
  215. if ( segments < 2 )
  216. {
  217. segments = 2;
  218. }
  219. }
  220. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  221. {
  222. segments = noise_divisions;
  223. }
  224. div = 1.0 / (segments-1);
  225. length *= 0.01;
  226. // UNDONE: Expose texture length scale factor to control "fuzziness"
  227. if ( flags & FBEAM_NOTILE )
  228. {
  229. // Don't tile
  230. vStep = div;
  231. }
  232. else
  233. {
  234. // Texture length texels per space pixel
  235. vStep = length*div;
  236. }
  237. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  238. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  239. if ( flags & FBEAM_SINENOISE )
  240. {
  241. if ( segments < 16 )
  242. {
  243. segments = 16;
  244. div = 1.0 / (segments-1);
  245. }
  246. scale *= 100;
  247. length = segments * (1.0/10);
  248. }
  249. else
  250. {
  251. scale *= length;
  252. }
  253. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  254. noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
  255. noiseIndex = 0;
  256. if ( flags & FBEAM_SINENOISE )
  257. {
  258. noiseIndex = 0;
  259. }
  260. brightness = 1.0;
  261. if ( flags & FBEAM_SHADEIN )
  262. {
  263. brightness = 0;
  264. }
  265. // What fraction of beam should be faded
  266. Assert( fadeLength >= 0.0f );
  267. float fadeFraction = fadeLength/ delta.Length();
  268. // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
  269. fadeFraction = clamp(fadeFraction,1e-6,1);
  270. // Choose two vectors that are perpendicular to the beam
  271. Vector perp1;
  272. ComputeBeamPerpendicular( delta, &perp1 );
  273. // Specify all the segments.
  274. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  275. CBeamSegDraw segDraw;
  276. segDraw.Start( pRenderContext, segments, NULL );
  277. for ( i = 0; i < segments; i++ )
  278. {
  279. Assert( noiseIndex < (noise_divisions<<16) );
  280. BeamSeg_t curSeg;
  281. fraction = i * div;
  282. // Fade in our out beam to fadeLength
  283. if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
  284. {
  285. if (fraction < 0.5)
  286. {
  287. brightness = 2*(fraction/fadeFraction);
  288. }
  289. else
  290. {
  291. brightness = 2*(1.0 - (fraction/fadeFraction));
  292. }
  293. }
  294. else if ( flags & FBEAM_SHADEIN )
  295. {
  296. brightness = fraction/fadeFraction;
  297. }
  298. else if ( flags & FBEAM_SHADEOUT )
  299. {
  300. brightness = 1.0 - (fraction/fadeFraction);
  301. }
  302. // clamps
  303. if (brightness < 0 )
  304. {
  305. brightness = 0;
  306. }
  307. else if (brightness > 1)
  308. {
  309. brightness = 1;
  310. }
  311. Vector vecTemp;
  312. VectorScale( *((Vector*)color), brightness, vecTemp );
  313. curSeg.SetColor( vecTemp, 1.0f );
  314. // UNDONE: Make this a spline instead of just a line?
  315. VectorMA( source, fraction, delta, curSeg.m_vPos );
  316. // Distort using noise
  317. if ( scale != 0 )
  318. {
  319. factor = prgNoise[noiseIndex>>16] * scale;
  320. if ( flags & FBEAM_SINENOISE )
  321. {
  322. float s, c;
  323. SinCos( fraction*M_PI*length + freq, &s, &c );
  324. VectorMA( curSeg.m_vPos, factor * s, CurrentViewUp(), curSeg.m_vPos );
  325. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  326. VectorMA( curSeg.m_vPos, factor * c, CurrentViewRight(), curSeg.m_vPos );
  327. }
  328. else
  329. {
  330. VectorMA( curSeg.m_vPos, factor, perp1, curSeg.m_vPos );
  331. }
  332. }
  333. // Specify the next segment.
  334. if( endWidth == startWidth )
  335. {
  336. curSeg.m_flWidth = startWidth * 2;
  337. }
  338. else
  339. {
  340. curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
  341. }
  342. curSeg.m_flTexCoord = vLast;
  343. segDraw.NextSeg( &curSeg );
  344. vLast += vStep; // Advance texture scroll (v axis only)
  345. noiseIndex += noiseStep;
  346. }
  347. segDraw.End();
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose:
  351. //-----------------------------------------------------------------------------
  352. void CalcSegOrigin( Vector *vecOut, int iPoint, int noise_divisions, float *prgNoise,
  353. const Vector &source, const Vector& delta, const Vector &perp, int segments,
  354. float freq, float scale, float fraction, int flags )
  355. {
  356. Assert( segments > 1 );
  357. float factor;
  358. float length = VectorLength( delta ) * 0.01;
  359. float div = 1.0 / (segments-1);
  360. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  361. int noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
  362. int noiseIndex = (iPoint) * noiseStep;
  363. // Sine noise beams have different length calculations
  364. if ( flags & FBEAM_SINENOISE )
  365. {
  366. length = segments * (1.0/10);
  367. noiseIndex = 0;
  368. }
  369. // UNDONE: Make this a spline instead of just a line?
  370. VectorMA( source, fraction, delta, *vecOut );
  371. // Distort using noise
  372. if ( scale != 0 )
  373. {
  374. factor = prgNoise[noiseIndex>>16] * scale;
  375. if ( flags & FBEAM_SINENOISE )
  376. {
  377. float s, c;
  378. SinCos( fraction*M_PI*length + freq, &s, &c );
  379. VectorMA( *vecOut, factor * s, CurrentViewUp(), *vecOut );
  380. // Rotate the noise along the perpendicular axis a bit to keep the bolt from looking diagonal
  381. VectorMA( *vecOut, factor * c, CurrentViewRight(), *vecOut );
  382. }
  383. else
  384. {
  385. VectorMA( *vecOut, factor, perp, *vecOut );
  386. }
  387. }
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose:
  391. // Input : noise_divisions -
  392. // *prgNoise -
  393. // *spritemodel -
  394. // frame -
  395. // rendermode -
  396. // source -
  397. // delta -
  398. // flags -
  399. // *color -
  400. // fadescale -
  401. //-----------------------------------------------------------------------------
  402. void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  403. float frame, int rendermode, const Vector& source, const Vector& delta,
  404. float startWidth, float endWidth, float scale, float freq, float speed, int segments,
  405. int flags, float* color, float fadeLength, float flHDRColorScale )
  406. {
  407. int i;
  408. float div, length, fraction, vLast, vStep, brightness;
  409. Assert( fadeLength >= 0.0f );
  410. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  411. if ( !pSprite )
  412. return;
  413. if ( segments < 2 )
  414. return;
  415. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  416. if( pMaterial )
  417. {
  418. static unsigned int nHDRColorScaleCache = 0;
  419. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  420. if( pHDRColorScaleVar )
  421. {
  422. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  423. }
  424. }
  425. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  426. segments = noise_divisions;
  427. length = VectorLength( delta ) * 0.01;
  428. div = 1.0 / (segments-1);
  429. // UNDONE: Expose texture length scale factor to control "fuzziness"
  430. vStep = length*div; // Texture length texels per space pixel
  431. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  432. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  433. brightness = 1.0;
  434. if ( flags & FBEAM_SHADEIN )
  435. brightness = 0;
  436. // What fraction of beam should be faded
  437. Assert( fadeLength >= 0.0f );
  438. float fadeFraction = fadeLength/ delta.Length();
  439. // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
  440. fadeFraction = clamp(fadeFraction,1e-6,1);
  441. Vector perp;
  442. ComputeBeamPerpendicular( delta, &perp );
  443. // Specify all the segments.
  444. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  445. CBeamSegDraw segDraw;
  446. segDraw.Start( pRenderContext, segments, NULL );
  447. // Keep track of how many times we've branched
  448. int iBranches = 0;
  449. Vector vecStart, vecEnd;
  450. float flWidth = 0;
  451. float flEndWidth = 0;
  452. for ( i = 0; i < segments; i++ )
  453. {
  454. BeamSeg_t curSeg;
  455. fraction = i * div;
  456. // Fade in our out beam to fadeLength
  457. if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
  458. {
  459. if (fraction < 0.5)
  460. {
  461. brightness = 2*(fraction/fadeFraction);
  462. }
  463. else
  464. {
  465. brightness = 2*(1.0 - (fraction/fadeFraction));
  466. }
  467. }
  468. else if ( flags & FBEAM_SHADEIN )
  469. {
  470. brightness = fraction/fadeFraction;
  471. }
  472. else if ( flags & FBEAM_SHADEOUT )
  473. {
  474. brightness = 1.0 - (fraction/fadeFraction);
  475. }
  476. // clamps
  477. if (brightness < 0 )
  478. {
  479. brightness = 0;
  480. }
  481. else if (brightness > 1)
  482. {
  483. brightness = 1;
  484. }
  485. Vector vecTemp;
  486. VectorScale( *((Vector*)color), brightness, vecTemp );
  487. curSeg.SetColor( vecTemp, 1.0f );
  488. CalcSegOrigin( &curSeg.m_vPos, i, noise_divisions, prgNoise, source, delta, perp, segments, freq, scale, fraction, flags );
  489. // Specify the next segment.
  490. if( endWidth == startWidth )
  491. curSeg.m_flWidth = startWidth * 2;
  492. else
  493. curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
  494. // Reduce the width by the current number of branches we've had
  495. for ( int j = 0; i < iBranches; j++ )
  496. {
  497. curSeg.m_flWidth *= 0.5;
  498. }
  499. curSeg.m_flTexCoord = vLast;
  500. segDraw.NextSeg( &curSeg );
  501. vLast += vStep; // Advance texture scroll (v axis only)
  502. // Now see if we'd like to branch here
  503. // For now, always branch at the midpoint.
  504. // We could branch randomly, and multiple times per beam
  505. if ( i == (segments * 0.5) )
  506. {
  507. // Figure out what the new width would be
  508. // Halve the width because the beam is breaking in two, and halve it again because width is doubled above
  509. flWidth = curSeg.m_flWidth * 0.25;
  510. if ( flWidth > 1 )
  511. {
  512. iBranches++;
  513. // Get an endpoint for the new branch
  514. vecStart = curSeg.m_vPos;
  515. vecEnd = source + delta + (CurrentViewUp() * 32) + (CurrentViewRight() * 32);
  516. vecEnd -= vecStart;
  517. // Reduce the end width by the current number of branches we've had
  518. flEndWidth = endWidth;
  519. for ( int j = 0; i < iBranches; j++ )
  520. {
  521. flEndWidth *= 0.5;
  522. }
  523. }
  524. }
  525. }
  526. segDraw.End();
  527. // If we branched, draw the new beam too
  528. if ( iBranches )
  529. {
  530. DrawTeslaSegs( noise_divisions, prgNoise, spritemodel, frame, rendermode,
  531. vecStart, vecEnd, flWidth, flEndWidth, scale, freq, speed, segments,
  532. flags, color, fadeLength, flHDRColorScale );
  533. }
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose:
  537. // Input : noise_divisions -
  538. // *prgNoise -
  539. // *beammodel -
  540. // *halomodel -
  541. // flHaloScale -
  542. // startWidth -
  543. // endWidth -
  544. // scale -
  545. // freq -
  546. // speed -
  547. // segments -
  548. // * -
  549. //-----------------------------------------------------------------------------
  550. void DrawSplineSegs( int noise_divisions, float *prgNoise,
  551. const model_t* beammodel, const model_t* halomodel, float flHaloScale,
  552. float frame, int rendermode, int numAttachments, Vector* attachment,
  553. float startWidth, float endWidth, float scale, float freq, float speed, int segments,
  554. int flags, float* color, float fadeLength, float flHDRColorScale )
  555. {
  556. int noiseIndex, noiseStep;
  557. float div, length, fraction, factor, vLast, vStep, brightness;
  558. float scaledColor[3];
  559. model_t *beamsprite = ( model_t *)beammodel;
  560. model_t *halosprite = ( model_t *)halomodel;
  561. CEngineSprite *pBeamSprite = Draw_SetSpriteTexture( beamsprite, frame, rendermode );
  562. if ( !pBeamSprite )
  563. return;
  564. // Figure out the number of segments.
  565. if ( segments < 2 )
  566. return;
  567. IMaterial *pMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
  568. if( pMaterial )
  569. {
  570. static unsigned int nHDRColorScaleCache = 0;
  571. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  572. if( pHDRColorScaleVar )
  573. {
  574. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  575. }
  576. }
  577. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  578. segments = noise_divisions;
  579. if ( flags & FBEAM_SINENOISE )
  580. {
  581. if ( segments < 16 )
  582. segments = 16;
  583. }
  584. IMaterial *pBeamMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
  585. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  586. CBeamSegDraw segDraw;
  587. segDraw.Start( pRenderContext, (segments-1)*(numAttachments-1), pBeamMaterial );
  588. CEngineSprite *pHaloSprite = (CEngineSprite *)modelinfo->GetModelExtraData( halosprite );
  589. IMaterial *pHaloMaterial = NULL;
  590. if ( pHaloSprite )
  591. {
  592. pHaloMaterial = pHaloSprite->GetMaterial( kRenderGlow );
  593. }
  594. //-----------------------------------------------------------
  595. // Calculate widthStep if start and end width are different
  596. //-----------------------------------------------------------
  597. float widthStep;
  598. if (startWidth != endWidth)
  599. {
  600. widthStep = (endWidth - startWidth)/numAttachments;
  601. }
  602. else
  603. {
  604. widthStep = 0;
  605. }
  606. // Calculate total length of beam
  607. float flBeamLength = (attachment[0]-attachment[numAttachments-1]).Length();
  608. // What fraction of beam should be faded
  609. float fadeFraction = fadeLength/flBeamLength;
  610. if (fadeFraction > 1)
  611. {
  612. fadeFraction = 1;
  613. }
  614. //---------------------------------------------------------------
  615. // Go through each attachment drawing spline beams between them
  616. //---------------------------------------------------------------
  617. Vector vLastPoint(0,0,0);
  618. Vector pPre; // attachment point before the current beam
  619. Vector pStart; // start of current beam
  620. Vector pEnd; // end of current beam
  621. Vector pNext; // attachment point after the current beam
  622. for (int j=0;j<numAttachments-1;j++)
  623. {
  624. if (j==0)
  625. {
  626. VectorCopy(attachment[0],pPre);
  627. VectorCopy(pPre,vLastPoint);
  628. }
  629. else
  630. {
  631. VectorCopy(attachment[j-1],pPre);
  632. }
  633. VectorCopy(attachment[j], pStart);
  634. VectorCopy(attachment[j+1], pEnd);
  635. if (j+2 >= numAttachments-1)
  636. {
  637. VectorCopy(attachment[j+1],pNext);
  638. }
  639. else
  640. {
  641. VectorCopy(attachment[j+2],pNext);
  642. }
  643. Vector vDelta;
  644. VectorSubtract(pEnd,pStart,vDelta);
  645. length = VectorLength( vDelta ) * 0.01;
  646. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  647. length = 0.5;
  648. div = 1.0 / (segments-1);
  649. // UNDONE: Expose texture length scale factor to control "fuzziness"
  650. vStep = length*div; // Texture length texels per space pixel
  651. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  652. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  653. if ( flags & FBEAM_SINENOISE )
  654. {
  655. scale = scale * 100;
  656. length = segments * (1.0/10);
  657. }
  658. else
  659. scale = scale * length;
  660. // -----------------------------------------------------------------------------
  661. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  662. // -----------------------------------------------------------------------------
  663. noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
  664. noiseIndex = noiseStep;
  665. if ( flags & FBEAM_SINENOISE )
  666. noiseIndex = 0;
  667. brightness = 1.0;
  668. if ( flags & FBEAM_SHADEIN )
  669. brightness = 0;
  670. BeamSeg_t seg;
  671. VectorScale( color, brightness, scaledColor );
  672. seg.SetColor( scaledColor[0], scaledColor[1], scaledColor[2], 1.0f );
  673. // -------------------------------------------------
  674. // Calc start and end widths for this segment
  675. // -------------------------------------------------
  676. float startSegWidth = startWidth + (widthStep*j);
  677. float endSegWidth = startWidth + (widthStep*(j+1));
  678. // -------------------------------------------------
  679. // Now draw each segment
  680. // -------------------------------------------------
  681. float fBestFraction = -1;
  682. float bestDot = 0;
  683. for (int i = 1; i < segments; i++ )
  684. {
  685. fraction = i * div;
  686. // Fade in our out beam to fadeLength
  687. // BUG BUG: should be based on total lengh of beam not this particular fraction
  688. if ( flags & FBEAM_SHADEIN )
  689. {
  690. brightness = fraction/fadeFraction;
  691. if (brightness > 1)
  692. {
  693. brightness = 1;
  694. }
  695. }
  696. else if ( flags & FBEAM_SHADEOUT )
  697. {
  698. float fadeFraction = fadeLength/length;
  699. brightness = 1.0 - (fraction/fadeFraction);
  700. if (brightness < 0)
  701. {
  702. brightness = 0;
  703. }
  704. }
  705. // -----------------------------------------------------------
  706. // Calculate spline position
  707. // -----------------------------------------------------------
  708. Vector vTarget(0,0,0);
  709. Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fraction, vTarget );
  710. seg.m_vPos[0] = vTarget.x;
  711. seg.m_vPos[1] = vTarget.y;
  712. seg.m_vPos[2] = vTarget.z;
  713. // --------------------------------------------------------------
  714. // Keep track of segment most facing the player for halo effect
  715. // --------------------------------------------------------------
  716. if (pHaloMaterial)
  717. {
  718. Vector vBeamDir1;
  719. VectorSubtract(seg.m_vPos,vLastPoint,vBeamDir1);
  720. VectorNormalize(vBeamDir1);
  721. Vector vLookDir;
  722. VectorSubtract(CurrentViewOrigin(),seg.m_vPos,vLookDir);
  723. VectorNormalize(vLookDir);
  724. float dotpr = fabs(DotProduct(vBeamDir1,vLookDir));
  725. static float thresh = 0.85;
  726. if (dotpr > thresh && dotpr > bestDot)
  727. {
  728. bestDot = dotpr;
  729. fBestFraction = fraction;
  730. }
  731. VectorCopy(seg.m_vPos,vLastPoint);
  732. }
  733. // ----------------------
  734. // Distort using noise
  735. // ----------------------
  736. if ( scale != 0 )
  737. {
  738. factor = prgNoise[noiseIndex>>16] * scale;
  739. if ( flags & FBEAM_SINENOISE )
  740. {
  741. float s, c;
  742. SinCos( fraction*M_PI*length + freq, &s, &c );
  743. VectorMA( seg.m_vPos, factor * s, CurrentViewUp(), seg.m_vPos );
  744. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  745. VectorMA( seg.m_vPos, factor * c, CurrentViewRight(), seg.m_vPos );
  746. }
  747. else
  748. {
  749. VectorMA( seg.m_vPos, factor, CurrentViewUp(), seg.m_vPos );
  750. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  751. factor = prgNoise[noiseIndex>>16] * scale * cos(fraction*M_PI*3+freq);
  752. VectorMA( seg.m_vPos, factor, CurrentViewRight(), seg.m_vPos );
  753. }
  754. }
  755. // Scale width if non-zero spread
  756. if (startWidth != endWidth)
  757. seg.m_flWidth = ((fraction*(endSegWidth-startSegWidth))+startSegWidth)*2;
  758. else
  759. seg.m_flWidth = startWidth*2;
  760. seg.m_flTexCoord = vLast;
  761. segDraw.NextSeg( &seg );
  762. vLast += vStep; // Advance texture scroll (v axis only)
  763. noiseIndex += noiseStep;
  764. }
  765. // --------------------------------------------------------------
  766. // Draw halo on segment most facing the player
  767. // --------------------------------------------------------------
  768. if (false&&pHaloMaterial)
  769. {
  770. Vector vHaloPos(0,0,0);
  771. if (bestDot != 0)
  772. {
  773. Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fBestFraction, vHaloPos);
  774. }
  775. else
  776. {
  777. Vector vBeamDir1;
  778. VectorSubtract(pStart,pEnd,vBeamDir1);
  779. VectorNormalize(vBeamDir1);
  780. Vector vLookDir;
  781. VectorSubtract(CurrentViewOrigin(),pStart,vLookDir);
  782. VectorNormalize(vLookDir);
  783. bestDot = fabs(DotProduct(vBeamDir1,vLookDir));
  784. static float thresh = 0.85;
  785. if (bestDot > thresh)
  786. {
  787. fBestFraction = 0.5;
  788. VectorAdd(pStart,pEnd,vHaloPos);
  789. VectorScale(vHaloPos,0.5,vHaloPos);
  790. }
  791. }
  792. if (fBestFraction > 0)
  793. {
  794. float fade = pow(bestDot,60);
  795. if (fade > 1.0) fade = 1.0;
  796. float haloColor[3];
  797. VectorScale( color, fade, haloColor );
  798. pRenderContext->Bind(pHaloMaterial);
  799. float curWidth = (fBestFraction*(endSegWidth-startSegWidth))+startSegWidth;
  800. DrawHalo(pHaloMaterial,vHaloPos,flHaloScale*curWidth/endWidth,haloColor, flHDRColorScale);
  801. }
  802. }
  803. }
  804. segDraw.End();
  805. // ------------------------
  806. // Draw halo at end of beam
  807. // ------------------------
  808. if (pHaloMaterial)
  809. {
  810. pRenderContext->Bind(pHaloMaterial);
  811. DrawHalo(pHaloMaterial,pEnd,flHaloScale,scaledColor, flHDRColorScale);
  812. }
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose:
  816. // Input : *spritemodel -
  817. // frame -
  818. // rendermode -
  819. // source -
  820. // scale -
  821. // *color -
  822. //-----------------------------------------------------------------------------
  823. void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode,
  824. const Vector& source, float scale, float* color, float flHDRColorScale )
  825. {
  826. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  827. if ( !pSprite )
  828. return;
  829. DrawHalo( pSprite->GetMaterial( (RenderMode_t)rendermode ), source, scale, color, flHDRColorScale );
  830. }
  831. //-----------------------------------------------------------------------------
  832. // Purpose:
  833. // Input : noise_divisions -
  834. // *prgNoise -
  835. // *spritemodel -
  836. // frame -
  837. // rendermode -
  838. // source -
  839. // delta -
  840. // width -
  841. // scale -
  842. // freq -
  843. // speed -
  844. // segments -
  845. // *color -
  846. //-----------------------------------------------------------------------------
  847. void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  848. float frame, int rendermode, const Vector& source, const Vector& delta,
  849. float width, float scale, float freq, float speed, int segments, float* color, float flHDRColorScale )
  850. {
  851. int i;
  852. float div, length, fraction, vLast, vStep;
  853. Vector point;
  854. float w;
  855. static unsigned int nHDRColorScaleCache = 0;
  856. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  857. if ( !pSprite )
  858. return;
  859. if ( segments < 2 )
  860. return;
  861. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  862. if( pMaterial )
  863. {
  864. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  865. if( pHDRColorScaleVar )
  866. {
  867. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  868. }
  869. }
  870. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  871. segments = noise_divisions;
  872. length = VectorLength( delta ) * 0.01;
  873. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  874. length = 0.5;
  875. div = 1.0 / (segments-1);
  876. // UNDONE: Expose texture length scale factor to control "fuzziness"
  877. vStep = length*div; // Texture length texels per space pixel
  878. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  879. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  880. scale = scale * length;
  881. w = freq * delta[2];
  882. CMatRenderContextPtr pRenderContext( materials );
  883. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  884. CMeshBuilder meshBuilder;
  885. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
  886. // NOTE: We must force the degenerate triangles to be on the edge
  887. for ( i = 0; i < segments; i++ )
  888. {
  889. float s, c;
  890. fraction = i * div;
  891. point[0] = source[0];
  892. point[1] = source[1];
  893. point[2] = source[2];
  894. meshBuilder.Color3fv( color );
  895. meshBuilder.TexCoord2f( 0, 1.0, vLast );
  896. meshBuilder.Position3fv( point.Base() );
  897. meshBuilder.AdvanceVertex();
  898. SinCos( fraction * 2 * M_PI, &s, &c );
  899. point[0] = s * w + source[0];
  900. point[1] = c * w + source[1];
  901. point[2] = source[2];
  902. meshBuilder.Color3fv( color );
  903. meshBuilder.TexCoord2f( 0, 0.0, vLast );
  904. meshBuilder.Position3fv( point.Base() );
  905. meshBuilder.AdvanceVertex();
  906. vLast += vStep; // Advance texture scroll (v axis only)
  907. }
  908. meshBuilder.End( );
  909. pMesh->Draw();
  910. }
  911. //-----------------------------------------------------------------------------
  912. // Purpose:
  913. // Input : noise_divisions -
  914. // *prgNoise -
  915. // *spritemodel -
  916. // frame -
  917. // rendermode -
  918. // source -
  919. // delta -
  920. // width -
  921. // scale -
  922. // freq -
  923. // speed -
  924. // segments -
  925. // *color -
  926. //-----------------------------------------------------------------------------
  927. void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  928. float frame, int rendermode, const Vector& source, const Vector& delta,
  929. float width, float scale, float freq, float speed, int segments,
  930. float* color, float flHDRColorScale )
  931. {
  932. int i;
  933. float div, length, fraction, vLast, vStep;
  934. Vector point;
  935. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  936. if ( !pSprite )
  937. return;
  938. if ( segments < 2 )
  939. return;
  940. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  941. if( pMaterial )
  942. {
  943. static unsigned int nHDRColorScaleCache = 0;
  944. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  945. if( pHDRColorScaleVar )
  946. {
  947. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  948. }
  949. }
  950. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  951. segments = noise_divisions;
  952. length = VectorLength( delta ) * 0.01;
  953. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  954. length = 0.5;
  955. div = 1.0 / (segments-1);
  956. // UNDONE: Expose texture length scale factor to control "fuzziness"
  957. vStep = length*div; // Texture length texels per space pixel
  958. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  959. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  960. scale = scale * length;
  961. CMatRenderContextPtr pRenderContext( materials );
  962. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  963. CMeshBuilder meshBuilder;
  964. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
  965. float radius = delta[2];
  966. for ( i = 0; i < segments; i++ )
  967. {
  968. float s, c;
  969. fraction = i * div;
  970. SinCos( fraction * 2 * M_PI, &s, &c );
  971. point[0] = s * freq * radius + source[0];
  972. point[1] = c * freq * radius + source[1];
  973. point[2] = source[2] + width;
  974. meshBuilder.Color3f( 0.0f, 0.0f, 0.0f );
  975. meshBuilder.TexCoord2f( 0, 1.0f, vLast );
  976. meshBuilder.Position3fv( point.Base() );
  977. meshBuilder.AdvanceVertex();
  978. point[0] = s * freq * (radius + width) + source[0];
  979. point[1] = c * freq * (radius + width) + source[1];
  980. point[2] = source[2] - width;
  981. meshBuilder.Color3fv( color );
  982. meshBuilder.TexCoord2f( 0, 0.0f, vLast );
  983. meshBuilder.Position3fv( point.Base() );
  984. meshBuilder.AdvanceVertex();
  985. vLast += vStep; // Advance texture scroll (v axis only)
  986. }
  987. meshBuilder.End();
  988. pMesh->Draw();
  989. }
  990. //-----------------------------------------------------------------------------
  991. // Purpose:
  992. // Input : noise_divisions -
  993. // *prgNoise -
  994. // (*pfnNoise -
  995. //-----------------------------------------------------------------------------
  996. void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ),
  997. const model_t* spritemodel, float frame, int rendermode,
  998. const Vector& source, const Vector& delta, float width,
  999. float amplitude, float freq, float speed, int segments, float *color, float flHDRColorScale )
  1000. {
  1001. int i, j, noiseIndex, noiseStep;
  1002. float div, length, fraction, factor, vLast, vStep;
  1003. Vector last1, last2, point, screen, screenLast(0,0,0), tmp, normal;
  1004. Vector center, xaxis, yaxis, zaxis;
  1005. float radius, x, y, scale;
  1006. Vector d;
  1007. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  1008. if ( !pSprite )
  1009. return;
  1010. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  1011. if( pMaterial )
  1012. {
  1013. static unsigned int nHDRColorScaleCache = 0;
  1014. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  1015. if( pHDRColorScaleVar )
  1016. {
  1017. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  1018. }
  1019. }
  1020. VectorCopy( delta, d );
  1021. if ( segments < 2 )
  1022. return;
  1023. segments = segments * M_PI;
  1024. if ( segments > noise_divisions * 8 ) // UNDONE: Allow more segments?
  1025. segments = noise_divisions * 8;
  1026. length = VectorLength( d ) * 0.01 * M_PI;
  1027. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  1028. length = 0.5;
  1029. div = 1.0 / (segments-1);
  1030. // UNDONE: Expose texture length scale factor to control "fuzziness"
  1031. vStep = length*div/8.0; // Texture length texels per space pixel
  1032. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  1033. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  1034. scale = amplitude * length / 8.0;
  1035. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  1036. noiseStep = (int)((noise_divisions-1) * div * 65536.0) * 8;
  1037. noiseIndex = 0;
  1038. VectorScale( d, 0.5, d );
  1039. VectorAdd( source, d, center );
  1040. zaxis[0] = 0; zaxis[1] = 0; zaxis[2] = 1;
  1041. VectorCopy( d, xaxis );
  1042. radius = VectorLength( xaxis );
  1043. // cull beamring
  1044. // --------------------------------
  1045. // Compute box center +/- radius
  1046. last1[0] = radius;
  1047. last1[1] = radius;
  1048. last1[2] = scale;
  1049. VectorAdd( center, last1, tmp ); // maxs
  1050. VectorSubtract( center, last1, screen ); // mins
  1051. // Is that box in PVS && frustum?
  1052. if ( !engine->IsBoxVisible( screen, tmp ) || engine->CullBox( screen, tmp ) )
  1053. {
  1054. return;
  1055. }
  1056. yaxis[0] = xaxis[1]; yaxis[1] = -xaxis[0]; yaxis[2] = 0;
  1057. VectorNormalize( yaxis );
  1058. VectorScale( yaxis, radius, yaxis );
  1059. j = segments / 8;
  1060. CMatRenderContextPtr pRenderContext( materials );
  1061. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  1062. CMeshBuilder meshBuilder;
  1063. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments) * 2 );
  1064. for ( i = 0; i < segments + 1; i++ )
  1065. {
  1066. fraction = i * div;
  1067. SinCos( fraction * 2 * M_PI, &x, &y );
  1068. point[0] = xaxis[0] * x + yaxis[0] * y + center[0];
  1069. point[1] = xaxis[1] * x + yaxis[1] * y + center[1];
  1070. point[2] = xaxis[2] * x + yaxis[2] * y + center[2];
  1071. // Distort using noise
  1072. if ( scale != 0.0f )
  1073. {
  1074. factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale;
  1075. VectorMA( point, factor, CurrentViewUp(), point );
  1076. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  1077. factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale * cos(fraction*M_PI*3*8+freq);
  1078. VectorMA( point, factor, CurrentViewRight(), point );
  1079. }
  1080. // Transform point into screen space
  1081. ScreenTransform( point, screen );
  1082. if (i != 0)
  1083. {
  1084. // Build world-space normal to screen-space direction vector
  1085. VectorSubtract( screen, screenLast, tmp );
  1086. // We don't need Z, we're in screen space
  1087. tmp[2] = 0;
  1088. VectorNormalize( tmp );
  1089. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1090. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1091. // Make a wide line
  1092. VectorMA( point, width, normal, last1 );
  1093. VectorMA( point, -width, normal, last2 );
  1094. vLast += vStep; // Advance texture scroll (v axis only)
  1095. meshBuilder.Color3fv( color );
  1096. meshBuilder.TexCoord2f( 0, 1.0f, vLast );
  1097. meshBuilder.Position3fv( last2.Base() );
  1098. meshBuilder.AdvanceVertex();
  1099. meshBuilder.Color3fv( color );
  1100. meshBuilder.TexCoord2f( 0, 0.0f, vLast );
  1101. meshBuilder.Position3fv( last1.Base() );
  1102. meshBuilder.AdvanceVertex();
  1103. }
  1104. VectorCopy( screen, screenLast );
  1105. noiseIndex += noiseStep;
  1106. j--;
  1107. if (j == 0 && amplitude != 0 )
  1108. {
  1109. j = segments / 8;
  1110. (*pfnNoise)( prgNoise, noise_divisions, 1.0f );
  1111. }
  1112. }
  1113. meshBuilder.End();
  1114. pMesh->Draw();
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Purpose:
  1118. // Input : spritemodel -
  1119. // *pHead -
  1120. // delta -
  1121. // *screen -
  1122. // *screenLast -
  1123. // die -
  1124. // source -
  1125. // flags -
  1126. // width -
  1127. // amplitude -
  1128. // freq -
  1129. // *color -
  1130. //-----------------------------------------------------------------------------
  1131. void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode,
  1132. Vector& delta, Vector& screen, Vector& screenLast, float die,
  1133. const Vector& source, int flags, float width, float amplitude,
  1134. float freq, float* color, float flHDRColorScale )
  1135. {
  1136. float fraction;
  1137. float div;
  1138. float vLast = 0.0;
  1139. float vStep = 1.0;
  1140. Vector last1, last2, tmp, normal;
  1141. float scaledColor[3];
  1142. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  1143. if ( !pSprite )
  1144. return;
  1145. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  1146. if( pMaterial )
  1147. {
  1148. static unsigned int nHDRColorScaleCache = 0;
  1149. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  1150. if( pHDRColorScaleVar )
  1151. {
  1152. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  1153. }
  1154. }
  1155. // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the
  1156. // first beam segment for this trail
  1157. // Build world-space normal to screen-space direction vector
  1158. VectorSubtract( screen, screenLast, tmp );
  1159. // We don't need Z, we're in screen space
  1160. tmp[2] = 0;
  1161. VectorNormalize( tmp );
  1162. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1163. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1164. // Make a wide line
  1165. VectorMA( delta, width, normal, last1 );
  1166. VectorMA( delta, -width, normal, last2 );
  1167. div = 1.0 / amplitude;
  1168. fraction = ( die - gpGlobals->curtime ) * div;
  1169. unsigned char nColor[3];
  1170. VectorScale( color, fraction, scaledColor );
  1171. nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
  1172. nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
  1173. nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
  1174. // need to count the segments
  1175. int count = 0;
  1176. BeamTrail_t* pTraverse = pHead;
  1177. while ( pTraverse )
  1178. {
  1179. ++count;
  1180. pTraverse = pTraverse->next;
  1181. }
  1182. CMatRenderContextPtr pRenderContext( materials );
  1183. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  1184. CMeshBuilder meshBuilder;
  1185. meshBuilder.Begin( pMesh, MATERIAL_QUADS, count );
  1186. while (pHead)
  1187. {
  1188. // Msg("%.2f ", fraction );
  1189. meshBuilder.Position3fv( last1.Base() );
  1190. meshBuilder.Color3ubv( nColor );
  1191. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1192. meshBuilder.AdvanceVertex();
  1193. meshBuilder.Position3fv( last2.Base() );
  1194. meshBuilder.Color3ubv( nColor );
  1195. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  1196. meshBuilder.AdvanceVertex();
  1197. // Transform point into screen space
  1198. ScreenTransform( pHead->org, screen );
  1199. // Build world-space normal to screen-space direction vector
  1200. VectorSubtract( screen, screenLast, tmp );
  1201. // We don't need Z, we're in screen space
  1202. tmp[2] = 0;
  1203. VectorNormalize( tmp );
  1204. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1205. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1206. // Make a wide line
  1207. VectorMA( pHead->org, width, normal, last1 );
  1208. VectorMA( pHead->org, -width, normal, last2 );
  1209. vLast += vStep; // Advance texture scroll (v axis only)
  1210. if (pHead->next != NULL)
  1211. {
  1212. fraction = (pHead->die - gpGlobals->curtime) * div;
  1213. VectorScale( color, fraction, scaledColor );
  1214. nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
  1215. nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
  1216. nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
  1217. }
  1218. else
  1219. {
  1220. fraction = 0.0;
  1221. nColor[0] = nColor[1] = nColor[2] = 0;
  1222. }
  1223. meshBuilder.Position3fv( last2.Base() );
  1224. meshBuilder.Color3ubv( nColor );
  1225. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  1226. meshBuilder.AdvanceVertex();
  1227. meshBuilder.Position3fv( last1.Base() );
  1228. meshBuilder.Color3ubv( nColor );
  1229. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  1230. meshBuilder.AdvanceVertex();
  1231. VectorCopy( screen, screenLast );
  1232. pHead = pHead->next;
  1233. }
  1234. meshBuilder.End();
  1235. pMesh->Draw();
  1236. }
  1237. /*
  1238. P0 = start
  1239. P1 = control
  1240. P2 = end
  1241. P(t) = (1-t)^2 * P0 + 2t(1-t)*P1 + t^2 * P2
  1242. */
  1243. void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale )
  1244. {
  1245. int subdivisions = 16;
  1246. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1247. CBeamSegDraw beamDraw;
  1248. beamDraw.Start( pRenderContext, subdivisions+1, NULL );
  1249. BeamSeg_t seg;
  1250. seg.m_flWidth = width;
  1251. float t = 0;
  1252. float u = fmod( scrollOffset, 1 );
  1253. float dt = 1.0 / (float)subdivisions;
  1254. for( int i = 0; i <= subdivisions; i++, t += dt )
  1255. {
  1256. float omt = (1-t);
  1257. float p0 = omt*omt;
  1258. float p1 = 2*t*omt;
  1259. float p2 = t*t;
  1260. seg.m_vPos = p0 * start + p1 * control + p2 * end;
  1261. seg.m_flTexCoord = u - t;
  1262. if ( i == 0 || i == subdivisions )
  1263. {
  1264. // HACK: fade out the ends a bit
  1265. seg.m_color.r = seg.m_color.g = seg.m_color.b = 0;
  1266. seg.m_color.a = 255;
  1267. }
  1268. else
  1269. {
  1270. seg.SetColor( color, 1.0f );
  1271. }
  1272. beamDraw.NextSeg( &seg );
  1273. }
  1274. beamDraw.End();
  1275. }