Team Fortress 2 Source Code as on 22/4/2020
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.

1526 lines
43 KiB

  1. //========= Copyright 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( "shadertest/wireframevertexcolor", 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,1.e-6f,1.f);
  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. curSeg.m_flAlpha = 1;
  282. fraction = i * div;
  283. // Fade in our out beam to fadeLength
  284. if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
  285. {
  286. if (fraction < 0.5)
  287. {
  288. brightness = 2*(fraction/fadeFraction);
  289. }
  290. else
  291. {
  292. brightness = 2*(1.0 - (fraction/fadeFraction));
  293. }
  294. }
  295. else if ( flags & FBEAM_SHADEIN )
  296. {
  297. brightness = fraction/fadeFraction;
  298. }
  299. else if ( flags & FBEAM_SHADEOUT )
  300. {
  301. brightness = 1.0 - (fraction/fadeFraction);
  302. }
  303. // clamps
  304. if (brightness < 0 )
  305. {
  306. brightness = 0;
  307. }
  308. else if (brightness > 1)
  309. {
  310. brightness = 1;
  311. }
  312. VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
  313. // UNDONE: Make this a spline instead of just a line?
  314. VectorMA( source, fraction, delta, curSeg.m_vPos );
  315. // Distort using noise
  316. if ( scale != 0 )
  317. {
  318. factor = prgNoise[noiseIndex>>16] * scale;
  319. if ( flags & FBEAM_SINENOISE )
  320. {
  321. float s, c;
  322. SinCos( fraction*M_PI*length + freq, &s, &c );
  323. VectorMA( curSeg.m_vPos, factor * s, CurrentViewUp(), curSeg.m_vPos );
  324. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  325. VectorMA( curSeg.m_vPos, factor * c, CurrentViewRight(), curSeg.m_vPos );
  326. }
  327. else
  328. {
  329. VectorMA( curSeg.m_vPos, factor, perp1, curSeg.m_vPos );
  330. }
  331. }
  332. // Specify the next segment.
  333. if( endWidth == startWidth )
  334. {
  335. curSeg.m_flWidth = startWidth * 2;
  336. }
  337. else
  338. {
  339. curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
  340. }
  341. curSeg.m_flTexCoord = vLast;
  342. segDraw.NextSeg( &curSeg );
  343. vLast += vStep; // Advance texture scroll (v axis only)
  344. noiseIndex += noiseStep;
  345. }
  346. segDraw.End();
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose:
  350. //-----------------------------------------------------------------------------
  351. void CalcSegOrigin( Vector *vecOut, int iPoint, int noise_divisions, float *prgNoise,
  352. const Vector &source, const Vector& delta, const Vector &perp, int segments,
  353. float freq, float scale, float fraction, int flags )
  354. {
  355. Assert( segments > 1 );
  356. float factor;
  357. float length = VectorLength( delta ) * 0.01;
  358. float div = 1.0 / (segments-1);
  359. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  360. int noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
  361. int noiseIndex = (iPoint) * noiseStep;
  362. // Sine noise beams have different length calculations
  363. if ( flags & FBEAM_SINENOISE )
  364. {
  365. length = segments * (1.0/10);
  366. noiseIndex = 0;
  367. }
  368. // UNDONE: Make this a spline instead of just a line?
  369. VectorMA( source, fraction, delta, *vecOut );
  370. // Distort using noise
  371. if ( scale != 0 )
  372. {
  373. factor = prgNoise[noiseIndex>>16] * scale;
  374. if ( flags & FBEAM_SINENOISE )
  375. {
  376. float s, c;
  377. SinCos( fraction*M_PI*length + freq, &s, &c );
  378. VectorMA( *vecOut, factor * s, MainViewUp(), *vecOut );
  379. // Rotate the noise along the perpendicular axis a bit to keep the bolt from looking diagonal
  380. VectorMA( *vecOut, factor * c, MainViewRight(), *vecOut );
  381. }
  382. else
  383. {
  384. VectorMA( *vecOut, factor, perp, *vecOut );
  385. }
  386. }
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose:
  390. // Input : noise_divisions -
  391. // *prgNoise -
  392. // *spritemodel -
  393. // frame -
  394. // rendermode -
  395. // source -
  396. // delta -
  397. // flags -
  398. // *color -
  399. // fadescale -
  400. //-----------------------------------------------------------------------------
  401. void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  402. float frame, int rendermode, const Vector& source, const Vector& delta,
  403. float startWidth, float endWidth, float scale, float freq, float speed, int segments,
  404. int flags, float* color, float fadeLength, float flHDRColorScale )
  405. {
  406. int i;
  407. float div, length, fraction, vLast, vStep, brightness;
  408. Assert( fadeLength >= 0.0f );
  409. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  410. if ( !pSprite )
  411. return;
  412. if ( segments < 2 )
  413. return;
  414. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  415. if( pMaterial )
  416. {
  417. static unsigned int nHDRColorScaleCache = 0;
  418. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  419. if( pHDRColorScaleVar )
  420. {
  421. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  422. }
  423. }
  424. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  425. segments = noise_divisions;
  426. length = VectorLength( delta ) * 0.01;
  427. div = 1.0 / (segments-1);
  428. // UNDONE: Expose texture length scale factor to control "fuzziness"
  429. vStep = length*div; // Texture length texels per space pixel
  430. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  431. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  432. brightness = 1.0;
  433. if ( flags & FBEAM_SHADEIN )
  434. brightness = 0;
  435. // What fraction of beam should be faded
  436. Assert( fadeLength >= 0.0f );
  437. float fadeFraction = fadeLength/ delta.Length();
  438. // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
  439. fadeFraction = clamp(fadeFraction,1.e-6f,1.f);
  440. Vector perp;
  441. ComputeBeamPerpendicular( delta, &perp );
  442. // Specify all the segments.
  443. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  444. CBeamSegDraw segDraw;
  445. segDraw.Start( pRenderContext, segments, NULL );
  446. // Keep track of how many times we've branched
  447. int iBranches = 0;
  448. Vector vecStart, vecEnd;
  449. float flWidth = 0;
  450. float flEndWidth = 0;
  451. for ( i = 0; i < segments; i++ )
  452. {
  453. BeamSeg_t curSeg;
  454. curSeg.m_flAlpha = 1;
  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. VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
  486. CalcSegOrigin( &curSeg.m_vPos, i, noise_divisions, prgNoise, source, delta, perp, segments, freq, scale, fraction, flags );
  487. // Specify the next segment.
  488. if( endWidth == startWidth )
  489. curSeg.m_flWidth = startWidth * 2;
  490. else
  491. curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
  492. // Reduce the width by the current number of branches we've had
  493. for ( int j = 0; j < iBranches; j++ )
  494. {
  495. curSeg.m_flWidth *= 0.5;
  496. }
  497. curSeg.m_flTexCoord = vLast;
  498. segDraw.NextSeg( &curSeg );
  499. vLast += vStep; // Advance texture scroll (v axis only)
  500. // Now see if we'd like to branch here
  501. // For now, always branch at the midpoint.
  502. // We could branch randomly, and multiple times per beam
  503. if ( i == (segments * 0.5) )
  504. {
  505. // Figure out what the new width would be
  506. // Halve the width because the beam is breaking in two, and halve it again because width is doubled above
  507. flWidth = curSeg.m_flWidth * 0.25;
  508. if ( flWidth > 1 )
  509. {
  510. iBranches++;
  511. // Get an endpoint for the new branch
  512. vecStart = curSeg.m_vPos;
  513. vecEnd = source + delta + (MainViewUp() * 32) + (MainViewRight() * 32);
  514. vecEnd -= vecStart;
  515. // Reduce the end width by the current number of branches we've had
  516. flEndWidth = endWidth;
  517. for ( int j = 0; j < iBranches; j++ )
  518. {
  519. flEndWidth *= 0.5;
  520. }
  521. }
  522. }
  523. }
  524. segDraw.End();
  525. // If we branched, draw the new beam too
  526. if ( iBranches )
  527. {
  528. DrawTeslaSegs( noise_divisions, prgNoise, spritemodel, frame, rendermode,
  529. vecStart, vecEnd, flWidth, flEndWidth, scale, freq, speed, segments,
  530. flags, color, fadeLength, flHDRColorScale );
  531. }
  532. }
  533. //-----------------------------------------------------------------------------
  534. // Purpose:
  535. // Input : noise_divisions -
  536. // *prgNoise -
  537. // *beammodel -
  538. // *halomodel -
  539. // flHaloScale -
  540. // startWidth -
  541. // endWidth -
  542. // scale -
  543. // freq -
  544. // speed -
  545. // segments -
  546. // * -
  547. //-----------------------------------------------------------------------------
  548. void DrawSplineSegs( int noise_divisions, float *prgNoise,
  549. const model_t* beammodel, const model_t* halomodel, float flHaloScale,
  550. float frame, int rendermode, int numAttachments, Vector* attachment,
  551. float startWidth, float endWidth, float scale, float freq, float speed, int segments,
  552. int flags, float* color, float fadeLength, float flHDRColorScale )
  553. {
  554. int noiseIndex, noiseStep;
  555. float div, length, fraction, factor, vLast, vStep, brightness;
  556. float scaledColor[3];
  557. model_t *beamsprite = ( model_t *)beammodel;
  558. model_t *halosprite = ( model_t *)halomodel;
  559. CEngineSprite *pBeamSprite = Draw_SetSpriteTexture( beamsprite, frame, rendermode );
  560. if ( !pBeamSprite )
  561. return;
  562. // Figure out the number of segments.
  563. if ( segments < 2 )
  564. return;
  565. IMaterial *pMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
  566. if( pMaterial )
  567. {
  568. static unsigned int nHDRColorScaleCache = 0;
  569. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  570. if( pHDRColorScaleVar )
  571. {
  572. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  573. }
  574. }
  575. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  576. segments = noise_divisions;
  577. if ( flags & FBEAM_SINENOISE )
  578. {
  579. if ( segments < 16 )
  580. segments = 16;
  581. }
  582. IMaterial *pBeamMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
  583. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  584. CBeamSegDraw segDraw;
  585. segDraw.Start( pRenderContext, (segments-1)*(numAttachments-1), pBeamMaterial );
  586. CEngineSprite *pHaloSprite = (CEngineSprite *)modelinfo->GetModelExtraData( halosprite );
  587. IMaterial *pHaloMaterial = NULL;
  588. if ( pHaloSprite )
  589. {
  590. pHaloMaterial = pHaloSprite->GetMaterial( kRenderGlow );
  591. }
  592. //-----------------------------------------------------------
  593. // Calculate widthStep if start and end width are different
  594. //-----------------------------------------------------------
  595. float widthStep;
  596. if (startWidth != endWidth)
  597. {
  598. widthStep = (endWidth - startWidth)/numAttachments;
  599. }
  600. else
  601. {
  602. widthStep = 0;
  603. }
  604. // Calculate total length of beam
  605. float flBeamLength = (attachment[0]-attachment[numAttachments-1]).Length();
  606. // What fraction of beam should be faded
  607. float fadeFraction = fadeLength/flBeamLength;
  608. if (fadeFraction > 1)
  609. {
  610. fadeFraction = 1;
  611. }
  612. //---------------------------------------------------------------
  613. // Go through each attachment drawing spline beams between them
  614. //---------------------------------------------------------------
  615. Vector vLastPoint(0,0,0);
  616. Vector pPre; // attachment point before the current beam
  617. Vector pStart; // start of current beam
  618. Vector pEnd; // end of current beam
  619. Vector pNext; // attachment point after the current beam
  620. for (int j=0;j<numAttachments-1;j++)
  621. {
  622. if (j==0)
  623. {
  624. VectorCopy(attachment[0],pPre);
  625. VectorCopy(pPre,vLastPoint);
  626. }
  627. else
  628. {
  629. VectorCopy(attachment[j-1],pPre);
  630. }
  631. VectorCopy(attachment[j], pStart);
  632. VectorCopy(attachment[j+1], pEnd);
  633. if (j+2 >= numAttachments-1)
  634. {
  635. VectorCopy(attachment[j+1],pNext);
  636. }
  637. else
  638. {
  639. VectorCopy(attachment[j+2],pNext);
  640. }
  641. Vector vDelta;
  642. VectorSubtract(pEnd,pStart,vDelta);
  643. length = VectorLength( vDelta ) * 0.01;
  644. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  645. length = 0.5;
  646. div = 1.0 / (segments-1);
  647. // UNDONE: Expose texture length scale factor to control "fuzziness"
  648. vStep = length*div; // Texture length texels per space pixel
  649. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  650. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  651. if ( flags & FBEAM_SINENOISE )
  652. {
  653. scale = scale * 100;
  654. length = segments * (1.0/10);
  655. }
  656. else
  657. scale = scale * length;
  658. // -----------------------------------------------------------------------------
  659. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  660. // -----------------------------------------------------------------------------
  661. noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
  662. noiseIndex = noiseStep;
  663. if ( flags & FBEAM_SINENOISE )
  664. noiseIndex = 0;
  665. brightness = 1.0;
  666. if ( flags & FBEAM_SHADEIN )
  667. brightness = 0;
  668. BeamSeg_t seg;
  669. seg.m_flAlpha = 1;
  670. VectorScale( color, brightness, scaledColor );
  671. seg.m_vColor.Init( scaledColor[0], scaledColor[1], scaledColor[2] );
  672. // -------------------------------------------------
  673. // Calc start and end widths for this segment
  674. // -------------------------------------------------
  675. float startSegWidth = startWidth + (widthStep*j);
  676. float endSegWidth = startWidth + (widthStep*(j+1));
  677. // -------------------------------------------------
  678. // Now draw each segment
  679. // -------------------------------------------------
  680. float fBestFraction = -1;
  681. float bestDot = 0;
  682. for (int i = 1; i < segments; i++ )
  683. {
  684. fraction = i * div;
  685. // Fade in our out beam to fadeLength
  686. // BUG BUG: should be based on total lengh of beam not this particular fraction
  687. if ( flags & FBEAM_SHADEIN )
  688. {
  689. brightness = fraction/fadeFraction;
  690. if (brightness > 1)
  691. {
  692. brightness = 1;
  693. }
  694. }
  695. else if ( flags & FBEAM_SHADEOUT )
  696. {
  697. float fadeFractionOut = fadeLength/length;
  698. brightness = 1.0 - (fraction/ fadeFractionOut);
  699. if (brightness < 0)
  700. {
  701. brightness = 0;
  702. }
  703. }
  704. // -----------------------------------------------------------
  705. // Calculate spline position
  706. // -----------------------------------------------------------
  707. Vector vTarget(0,0,0);
  708. Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fraction, vTarget );
  709. seg.m_vPos[0] = vTarget.x;
  710. seg.m_vPos[1] = vTarget.y;
  711. seg.m_vPos[2] = vTarget.z;
  712. // --------------------------------------------------------------
  713. // Keep track of segment most facing the player for halo effect
  714. // --------------------------------------------------------------
  715. if (pHaloMaterial)
  716. {
  717. Vector vBeamDir1;
  718. VectorSubtract(seg.m_vPos,vLastPoint,vBeamDir1);
  719. VectorNormalize(vBeamDir1);
  720. Vector vLookDir;
  721. VectorSubtract(CurrentViewOrigin(),seg.m_vPos,vLookDir);
  722. VectorNormalize(vLookDir);
  723. float dotpr = fabs(DotProduct(vBeamDir1,vLookDir));
  724. static float thresh = 0.85;
  725. if (dotpr > thresh && dotpr > bestDot)
  726. {
  727. bestDot = dotpr;
  728. fBestFraction = fraction;
  729. }
  730. VectorCopy(seg.m_vPos,vLastPoint);
  731. }
  732. // ----------------------
  733. // Distort using noise
  734. // ----------------------
  735. if ( scale != 0 )
  736. {
  737. factor = prgNoise[noiseIndex>>16] * scale;
  738. if ( flags & FBEAM_SINENOISE )
  739. {
  740. float s, c;
  741. SinCos( fraction*M_PI*length + freq, &s, &c );
  742. VectorMA( seg.m_vPos, factor * s, CurrentViewUp(), seg.m_vPos );
  743. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  744. VectorMA( seg.m_vPos, factor * c, CurrentViewRight(), seg.m_vPos );
  745. }
  746. else
  747. {
  748. VectorMA( seg.m_vPos, factor, CurrentViewUp(), seg.m_vPos );
  749. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  750. factor = prgNoise[noiseIndex>>16] * scale * cos(fraction*M_PI*3+freq);
  751. VectorMA( seg.m_vPos, factor, CurrentViewRight(), seg.m_vPos );
  752. }
  753. }
  754. // Scale width if non-zero spread
  755. if (startWidth != endWidth)
  756. seg.m_flWidth = ((fraction*(endSegWidth-startSegWidth))+startSegWidth)*2;
  757. else
  758. seg.m_flWidth = startWidth*2;
  759. seg.m_flTexCoord = vLast;
  760. segDraw.NextSeg( &seg );
  761. vLast += vStep; // Advance texture scroll (v axis only)
  762. noiseIndex += noiseStep;
  763. }
  764. // --------------------------------------------------------------
  765. // Draw halo on segment most facing the player
  766. // --------------------------------------------------------------
  767. if (false&&pHaloMaterial)
  768. {
  769. Vector vHaloPos(0,0,0);
  770. if (bestDot != 0)
  771. {
  772. Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fBestFraction, vHaloPos);
  773. }
  774. else
  775. {
  776. Vector vBeamDir1;
  777. VectorSubtract(pStart,pEnd,vBeamDir1);
  778. VectorNormalize(vBeamDir1);
  779. Vector vLookDir;
  780. VectorSubtract(CurrentViewOrigin(),pStart,vLookDir);
  781. VectorNormalize(vLookDir);
  782. bestDot = fabs(DotProduct(vBeamDir1,vLookDir));
  783. static float thresh = 0.85;
  784. if (bestDot > thresh)
  785. {
  786. fBestFraction = 0.5;
  787. VectorAdd(pStart,pEnd,vHaloPos);
  788. VectorScale(vHaloPos,0.5,vHaloPos);
  789. }
  790. }
  791. if (fBestFraction > 0)
  792. {
  793. float fade = pow(bestDot,60);
  794. if (fade > 1.0) fade = 1.0;
  795. float haloColor[3];
  796. VectorScale( color, fade, haloColor );
  797. pRenderContext->Bind(pHaloMaterial);
  798. float curWidth = (fBestFraction*(endSegWidth-startSegWidth))+startSegWidth;
  799. DrawHalo(pHaloMaterial,vHaloPos,flHaloScale*curWidth/endWidth,haloColor, flHDRColorScale);
  800. }
  801. }
  802. }
  803. segDraw.End();
  804. // ------------------------
  805. // Draw halo at end of beam
  806. // ------------------------
  807. if (pHaloMaterial)
  808. {
  809. pRenderContext->Bind(pHaloMaterial);
  810. DrawHalo(pHaloMaterial,pEnd,flHaloScale,scaledColor, flHDRColorScale);
  811. }
  812. }
  813. //-----------------------------------------------------------------------------
  814. // Purpose:
  815. // Input : *spritemodel -
  816. // frame -
  817. // rendermode -
  818. // source -
  819. // scale -
  820. // *color -
  821. //-----------------------------------------------------------------------------
  822. void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode,
  823. const Vector& source, float scale, float* color, float flHDRColorScale )
  824. {
  825. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  826. if ( !pSprite )
  827. return;
  828. DrawHalo( pSprite->GetMaterial( (RenderMode_t)rendermode ), source, scale, color, flHDRColorScale );
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose:
  832. // Input : noise_divisions -
  833. // *prgNoise -
  834. // *spritemodel -
  835. // frame -
  836. // rendermode -
  837. // source -
  838. // delta -
  839. // width -
  840. // scale -
  841. // freq -
  842. // speed -
  843. // segments -
  844. // *color -
  845. //-----------------------------------------------------------------------------
  846. void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  847. float frame, int rendermode, const Vector& source, const Vector& delta,
  848. float width, float scale, float freq, float speed, int segments, float* color, float flHDRColorScale )
  849. {
  850. int i;
  851. float div, length, fraction, vLast, vStep;
  852. Vector point;
  853. float w;
  854. static unsigned int nHDRColorScaleCache = 0;
  855. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  856. if ( !pSprite )
  857. return;
  858. if ( segments < 2 )
  859. return;
  860. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  861. if( pMaterial )
  862. {
  863. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  864. if( pHDRColorScaleVar )
  865. {
  866. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  867. }
  868. }
  869. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  870. segments = noise_divisions;
  871. length = VectorLength( delta ) * 0.01;
  872. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  873. length = 0.5;
  874. div = 1.0 / (segments-1);
  875. // UNDONE: Expose texture length scale factor to control "fuzziness"
  876. vStep = length*div; // Texture length texels per space pixel
  877. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  878. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  879. scale = scale * length;
  880. w = freq * delta[2];
  881. CMatRenderContextPtr pRenderContext( materials );
  882. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  883. CMeshBuilder meshBuilder;
  884. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
  885. // NOTE: We must force the degenerate triangles to be on the edge
  886. for ( i = 0; i < segments; i++ )
  887. {
  888. float s, c;
  889. fraction = i * div;
  890. point[0] = source[0];
  891. point[1] = source[1];
  892. point[2] = source[2];
  893. meshBuilder.Color3fv( color );
  894. meshBuilder.TexCoord2f( 0, 1.0, vLast );
  895. meshBuilder.Position3fv( point.Base() );
  896. meshBuilder.AdvanceVertex();
  897. SinCos( fraction * 2 * M_PI, &s, &c );
  898. point[0] = s * w + source[0];
  899. point[1] = c * w + source[1];
  900. point[2] = source[2];
  901. meshBuilder.Color3fv( color );
  902. meshBuilder.TexCoord2f( 0, 0.0, vLast );
  903. meshBuilder.Position3fv( point.Base() );
  904. meshBuilder.AdvanceVertex();
  905. vLast += vStep; // Advance texture scroll (v axis only)
  906. }
  907. meshBuilder.End( );
  908. pMesh->Draw();
  909. }
  910. //-----------------------------------------------------------------------------
  911. // Purpose:
  912. // Input : noise_divisions -
  913. // *prgNoise -
  914. // *spritemodel -
  915. // frame -
  916. // rendermode -
  917. // source -
  918. // delta -
  919. // width -
  920. // scale -
  921. // freq -
  922. // speed -
  923. // segments -
  924. // *color -
  925. //-----------------------------------------------------------------------------
  926. void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel,
  927. float frame, int rendermode, const Vector& source, const Vector& delta,
  928. float width, float scale, float freq, float speed, int segments,
  929. float* color, float flHDRColorScale )
  930. {
  931. int i;
  932. float div, length, fraction, vLast, vStep;
  933. Vector point;
  934. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  935. if ( !pSprite )
  936. return;
  937. if ( segments < 2 )
  938. return;
  939. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  940. if( pMaterial )
  941. {
  942. static unsigned int nHDRColorScaleCache = 0;
  943. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  944. if( pHDRColorScaleVar )
  945. {
  946. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  947. }
  948. }
  949. if ( segments > noise_divisions ) // UNDONE: Allow more segments?
  950. segments = noise_divisions;
  951. length = VectorLength( delta ) * 0.01;
  952. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  953. length = 0.5;
  954. div = 1.0 / (segments-1);
  955. // UNDONE: Expose texture length scale factor to control "fuzziness"
  956. vStep = length*div; // Texture length texels per space pixel
  957. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  958. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  959. scale = scale * length;
  960. CMatRenderContextPtr pRenderContext( materials );
  961. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  962. CMeshBuilder meshBuilder;
  963. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
  964. float radius = delta[2];
  965. for ( i = 0; i < segments; i++ )
  966. {
  967. float s, c;
  968. fraction = i * div;
  969. SinCos( fraction * 2 * M_PI, &s, &c );
  970. point[0] = s * freq * radius + source[0];
  971. point[1] = c * freq * radius + source[1];
  972. point[2] = source[2] + width;
  973. meshBuilder.Color3f( 0.0f, 0.0f, 0.0f );
  974. meshBuilder.TexCoord2f( 0, 1.0f, vLast );
  975. meshBuilder.Position3fv( point.Base() );
  976. meshBuilder.AdvanceVertex();
  977. point[0] = s * freq * (radius + width) + source[0];
  978. point[1] = c * freq * (radius + width) + source[1];
  979. point[2] = source[2] - width;
  980. meshBuilder.Color3fv( color );
  981. meshBuilder.TexCoord2f( 0, 0.0f, vLast );
  982. meshBuilder.Position3fv( point.Base() );
  983. meshBuilder.AdvanceVertex();
  984. vLast += vStep; // Advance texture scroll (v axis only)
  985. }
  986. meshBuilder.End();
  987. pMesh->Draw();
  988. }
  989. //-----------------------------------------------------------------------------
  990. // Purpose:
  991. // Input : noise_divisions -
  992. // *prgNoise -
  993. // (*pfnNoise -
  994. //-----------------------------------------------------------------------------
  995. void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ),
  996. const model_t* spritemodel, float frame, int rendermode,
  997. const Vector& source, const Vector& delta, float width,
  998. float amplitude, float freq, float speed, int segments, float *color, float flHDRColorScale )
  999. {
  1000. int i, j, noiseIndex, noiseStep;
  1001. float div, length, fraction, factor, vLast, vStep;
  1002. Vector last1, last2, point, screen, screenLast(0,0,0), tmp, normal;
  1003. Vector center, xaxis, yaxis, zaxis;
  1004. float radius, x, y, scale;
  1005. Vector d;
  1006. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  1007. if ( !pSprite )
  1008. return;
  1009. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  1010. if( pMaterial )
  1011. {
  1012. static unsigned int nHDRColorScaleCache = 0;
  1013. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  1014. if( pHDRColorScaleVar )
  1015. {
  1016. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  1017. }
  1018. }
  1019. VectorCopy( delta, d );
  1020. if ( segments < 2 )
  1021. return;
  1022. segments = segments * M_PI;
  1023. if ( segments > noise_divisions * 8 ) // UNDONE: Allow more segments?
  1024. segments = noise_divisions * 8;
  1025. length = VectorLength( d ) * 0.01 * M_PI;
  1026. if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
  1027. length = 0.5;
  1028. div = 1.0 / (segments-1);
  1029. // UNDONE: Expose texture length scale factor to control "fuzziness"
  1030. vStep = length*div/8.0; // Texture length texels per space pixel
  1031. // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
  1032. vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
  1033. scale = amplitude * length / 8.0;
  1034. // Iterator to resample noise waveform (it needs to be generated in powers of 2)
  1035. noiseStep = (int)((noise_divisions-1) * div * 65536.0) * 8;
  1036. noiseIndex = 0;
  1037. VectorScale( d, 0.5, d );
  1038. VectorAdd( source, d, center );
  1039. zaxis[0] = 0; zaxis[1] = 0; zaxis[2] = 1;
  1040. VectorCopy( d, xaxis );
  1041. radius = VectorLength( xaxis );
  1042. // cull beamring
  1043. // --------------------------------
  1044. // Compute box center +/- radius
  1045. last1[0] = radius;
  1046. last1[1] = radius;
  1047. last1[2] = scale;
  1048. VectorAdd( center, last1, tmp ); // maxs
  1049. VectorSubtract( center, last1, screen ); // mins
  1050. // Is that box in PVS && frustum?
  1051. if ( !engine->IsBoxVisible( screen, tmp ) || engine->CullBox( screen, tmp ) )
  1052. {
  1053. return;
  1054. }
  1055. yaxis[0] = xaxis[1]; yaxis[1] = -xaxis[0]; yaxis[2] = 0;
  1056. VectorNormalize( yaxis );
  1057. VectorScale( yaxis, radius, yaxis );
  1058. j = segments / 8;
  1059. CMatRenderContextPtr pRenderContext( materials );
  1060. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  1061. CMeshBuilder meshBuilder;
  1062. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments) * 2 );
  1063. for ( i = 0; i < segments + 1; i++ )
  1064. {
  1065. fraction = i * div;
  1066. SinCos( fraction * 2 * M_PI, &x, &y );
  1067. point[0] = xaxis[0] * x + yaxis[0] * y + center[0];
  1068. point[1] = xaxis[1] * x + yaxis[1] * y + center[1];
  1069. point[2] = xaxis[2] * x + yaxis[2] * y + center[2];
  1070. // Distort using noise
  1071. if ( scale != 0.0f )
  1072. {
  1073. factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale;
  1074. VectorMA( point, factor, CurrentViewUp(), point );
  1075. // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
  1076. factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale * cos(fraction*M_PI*3*8+freq);
  1077. VectorMA( point, factor, CurrentViewRight(), point );
  1078. }
  1079. // Transform point into screen space
  1080. ScreenTransform( point, screen );
  1081. if (i != 0)
  1082. {
  1083. // Build world-space normal to screen-space direction vector
  1084. VectorSubtract( screen, screenLast, tmp );
  1085. // We don't need Z, we're in screen space
  1086. tmp[2] = 0;
  1087. VectorNormalize( tmp );
  1088. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1089. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1090. // Make a wide line
  1091. VectorMA( point, width, normal, last1 );
  1092. VectorMA( point, -width, normal, last2 );
  1093. vLast += vStep; // Advance texture scroll (v axis only)
  1094. meshBuilder.Color3fv( color );
  1095. meshBuilder.TexCoord2f( 0, 1.0f, vLast );
  1096. meshBuilder.Position3fv( last2.Base() );
  1097. meshBuilder.AdvanceVertex();
  1098. meshBuilder.Color3fv( color );
  1099. meshBuilder.TexCoord2f( 0, 0.0f, vLast );
  1100. meshBuilder.Position3fv( last1.Base() );
  1101. meshBuilder.AdvanceVertex();
  1102. }
  1103. VectorCopy( screen, screenLast );
  1104. noiseIndex += noiseStep;
  1105. j--;
  1106. if (j == 0 && amplitude != 0 )
  1107. {
  1108. j = segments / 8;
  1109. (*pfnNoise)( prgNoise, noise_divisions, 1.0f );
  1110. }
  1111. }
  1112. meshBuilder.End();
  1113. pMesh->Draw();
  1114. }
  1115. //-----------------------------------------------------------------------------
  1116. // Purpose:
  1117. // Input : spritemodel -
  1118. // *pHead -
  1119. // delta -
  1120. // *screen -
  1121. // *screenLast -
  1122. // die -
  1123. // source -
  1124. // flags -
  1125. // width -
  1126. // amplitude -
  1127. // freq -
  1128. // *color -
  1129. //-----------------------------------------------------------------------------
  1130. void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode,
  1131. Vector& delta, Vector& screen, Vector& screenLast, float die,
  1132. const Vector& source, int flags, float width, float amplitude,
  1133. float freq, float* color, float flHDRColorScale )
  1134. {
  1135. float fraction;
  1136. float div;
  1137. float vLast = 0.0;
  1138. float vStep = 1.0;
  1139. Vector last1, last2, tmp, normal;
  1140. float scaledColor[3];
  1141. CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
  1142. if ( !pSprite )
  1143. return;
  1144. IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
  1145. if( pMaterial )
  1146. {
  1147. static unsigned int nHDRColorScaleCache = 0;
  1148. IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  1149. if( pHDRColorScaleVar )
  1150. {
  1151. pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
  1152. }
  1153. }
  1154. // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the
  1155. // first beam segment for this trail
  1156. // Build world-space normal to screen-space direction vector
  1157. VectorSubtract( screen, screenLast, tmp );
  1158. // We don't need Z, we're in screen space
  1159. tmp[2] = 0;
  1160. VectorNormalize( tmp );
  1161. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1162. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1163. // Make a wide line
  1164. VectorMA( delta, width, normal, last1 );
  1165. VectorMA( delta, -width, normal, last2 );
  1166. div = 1.0 / amplitude;
  1167. fraction = ( die - gpGlobals->curtime ) * div;
  1168. unsigned char nColor[3];
  1169. VectorScale( color, fraction, scaledColor );
  1170. nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
  1171. nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
  1172. nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
  1173. // need to count the segments
  1174. int count = 0;
  1175. BeamTrail_t* pTraverse = pHead;
  1176. while ( pTraverse )
  1177. {
  1178. ++count;
  1179. pTraverse = pTraverse->next;
  1180. }
  1181. CMatRenderContextPtr pRenderContext( materials );
  1182. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  1183. CMeshBuilder meshBuilder;
  1184. meshBuilder.Begin( pMesh, MATERIAL_QUADS, count );
  1185. while (pHead)
  1186. {
  1187. // Msg("%.2f ", fraction );
  1188. meshBuilder.Position3fv( last1.Base() );
  1189. meshBuilder.Color3ubv( nColor );
  1190. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1191. meshBuilder.AdvanceVertex();
  1192. meshBuilder.Position3fv( last2.Base() );
  1193. meshBuilder.Color3ubv( nColor );
  1194. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  1195. meshBuilder.AdvanceVertex();
  1196. // Transform point into screen space
  1197. ScreenTransform( pHead->org, screen );
  1198. // Build world-space normal to screen-space direction vector
  1199. VectorSubtract( screen, screenLast, tmp );
  1200. // We don't need Z, we're in screen space
  1201. tmp[2] = 0;
  1202. VectorNormalize( tmp );
  1203. VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
  1204. VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
  1205. // Make a wide line
  1206. VectorMA( pHead->org, width, normal, last1 );
  1207. VectorMA( pHead->org, -width, normal, last2 );
  1208. vLast += vStep; // Advance texture scroll (v axis only)
  1209. if (pHead->next != NULL)
  1210. {
  1211. fraction = (pHead->die - gpGlobals->curtime) * div;
  1212. VectorScale( color, fraction, scaledColor );
  1213. nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
  1214. nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
  1215. nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
  1216. }
  1217. else
  1218. {
  1219. fraction = 0.0;
  1220. nColor[0] = nColor[1] = nColor[2] = 0;
  1221. }
  1222. meshBuilder.Position3fv( last2.Base() );
  1223. meshBuilder.Color3ubv( nColor );
  1224. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  1225. meshBuilder.AdvanceVertex();
  1226. meshBuilder.Position3fv( last1.Base() );
  1227. meshBuilder.Color3ubv( nColor );
  1228. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  1229. meshBuilder.AdvanceVertex();
  1230. VectorCopy( screen, screenLast );
  1231. pHead = pHead->next;
  1232. }
  1233. meshBuilder.End();
  1234. pMesh->Draw();
  1235. }
  1236. /*
  1237. P0 = start
  1238. P1 = control
  1239. P2 = end
  1240. P(t) = (1-t)^2 * P0 + 2t(1-t)*P1 + t^2 * P2
  1241. */
  1242. void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale )
  1243. {
  1244. int subdivisions = 16;
  1245. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1246. CBeamSegDraw beamDraw;
  1247. beamDraw.Start( pRenderContext, subdivisions+1, NULL );
  1248. BeamSeg_t seg;
  1249. seg.m_flAlpha = 1.0;
  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_vColor = vec3_origin;
  1266. }
  1267. else
  1268. {
  1269. seg.m_vColor = color;
  1270. }
  1271. beamDraw.NextSeg( &seg );
  1272. }
  1273. beamDraw.End();
  1274. }