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.

2272 lines
63 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include "iviewrender_beams.h"
  10. #include "tempentity.h"
  11. #include "beam_shared.h"
  12. #include "ivieweffects.h"
  13. #include "beamdraw.h"
  14. #include "engine/ivdebugoverlay.h"
  15. #include "engine/ivmodelinfo.h"
  16. #include "view.h"
  17. #include "fx.h"
  18. #include "tier0/icommandline.h"
  19. #include "tier0/vprof.h"
  20. #include "c_pixel_visibility.h"
  21. #include "iviewrender.h"
  22. #include "view_shared.h"
  23. #include "viewrender.h"
  24. ConVar r_DrawBeams( "r_DrawBeams", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" );
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. bool g_BeamCreationAllowed = false;
  28. //-----------------------------------------------------------------------------
  29. // Purpose:
  30. // Input : state -
  31. //-----------------------------------------------------------------------------
  32. void SetBeamCreationAllowed( bool state )
  33. {
  34. g_BeamCreationAllowed = state;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. // Output : Returns true on success, false on failure.
  39. //-----------------------------------------------------------------------------
  40. bool BeamCreationAllowed( void )
  41. {
  42. return g_BeamCreationAllowed;
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Purpose: Implements beam rendering apis
  46. //-----------------------------------------------------------------------------
  47. class CViewRenderBeams : public IViewRenderBeams
  48. {
  49. // Construction
  50. public:
  51. CViewRenderBeams( void );
  52. virtual ~CViewRenderBeams( void );
  53. // Implement IViewRenderBeams
  54. public:
  55. virtual void InitBeams( void );
  56. virtual void ShutdownBeams( void );
  57. virtual void ClearBeams( void );
  58. // Updates the state of the temp ent beams
  59. virtual void UpdateTempEntBeams();
  60. virtual void DrawBeam( C_Beam* pbeam, const RenderableInstance_t &instance, ITraceFilter *pEntityBeamTraceFilter = NULL );
  61. virtual void DrawBeam( Beam_t *pbeam );
  62. virtual void KillDeadBeams( C_BaseEntity *pDeadEntity );
  63. virtual Beam_t *CreateBeamEnts( BeamInfo_t &beamInfo );
  64. virtual Beam_t *CreateBeamEntPoint( BeamInfo_t &beamInfo );
  65. virtual Beam_t *CreateBeamPoints( BeamInfo_t &beamInfo );
  66. virtual Beam_t *CreateBeamRing( BeamInfo_t &beamInfo );
  67. virtual Beam_t *CreateBeamRingPoint( BeamInfo_t &beamInfo );
  68. virtual Beam_t *CreateBeamCirclePoints( BeamInfo_t &beamInfo );
  69. virtual Beam_t *CreateBeamFollow( BeamInfo_t &beamInfo );
  70. virtual void CreateBeamEnts( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale,
  71. float life, float width, float endWidth, float fadeLength, float amplitude,
  72. float brightness, float speed, int startFrame,
  73. float framerate, float r, float g, float b, int type = -1 );
  74. virtual void CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, const Vector* pEnd,
  75. int modelIndex, int haloIndex, float haloScale,
  76. float life, float width, float endWidth, float fadeLength, float amplitude,
  77. float brightness, float speed, int startFrame,
  78. float framerate, float r, float g, float b );
  79. virtual void CreateBeamPoints( Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale,
  80. float life, float width, float endWidth, float fadeLength, float amplitude,
  81. float brightness, float speed, int startFrame,
  82. float framerate, float r, float g, float b );
  83. virtual void CreateBeamRing( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale,
  84. float life, float width, float endWidth, float fadeLength, float amplitude,
  85. float brightness, float speed, int startFrame,
  86. float framerate, float r, float g, float b, int flags );
  87. virtual void CreateBeamRingPoint( const Vector& center, float start_radius, float end_radius, int modelIndex, int haloIndex, float haloScale,
  88. float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude,
  89. float brightness, float speed, int startFrame,
  90. float framerate, float r, float g, float b, int flags );
  91. virtual void CreateBeamCirclePoints( int type, Vector& start, Vector& end,
  92. int modelIndex, int haloIndex, float haloScale, float life, float width,
  93. float endWidth, float fadeLength, float amplitude, float brightness, float speed,
  94. int startFrame, float framerate, float r, float g, float b );
  95. virtual void CreateBeamFollow( int startEnt, int modelIndex, int haloIndex, float haloScale,
  96. float life, float width, float endWidth, float fadeLength, float r, float g, float b,
  97. float brightness );
  98. virtual void FreeBeam( Beam_t *pBeam ) { BeamFree( pBeam ); }
  99. virtual void UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo );
  100. private:
  101. void FreeDeadTrails( BeamTrail_t **trail );
  102. void UpdateBeam( Beam_t *pbeam, float frametime, C_Beam *pcbeam = NULL );
  103. void DrawBeamWithHalo( Beam_t* pbeam,int frame,int rendermode,float *color, float *srcColor, const model_t *sprite,const model_t *halosprite, float flHDRColorScale );
  104. void DrawBeamFollow( const model_t* pSprite, Beam_t *pbeam, int frame, int rendermode, float frametime, const float* color, float flHDRColorScale = 1.0f );
  105. void DrawLaser( Beam_t* pBeam, int frame, int rendermode, float* color, model_t const* sprite, model_t const* halosprite, float flHDRColorScale = 1.0f );
  106. void DrawTesla( Beam_t* pBeam, int frame, int rendermode, float* color, model_t const* sprite, float flHDRColorScale = 1.0f );
  107. bool RecomputeBeamEndpoints( Beam_t *pbeam );
  108. int CullBeam( const Vector &start, const Vector &end, int pvsOnly );
  109. // special case clipping to geometry behavior
  110. void ClipBeam( C_Beam *pcbeam, Beam_t *pbeamt );
  111. // Creation
  112. Beam_t *CreateGenericBeam( BeamInfo_t &beamInfo );
  113. void SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo );
  114. void SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo );
  115. // Memory Alloc/Free
  116. Beam_t* BeamAlloc( bool bRenderable );
  117. void BeamFree( Beam_t* pBeam );
  118. // DATA
  119. private:
  120. enum
  121. {
  122. // default max # of particles at one time
  123. DEFAULT_PARTICLES = 2048,
  124. // no fewer than this no matter what's on the command line
  125. MIN_PARTICLES = 512,
  126. // Maximum length of the free list.
  127. BEAM_FREELIST_MAX = 32
  128. };
  129. Beam_t *m_pActiveBeams;
  130. Beam_t *m_pFreeBeams;
  131. int m_nBeamFreeListLength;
  132. BeamTrail_t *m_pBeamTrails;
  133. BeamTrail_t *m_pActiveTrails;
  134. BeamTrail_t *m_pFreeTrails;
  135. int m_nNumBeamTrails;
  136. };
  137. // Expose interface to rest of client .dll
  138. static CViewRenderBeams s_ViewRenderBeams;
  139. IViewRenderBeams *beams = ( IViewRenderBeams * )&s_ViewRenderBeams;
  140. CUniformRandomStream beamRandom;
  141. //-----------------------------------------------------------------------------
  142. // Global methods
  143. //-----------------------------------------------------------------------------
  144. // freq2 += step * 0.1;
  145. // Fractal noise generator, power of 2 wavelength
  146. static void Noise( float *noise, int divs, float scale )
  147. {
  148. int div2;
  149. div2 = divs >> 1;
  150. if ( divs < 2 )
  151. return;
  152. // Noise is normalized to +/- scale
  153. noise[ div2 ] = (noise[0] + noise[divs]) * 0.5 + scale * beamRandom.RandomFloat(-1, 1);
  154. if ( div2 > 1 )
  155. {
  156. Noise( &noise[div2], div2, scale * 0.5 );
  157. Noise( noise, div2, scale * 0.5 );
  158. }
  159. }
  160. static void SineNoise( float *noise, int divs )
  161. {
  162. int i;
  163. float freq;
  164. float step = M_PI / (float)divs;
  165. freq = 0;
  166. for ( i = 0; i < divs; i++ )
  167. {
  168. noise[i] = sin( freq );
  169. freq += step;
  170. }
  171. }
  172. bool ComputeBeamEntPosition( C_BaseEntity *pEnt, int nAttachment, bool bInterpretAttachmentIndexAsHitboxIndex, Vector& pt )
  173. {
  174. // NOTE: This will *leave* the pt at its current value, essential for
  175. // beam follow ents what want to stick around a little after their ent has died
  176. if (!pEnt)
  177. return false;
  178. if ( !bInterpretAttachmentIndexAsHitboxIndex )
  179. {
  180. if ( pEnt->GetAttachment( nAttachment, pt ) )
  181. return true;
  182. }
  183. else
  184. {
  185. C_BaseAnimating *pAnimating = pEnt->GetBaseAnimating();
  186. if ( pAnimating )
  187. {
  188. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  189. if (pStudioHdr)
  190. {
  191. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
  192. if ( set && (set->numhitboxes >= nAttachment) && (nAttachment > 0) )
  193. {
  194. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  195. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  196. {
  197. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  198. mstudiobbox_t *pHitbox = set->pHitbox( nAttachment - 1 );
  199. Vector vecViewPt = MainViewOrigin(nSlot);
  200. Vector vecLocalViewPt;
  201. VectorITransform( vecViewPt, *hitboxbones[ pHitbox->bone ], vecLocalViewPt );
  202. Vector vecLocalClosestPt;
  203. CalcClosestPointOnAABB( pHitbox->bbmin, pHitbox->bbmax, vecLocalViewPt, vecLocalClosestPt );
  204. VectorTransform( vecLocalClosestPt, *hitboxbones[ pHitbox->bone ], pt );
  205. // MatrixGetColumn( *hitboxbones[ pHitbox->bone ], 3, pt );
  206. return true;
  207. }
  208. }
  209. }
  210. }
  211. }
  212. // Player origins are at their feet
  213. if ( pEnt->IsPlayer() )
  214. {
  215. pt = pEnt->WorldSpaceCenter();
  216. }
  217. else
  218. {
  219. VectorCopy( pEnt->GetRenderOrigin(), pt );
  220. }
  221. return true;
  222. }
  223. //-----------------------------------------------------------------------------
  224. //
  225. // Methods of Beam_t
  226. //
  227. //-----------------------------------------------------------------------------
  228. Beam_t::Beam_t()
  229. {
  230. Reset();
  231. }
  232. void Beam_t::Reset()
  233. {
  234. m_Mins.Init(0,0,0);
  235. m_Maxs.Init(0,0,0);
  236. type = 0;
  237. flags = 0;
  238. trail = 0;
  239. m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE;
  240. m_bCalculatedNoise = false;
  241. m_queryHandleHalo = NULL;
  242. m_flHDRColorScale = 1.0f;
  243. }
  244. const Vector& Beam_t::GetRenderOrigin( void )
  245. {
  246. if ((type == TE_BEAMRING) || (type == TE_BEAMRINGPOINT))
  247. {
  248. // return the center of the ring
  249. static Vector org;
  250. VectorMA( attachment[0], 0.5f, delta, org );
  251. return org;
  252. }
  253. return attachment[0];
  254. }
  255. const QAngle& Beam_t::GetRenderAngles( void )
  256. {
  257. return vec3_angle;
  258. }
  259. const matrix3x4_t &Beam_t::RenderableToWorldTransform()
  260. {
  261. static matrix3x4_t mat;
  262. SetIdentityMatrix( mat );
  263. PositionMatrix( GetRenderOrigin(), mat );
  264. return mat;
  265. }
  266. void Beam_t::GetRenderBounds( Vector& mins, Vector& maxs )
  267. {
  268. VectorCopy( m_Mins, mins );
  269. VectorCopy( m_Maxs, maxs );
  270. }
  271. void Beam_t::ComputeBounds( )
  272. {
  273. switch( type )
  274. {
  275. case TE_BEAMSPLINE:
  276. {
  277. // Here, we gotta look at all the attachments....
  278. Vector attachmentDelta;
  279. m_Mins.Init( 0,0,0 );
  280. m_Maxs.Init( 0,0,0 );
  281. for (int i=1; i < numAttachments; i++)
  282. {
  283. VectorSubtract( attachment[i], attachment[0], attachmentDelta );
  284. m_Mins = m_Mins.Min( attachmentDelta );
  285. m_Maxs = m_Maxs.Max( attachmentDelta );
  286. }
  287. }
  288. break;
  289. case TE_BEAMDISK:
  290. case TE_BEAMCYLINDER:
  291. {
  292. // FIXME: This isn't quite right for the cylinder
  293. // Here, delta[2] is the radius
  294. int radius = delta[2];
  295. m_Mins.Init( -radius, -radius, -radius );
  296. m_Maxs.Init( radius, radius, radius );
  297. }
  298. break;
  299. case TE_BEAMRING:
  300. case TE_BEAMRINGPOINT:
  301. {
  302. int radius = delta.Length() * 0.5f;
  303. m_Mins.Init( -radius, -radius, -radius );
  304. m_Maxs.Init( radius, radius, radius );
  305. }
  306. break;
  307. case TE_BEAMPOINTS:
  308. default:
  309. {
  310. // Just use the delta
  311. for (int i = 0; i < 3; ++i)
  312. {
  313. if (delta[i] > 0.0f)
  314. {
  315. m_Mins[i] = 0.0f;
  316. m_Maxs[i] = delta[i];
  317. }
  318. else
  319. {
  320. m_Mins[i] = delta[i];
  321. m_Maxs[i] = 0.0f;
  322. }
  323. }
  324. }
  325. break;
  326. }
  327. // Deal with beam follow
  328. Vector org = GetRenderOrigin();
  329. Vector followDelta;
  330. BeamTrail_t* pFollow = trail;
  331. while (pFollow)
  332. {
  333. VectorSubtract( pFollow->org, org, followDelta );
  334. m_Mins = m_Mins.Min( followDelta );
  335. m_Maxs = m_Maxs.Max( followDelta );
  336. pFollow = pFollow->next;
  337. }
  338. }
  339. bool Beam_t::ShouldDraw( void )
  340. {
  341. return true;
  342. }
  343. extern bool g_bRenderingScreenshot;
  344. extern ConVar r_drawviewmodel;
  345. int Beam_t::DrawModel( int flags, const RenderableInstance_t &instance )
  346. {
  347. // Tracker 16432: If rendering a savegame screenshot don't draw beams
  348. // who have viewmodels as their attached entity
  349. if ( g_bRenderingScreenshot || !r_drawviewmodel.GetBool() )
  350. {
  351. // If the beam is attached
  352. for (int i=0;i<MAX_BEAM_ENTS;i++)
  353. {
  354. C_BaseViewModel *vm = ToBaseViewModel(entity[i].Get());
  355. if ( vm )
  356. {
  357. return 0;
  358. }
  359. }
  360. }
  361. s_ViewRenderBeams.DrawBeam( this );
  362. return 0;
  363. }
  364. //-----------------------------------------------------------------------------
  365. //
  366. // Implementation of CViewRenderBeams
  367. //
  368. //-----------------------------------------------------------------------------
  369. //-----------------------------------------------------------------------------
  370. // Constructor, destructor:
  371. //-----------------------------------------------------------------------------
  372. CViewRenderBeams::CViewRenderBeams( void ) : m_pBeamTrails(0)
  373. {
  374. m_pFreeBeams = NULL;
  375. m_pActiveBeams = NULL;
  376. m_nBeamFreeListLength = 0;
  377. }
  378. CViewRenderBeams::~CViewRenderBeams( void )
  379. {
  380. ClearBeams();
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose: Initialize beam system and beam trails for follow beams
  384. //-----------------------------------------------------------------------------
  385. void CViewRenderBeams::InitBeams( void )
  386. {
  387. int p = CommandLine()->ParmValue("-particles", -1);
  388. if ( p >= 0 )
  389. {
  390. m_nNumBeamTrails = MAX( p, MIN_PARTICLES );
  391. }
  392. else
  393. {
  394. m_nNumBeamTrails = DEFAULT_PARTICLES;
  395. }
  396. m_pBeamTrails = (BeamTrail_t *)new BeamTrail_t[ m_nNumBeamTrails ];
  397. Assert( m_pBeamTrails );
  398. // Clear them out
  399. ClearBeams();
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Purpose: Clear out all beams
  403. //-----------------------------------------------------------------------------
  404. void CViewRenderBeams::ClearBeams( void )
  405. {
  406. Beam_t *next = NULL;
  407. for( ; m_pActiveBeams; m_pActiveBeams = next )
  408. {
  409. next = m_pActiveBeams->next;
  410. delete m_pActiveBeams;
  411. }
  412. for( ; m_pFreeBeams; m_pFreeBeams = next )
  413. {
  414. next = m_pFreeBeams->next;
  415. delete m_pFreeBeams;
  416. }
  417. m_nBeamFreeListLength = 0;
  418. if ( m_nNumBeamTrails )
  419. {
  420. // Also clear any particles used by beams
  421. m_pFreeTrails = &m_pBeamTrails[0];
  422. m_pActiveTrails = NULL;
  423. for (int i=0 ;i<m_nNumBeamTrails ; i++)
  424. {
  425. m_pBeamTrails[i].next = &m_pBeamTrails[i+1];
  426. }
  427. m_pBeamTrails[m_nNumBeamTrails-1].next = NULL;
  428. }
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose: Shut down beam system
  432. //-----------------------------------------------------------------------------
  433. void CViewRenderBeams::ShutdownBeams( void )
  434. {
  435. if (m_pBeamTrails)
  436. {
  437. delete[] m_pBeamTrails;
  438. m_pActiveTrails = NULL;
  439. m_pBeamTrails = NULL;
  440. m_pFreeTrails = NULL;
  441. m_nNumBeamTrails = 0;
  442. }
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose: Try and allocate a free beam
  446. // Output : Beam_t
  447. //-----------------------------------------------------------------------------
  448. Beam_t *CViewRenderBeams::BeamAlloc( bool bRenderable )
  449. {
  450. Beam_t* pBeam = NULL;
  451. if ( m_pFreeBeams )
  452. {
  453. pBeam = m_pFreeBeams;
  454. m_pFreeBeams = pBeam->next;
  455. m_nBeamFreeListLength--;
  456. }
  457. else
  458. {
  459. pBeam = new Beam_t();
  460. if( !pBeam )
  461. {
  462. DevMsg( "ERROR: failed to alloc Beam_t!\n" );
  463. Assert( pBeam );
  464. }
  465. }
  466. pBeam->next = m_pActiveBeams;
  467. m_pActiveBeams = pBeam;
  468. if ( bRenderable )
  469. {
  470. // Hook it into the rendering system...
  471. ClientLeafSystem()->AddRenderable( pBeam, false, RENDERABLE_IS_TRANSLUCENT, RENDERABLE_MODEL_ENTITY );
  472. }
  473. else
  474. {
  475. pBeam->m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE;
  476. }
  477. return pBeam;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose: Free the beam.
  481. //-----------------------------------------------------------------------------
  482. void CViewRenderBeams::BeamFree( Beam_t* pBeam )
  483. {
  484. // Free particles that have died off.
  485. FreeDeadTrails( &pBeam->trail );
  486. // Remove it from the rendering system...
  487. ClientLeafSystem()->RemoveRenderable( pBeam->m_hRenderHandle );
  488. // Clear us out
  489. pBeam->Reset();
  490. if( m_nBeamFreeListLength < BEAM_FREELIST_MAX )
  491. {
  492. m_nBeamFreeListLength++;
  493. // Now link into free list;
  494. pBeam->next = m_pFreeBeams;
  495. m_pFreeBeams = pBeam;
  496. }
  497. else
  498. {
  499. delete pBeam;
  500. }
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose: Iterates through active list and kills beams associated with deadEntity
  504. // Input : deadEntity -
  505. //-----------------------------------------------------------------------------
  506. void CViewRenderBeams::KillDeadBeams( C_BaseEntity *pDeadEntity )
  507. {
  508. Beam_t *pbeam;
  509. Beam_t *pnewlist;
  510. Beam_t *pnext;
  511. BeamTrail_t *pHead; // Build a new list to replace m_pActiveBeams.
  512. pbeam = m_pActiveBeams; // Old list.
  513. pnewlist = NULL; // New list.
  514. while (pbeam)
  515. {
  516. pnext = pbeam->next;
  517. if (pbeam->entity[0] != pDeadEntity ) // Link into new list.
  518. {
  519. pbeam->next = pnewlist;
  520. pnewlist = pbeam;
  521. pbeam = pnext;
  522. continue;
  523. }
  524. pbeam->flags &= ~(FBEAM_STARTENTITY | FBEAM_ENDENTITY);
  525. if ( pbeam->type != TE_BEAMFOLLOW )
  526. {
  527. // Die Die Die!
  528. pbeam->die = gpGlobals->curtime - 0.1;
  529. // Kill off particles
  530. pHead = pbeam->trail;
  531. while (pHead)
  532. {
  533. pHead->die = gpGlobals->curtime - 0.1;
  534. pHead = pHead->next;
  535. }
  536. // Free the beam
  537. BeamFree( pbeam );
  538. }
  539. else
  540. {
  541. // Stay active
  542. pbeam->next = pnewlist;
  543. pnewlist = pbeam;
  544. }
  545. pbeam = pnext;
  546. }
  547. // We now have a new list with the bogus stuff released.
  548. m_pActiveBeams = pnewlist;
  549. }
  550. //-----------------------------------------------------------------------------
  551. // Purpose: Fill in values to beam structure.
  552. // Input: pBeam -
  553. // beamInfo -
  554. //-----------------------------------------------------------------------------
  555. void CViewRenderBeams::SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo )
  556. {
  557. const model_t *pSprite = modelinfo->GetModel( beamInfo.m_nModelIndex );
  558. if ( !pSprite )
  559. return;
  560. pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType;
  561. pBeam->modelIndex = beamInfo.m_nModelIndex;
  562. pBeam->haloIndex = beamInfo.m_nHaloIndex;
  563. pBeam->haloScale = beamInfo.m_flHaloScale;
  564. pBeam->frame = 0;
  565. pBeam->frameRate = 0;
  566. pBeam->frameCount = modelinfo->GetModelFrameCount( pSprite );
  567. pBeam->freq = gpGlobals->curtime * beamInfo.m_flSpeed;
  568. pBeam->die = gpGlobals->curtime + beamInfo.m_flLife;
  569. pBeam->width = beamInfo.m_flWidth;
  570. pBeam->endWidth = beamInfo.m_flEndWidth;
  571. pBeam->fadeLength = beamInfo.m_flFadeLength;
  572. pBeam->amplitude = beamInfo.m_flAmplitude;
  573. pBeam->brightness = beamInfo.m_flBrightness;
  574. pBeam->speed = beamInfo.m_flSpeed;
  575. pBeam->life = beamInfo.m_flLife;
  576. pBeam->flags = beamInfo.m_nFlags;
  577. VectorCopy( beamInfo.m_vecStart, pBeam->attachment[0] );
  578. VectorCopy( beamInfo.m_vecEnd, pBeam->attachment[1] );
  579. VectorSubtract( beamInfo.m_vecEnd, beamInfo.m_vecStart, pBeam->delta );
  580. Assert( pBeam->delta.IsValid() );
  581. if ( beamInfo.m_nSegments == -1 )
  582. {
  583. if ( pBeam->amplitude >= 0.50 )
  584. {
  585. pBeam->segments = VectorLength( pBeam->delta ) * 0.25 + 3; // one per 4 pixels
  586. }
  587. else
  588. {
  589. pBeam->segments = VectorLength( pBeam->delta ) * 0.075 + 3; // one per 16 pixels
  590. }
  591. }
  592. else
  593. {
  594. pBeam->segments = beamInfo.m_nSegments;
  595. }
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Purpose: Set beam color and frame data.
  599. // Input: pBeam -
  600. // beamInfo -
  601. //-----------------------------------------------------------------------------
  602. void CViewRenderBeams::SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo )
  603. {
  604. pBeam->frame = ( float )beamInfo.m_nStartFrame;
  605. pBeam->frameRate = beamInfo.m_flFrameRate;
  606. pBeam->flags |= beamInfo.m_nFlags;
  607. pBeam->r = beamInfo.m_flRed;
  608. pBeam->g = beamInfo.m_flGreen;
  609. pBeam->b = beamInfo.m_flBlue;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Purpose: Cull beam by bbox
  613. // Input : *start -
  614. // *end -
  615. // pvsOnly -
  616. // Output : int
  617. //-----------------------------------------------------------------------------
  618. int CViewRenderBeams::CullBeam( const Vector &start, const Vector &end, int pvsOnly )
  619. {
  620. Vector mins, maxs;
  621. int i;
  622. for ( i = 0; i < 3; i++ )
  623. {
  624. if ( start[i] < end[i] )
  625. {
  626. mins[i] = start[i];
  627. maxs[i] = end[i];
  628. }
  629. else
  630. {
  631. mins[i] = end[i];
  632. maxs[i] = start[i];
  633. }
  634. // Don't let it be zero sized
  635. if ( mins[i] == maxs[i] )
  636. {
  637. maxs[i] += 1;
  638. }
  639. }
  640. // Check bbox
  641. if ( engine->IsBoxVisible( mins, maxs ) )
  642. {
  643. if ( pvsOnly || !engine->CullBox( mins, maxs ) )
  644. {
  645. // Beam is visible
  646. return 1;
  647. }
  648. }
  649. // Beam is not visible
  650. return 0;
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Purpose: Allocate and setup a generic beam.
  654. // Input: beamInfo -
  655. // Output: Beam_t
  656. //-----------------------------------------------------------------------------
  657. Beam_t *CViewRenderBeams::CreateGenericBeam( BeamInfo_t &beamInfo )
  658. {
  659. #if 0
  660. if ( BeamCreationAllowed() == false )
  661. {
  662. //NOTENOTE: If you've hit this, you may not add a beam where you have attempted to.
  663. // Most often this means that you have added it in an entity's DrawModel function.
  664. // Move this to the ClientThink function instead!
  665. DevMsg( "ERROR: Beam created too late in frame!\n" );
  666. Assert(0);
  667. return NULL;
  668. }
  669. #endif
  670. Beam_t *pBeam = BeamAlloc( beamInfo.m_bRenderable );
  671. if ( !pBeam )
  672. return NULL;
  673. // In case we fail.
  674. pBeam->die = gpGlobals->curtime;
  675. // Need a valid model.
  676. if ( beamInfo.m_nModelIndex < 0 )
  677. return NULL;
  678. // Set it up
  679. SetupBeam( pBeam, beamInfo );
  680. return pBeam;
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose: Create a beam between two ents
  684. // Input : startEnt -
  685. // endEnt -
  686. // modelIndex -
  687. // life -
  688. // width -
  689. // amplitude -
  690. // brightness -
  691. // speed -
  692. // startFrame -
  693. // framerate -
  694. // BEAMENT_ENTITY(startEnt -
  695. // Output : Beam_t
  696. //-----------------------------------------------------------------------------
  697. void CViewRenderBeams::CreateBeamEnts( int startEnt, int endEnt, int modelIndex,
  698. int haloIndex, float haloScale, float life, float width, float endWidth,
  699. float fadeLength, float amplitude, float brightness, float speed,
  700. int startFrame, float framerate, float r, float g, float b, int type )
  701. {
  702. BeamInfo_t beamInfo;
  703. beamInfo.m_nType = type;
  704. beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
  705. beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
  706. beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( endEnt ) );
  707. beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt );
  708. beamInfo.m_nModelIndex = modelIndex;
  709. beamInfo.m_nHaloIndex = haloIndex;
  710. beamInfo.m_flHaloScale = haloScale;
  711. beamInfo.m_flLife = life;
  712. beamInfo.m_flWidth = width;
  713. beamInfo.m_flEndWidth = endWidth;
  714. beamInfo.m_flFadeLength = fadeLength;
  715. beamInfo.m_flAmplitude = amplitude;
  716. beamInfo.m_flBrightness = brightness;
  717. beamInfo.m_flSpeed = speed;
  718. beamInfo.m_nStartFrame = startFrame;
  719. beamInfo.m_flFrameRate = framerate;
  720. beamInfo.m_flRed = r;
  721. beamInfo.m_flGreen = g;
  722. beamInfo.m_flBlue = b;
  723. CreateBeamEnts( beamInfo );
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Purpose: Create a beam between two entities.
  727. //-----------------------------------------------------------------------------
  728. Beam_t *CViewRenderBeams::CreateBeamEnts( BeamInfo_t &beamInfo )
  729. {
  730. // Don't start temporary beams out of the PVS
  731. if ( beamInfo.m_flLife != 0 &&
  732. ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->GetModel() == NULL ||
  733. !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->GetModel() == NULL) )
  734. {
  735. return NULL;
  736. }
  737. beamInfo.m_vecStart = vec3_origin;
  738. beamInfo.m_vecEnd = vec3_origin;
  739. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  740. if ( !pBeam )
  741. return NULL;
  742. pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType;
  743. pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
  744. pBeam->entity[0] = beamInfo.m_pStartEnt;
  745. pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
  746. pBeam->entity[1] = beamInfo.m_pEndEnt;
  747. pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
  748. // Attributes.
  749. SetBeamAttributes( pBeam, beamInfo );
  750. if ( beamInfo.m_flLife == 0 )
  751. {
  752. pBeam->flags |= FBEAM_FOREVER;
  753. }
  754. UpdateBeam( pBeam, 0 );
  755. return pBeam;
  756. }
  757. //-----------------------------------------------------------------------------
  758. // Purpose: Creates a beam between an entity and a point
  759. // Input : startEnt -
  760. // *end -
  761. // modelIndex -
  762. // life -
  763. // width -
  764. // amplitude -
  765. // brightness -
  766. // speed -
  767. // startFrame -
  768. // framerate -
  769. // r -
  770. // g -
  771. // b -
  772. // Output : Beam_t
  773. //-----------------------------------------------------------------------------
  774. void CViewRenderBeams::CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, const Vector* pEnd,
  775. int modelIndex, int haloIndex, float haloScale, float life, float width,
  776. float endWidth, float fadeLength, float amplitude, float brightness, float speed, int startFrame,
  777. float framerate, float r, float g, float b )
  778. {
  779. BeamInfo_t beamInfo;
  780. if ( nStartEntity <= 0 )
  781. {
  782. beamInfo.m_vecStart = pStart ? *pStart : vec3_origin;
  783. beamInfo.m_pStartEnt = NULL;
  784. }
  785. else
  786. {
  787. beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( nStartEntity ) );
  788. beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( nStartEntity );
  789. // Don't start beams out of the PVS
  790. if ( !beamInfo.m_pStartEnt )
  791. return;
  792. }
  793. if ( nEndEntity <= 0 )
  794. {
  795. beamInfo.m_vecEnd = pEnd ? *pEnd : vec3_origin;
  796. beamInfo.m_pEndEnt = NULL;
  797. }
  798. else
  799. {
  800. beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( nEndEntity ) );
  801. beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( nEndEntity );
  802. // Don't start beams out of the PVS
  803. if ( !beamInfo.m_pEndEnt )
  804. return;
  805. }
  806. beamInfo.m_nModelIndex = modelIndex;
  807. beamInfo.m_nHaloIndex = haloIndex;
  808. beamInfo.m_flHaloScale = haloScale;
  809. beamInfo.m_flLife = life;
  810. beamInfo.m_flWidth = width;
  811. beamInfo.m_flEndWidth = endWidth;
  812. beamInfo.m_flFadeLength = fadeLength;
  813. beamInfo.m_flAmplitude = amplitude;
  814. beamInfo.m_flBrightness = brightness;
  815. beamInfo.m_flSpeed = speed;
  816. beamInfo.m_nStartFrame = startFrame;
  817. beamInfo.m_flFrameRate = framerate;
  818. beamInfo.m_flRed = r;
  819. beamInfo.m_flGreen = g;
  820. beamInfo.m_flBlue = b;
  821. CreateBeamEntPoint( beamInfo );
  822. }
  823. //-----------------------------------------------------------------------------
  824. // Purpose: Creates a beam between an entity and a point.
  825. //-----------------------------------------------------------------------------
  826. Beam_t *CViewRenderBeams::CreateBeamEntPoint( BeamInfo_t &beamInfo )
  827. {
  828. if ( beamInfo.m_flLife != 0 )
  829. {
  830. if ( beamInfo.m_pStartEnt && beamInfo.m_pStartEnt->GetModel() == NULL )
  831. return NULL;
  832. if ( beamInfo.m_pEndEnt && beamInfo.m_pEndEnt->GetModel() == NULL )
  833. return NULL;
  834. }
  835. // Model index.
  836. if ( ( beamInfo.m_pszModelName ) && ( beamInfo.m_nModelIndex == -1 ) )
  837. {
  838. beamInfo.m_nModelIndex = modelinfo->GetModelIndex( beamInfo.m_pszModelName );
  839. }
  840. if ( ( beamInfo.m_pszHaloName ) && ( beamInfo.m_nHaloIndex == -1 ) )
  841. {
  842. beamInfo.m_nHaloIndex = modelinfo->GetModelIndex( beamInfo.m_pszHaloName );
  843. }
  844. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  845. if ( !pBeam )
  846. return NULL;
  847. pBeam->type = TE_BEAMPOINTS;
  848. pBeam->flags = 0;
  849. if ( beamInfo.m_pStartEnt )
  850. {
  851. pBeam->flags |= FBEAM_STARTENTITY;
  852. pBeam->entity[0] = beamInfo.m_pStartEnt;
  853. pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
  854. beamInfo.m_vecStart = vec3_origin;
  855. }
  856. if ( beamInfo.m_pEndEnt )
  857. {
  858. pBeam->flags |= FBEAM_ENDENTITY;
  859. pBeam->entity[1] = beamInfo.m_pEndEnt;
  860. pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
  861. beamInfo.m_vecEnd = vec3_origin;
  862. }
  863. SetBeamAttributes( pBeam, beamInfo );
  864. if ( beamInfo.m_flLife == 0 )
  865. {
  866. pBeam->flags |= FBEAM_FOREVER;
  867. }
  868. UpdateBeam( pBeam, 0 );
  869. return pBeam;
  870. }
  871. //-----------------------------------------------------------------------------
  872. // Purpose: Creates a beam between two points
  873. // Input : *start -
  874. // *end -
  875. // modelIndex -
  876. // life -
  877. // width -
  878. // amplitude -
  879. // brightness -
  880. // speed -
  881. // startFrame -
  882. // framerate -
  883. // r -
  884. // g -
  885. // b -
  886. // Output : Beam_t
  887. //-----------------------------------------------------------------------------
  888. void CViewRenderBeams::CreateBeamPoints( Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale, float life, float width,
  889. float endWidth, float fadeLength,float amplitude, float brightness, float speed, int startFrame,
  890. float framerate, float r, float g, float b )
  891. {
  892. BeamInfo_t beamInfo;
  893. beamInfo.m_vecStart = start;
  894. beamInfo.m_vecEnd = end;
  895. beamInfo.m_nModelIndex = modelIndex;
  896. beamInfo.m_nHaloIndex = haloIndex;
  897. beamInfo.m_flHaloScale = haloScale;
  898. beamInfo.m_flLife = life;
  899. beamInfo.m_flWidth = width;
  900. beamInfo.m_flEndWidth = endWidth;
  901. beamInfo.m_flFadeLength = fadeLength;
  902. beamInfo.m_flAmplitude = amplitude;
  903. beamInfo.m_flBrightness = brightness;
  904. beamInfo.m_flSpeed = speed;
  905. beamInfo.m_nStartFrame = startFrame;
  906. beamInfo.m_flFrameRate = framerate;
  907. beamInfo.m_flRed = r;
  908. beamInfo.m_flGreen = g;
  909. beamInfo.m_flBlue = b;
  910. CreateBeamPoints( beamInfo );
  911. }
  912. //-----------------------------------------------------------------------------
  913. // Purpose: Creates a beam between two points.
  914. //-----------------------------------------------------------------------------
  915. Beam_t *CViewRenderBeams::CreateBeamPoints( BeamInfo_t &beamInfo )
  916. {
  917. // Don't start temporary beams out of the PVS
  918. if ( beamInfo.m_flLife != 0 && !CullBeam( beamInfo.m_vecStart, beamInfo.m_vecEnd, 1 ) )
  919. return NULL;
  920. // Model index.
  921. if ( ( beamInfo.m_pszModelName ) && ( beamInfo.m_nModelIndex == -1 ) )
  922. {
  923. beamInfo.m_nModelIndex = modelinfo->GetModelIndex( beamInfo.m_pszModelName );
  924. }
  925. if ( ( beamInfo.m_pszHaloName ) && ( beamInfo.m_nHaloIndex == -1 ) )
  926. {
  927. beamInfo.m_nHaloIndex = modelinfo->GetModelIndex( beamInfo.m_pszHaloName );
  928. }
  929. // Create the new beam.
  930. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  931. if ( !pBeam )
  932. return NULL;
  933. // Set beam initial state.
  934. SetBeamAttributes( pBeam, beamInfo );
  935. if ( beamInfo.m_flLife == 0 )
  936. {
  937. pBeam->flags |= FBEAM_FOREVER;
  938. }
  939. return pBeam;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Purpose: Creates a circular beam between two points
  943. // Input : type -
  944. // *start -
  945. // *end -
  946. // modelIndex -
  947. // life -
  948. // width -
  949. // amplitude -
  950. // brightness -
  951. // speed -
  952. // startFrame -
  953. // framerate -
  954. // r -
  955. // g -
  956. // b -
  957. // Output : Beam_t
  958. //-----------------------------------------------------------------------------
  959. void CViewRenderBeams::CreateBeamCirclePoints( int type, Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale, float life, float width,
  960. float endWidth, float fadeLength,float amplitude, float brightness, float speed, int startFrame,
  961. float framerate, float r, float g, float b )
  962. {
  963. BeamInfo_t beamInfo;
  964. beamInfo.m_nType = type;
  965. beamInfo.m_vecStart = start;
  966. beamInfo.m_vecEnd = end;
  967. beamInfo.m_nModelIndex = modelIndex;
  968. beamInfo.m_nHaloIndex = haloIndex;
  969. beamInfo.m_flHaloScale = haloScale;
  970. beamInfo.m_flLife = life;
  971. beamInfo.m_flWidth = width;
  972. beamInfo.m_flEndWidth = endWidth;
  973. beamInfo.m_flFadeLength = fadeLength;
  974. beamInfo.m_flAmplitude = amplitude;
  975. beamInfo.m_flBrightness = brightness;
  976. beamInfo.m_flSpeed = speed;
  977. beamInfo.m_nStartFrame = startFrame;
  978. beamInfo.m_flFrameRate = framerate;
  979. beamInfo.m_flRed = r;
  980. beamInfo.m_flGreen = g;
  981. beamInfo.m_flBlue = b;
  982. CreateBeamCirclePoints( beamInfo );
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose: Creates a circular beam between two points.
  986. //-----------------------------------------------------------------------------
  987. Beam_t *CViewRenderBeams::CreateBeamCirclePoints( BeamInfo_t &beamInfo )
  988. {
  989. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  990. if ( !pBeam )
  991. return NULL;
  992. pBeam->type = beamInfo.m_nType;
  993. SetBeamAttributes( pBeam, beamInfo );
  994. if ( beamInfo.m_flLife == 0 )
  995. {
  996. pBeam->flags |= FBEAM_FOREVER;
  997. }
  998. return pBeam;
  999. }
  1000. //-----------------------------------------------------------------------------
  1001. // Purpose: Create a beam which follows an entity
  1002. // Input : startEnt -
  1003. // modelIndex -
  1004. // life -
  1005. // width -
  1006. // r -
  1007. // g -
  1008. // b -
  1009. // brightness -
  1010. // Output : Beam_t
  1011. //-----------------------------------------------------------------------------
  1012. void CViewRenderBeams::CreateBeamFollow( int startEnt, int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth,
  1013. float fadeLength, float r, float g, float b, float brightness )
  1014. {
  1015. BeamInfo_t beamInfo;
  1016. beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
  1017. beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
  1018. beamInfo.m_nModelIndex = modelIndex;
  1019. beamInfo.m_nHaloIndex = haloIndex;
  1020. beamInfo.m_flHaloScale = haloScale;
  1021. beamInfo.m_flLife = life;
  1022. beamInfo.m_flWidth = width;
  1023. beamInfo.m_flEndWidth = endWidth;
  1024. beamInfo.m_flFadeLength = fadeLength;
  1025. beamInfo.m_flBrightness = brightness;
  1026. beamInfo.m_flRed = r;
  1027. beamInfo.m_flGreen = g;
  1028. beamInfo.m_flBlue = b;
  1029. beamInfo.m_flAmplitude = life;
  1030. CreateBeamFollow( beamInfo );
  1031. }
  1032. //-----------------------------------------------------------------------------
  1033. // Purpose: Create a beam which follows an entity.
  1034. //-----------------------------------------------------------------------------
  1035. Beam_t *CViewRenderBeams::CreateBeamFollow( BeamInfo_t &beamInfo )
  1036. {
  1037. beamInfo.m_vecStart = vec3_origin;
  1038. beamInfo.m_vecEnd = vec3_origin;
  1039. beamInfo.m_flSpeed = 1.0f;
  1040. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  1041. if ( !pBeam )
  1042. return NULL;
  1043. pBeam->type = TE_BEAMFOLLOW;
  1044. pBeam->flags = FBEAM_STARTENTITY;
  1045. pBeam->entity[0] = beamInfo.m_pStartEnt;
  1046. pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
  1047. beamInfo.m_flFrameRate = 1.0f;
  1048. beamInfo.m_nStartFrame = 0;
  1049. SetBeamAttributes( pBeam, beamInfo );
  1050. UpdateBeam( pBeam, 0 );
  1051. return pBeam;
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose: Create a beam ring between two entities
  1055. // Input : startEnt -
  1056. // endEnt -
  1057. // modelIndex -
  1058. // life -
  1059. // width -
  1060. // amplitude -
  1061. // brightness -
  1062. // speed -
  1063. // startFrame -
  1064. // framerate -
  1065. // startEnt -
  1066. // Output : Beam_t
  1067. //-----------------------------------------------------------------------------
  1068. void CViewRenderBeams::CreateBeamRingPoint( const Vector& center, float start_radius, float end_radius,
  1069. int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth,
  1070. float fadeLength, float amplitude, float brightness, float speed, int startFrame, float framerate,
  1071. float r, float g, float b, int nFlags )
  1072. {
  1073. BeamInfo_t beamInfo;
  1074. beamInfo.m_nModelIndex = modelIndex;
  1075. beamInfo.m_nHaloIndex = haloIndex;
  1076. beamInfo.m_flHaloScale = haloScale;
  1077. beamInfo.m_flLife = life;
  1078. beamInfo.m_flWidth = width;
  1079. beamInfo.m_flEndWidth = endWidth;
  1080. beamInfo.m_flFadeLength = fadeLength;
  1081. beamInfo.m_flAmplitude = amplitude;
  1082. beamInfo.m_flBrightness = brightness;
  1083. beamInfo.m_flSpeed = speed;
  1084. beamInfo.m_nStartFrame = startFrame;
  1085. beamInfo.m_flFrameRate = framerate;
  1086. beamInfo.m_flRed = r;
  1087. beamInfo.m_flGreen = g;
  1088. beamInfo.m_flBlue = b;
  1089. beamInfo.m_vecCenter = center;
  1090. beamInfo.m_flStartRadius = start_radius;
  1091. beamInfo.m_flEndRadius = end_radius;
  1092. beamInfo.m_nFlags = nFlags;
  1093. CreateBeamRingPoint( beamInfo );
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. // Purpose: Create a beam ring between two entities
  1097. // Input: beamInfo -
  1098. //-----------------------------------------------------------------------------
  1099. Beam_t *CViewRenderBeams::CreateBeamRingPoint( BeamInfo_t &beamInfo )
  1100. {
  1101. // ??
  1102. Vector endpos = beamInfo.m_vecCenter;
  1103. beamInfo.m_vecStart = beamInfo.m_vecCenter;
  1104. beamInfo.m_vecEnd = beamInfo.m_vecCenter;
  1105. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  1106. if ( !pBeam )
  1107. return NULL;
  1108. pBeam->type = TE_BEAMRINGPOINT;
  1109. pBeam->start_radius = beamInfo.m_flStartRadius;
  1110. pBeam->end_radius = beamInfo.m_flEndRadius;
  1111. pBeam->attachment[2] = beamInfo.m_vecCenter;
  1112. SetBeamAttributes( pBeam, beamInfo );
  1113. if ( beamInfo.m_flLife == 0 )
  1114. {
  1115. pBeam->flags |= FBEAM_FOREVER;
  1116. }
  1117. return pBeam;
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose: Create a beam ring between two entities
  1121. // Input : startEnt -
  1122. // endEnt -
  1123. // modelIndex -
  1124. // life -
  1125. // width -
  1126. // amplitude -
  1127. // brightness -
  1128. // speed -
  1129. // startFrame -
  1130. // framerate -
  1131. // startEnt -
  1132. // Output : Beam_t
  1133. //-----------------------------------------------------------------------------
  1134. void CViewRenderBeams::CreateBeamRing( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth, float fadeLength,
  1135. float amplitude, float brightness, float speed, int startFrame, float framerate,
  1136. float r, float g, float b, int flags )
  1137. {
  1138. BeamInfo_t beamInfo;
  1139. beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
  1140. beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
  1141. beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( endEnt ) );
  1142. beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt );
  1143. beamInfo.m_nModelIndex = modelIndex;
  1144. beamInfo.m_nHaloIndex = haloIndex;
  1145. beamInfo.m_flHaloScale = haloScale;
  1146. beamInfo.m_flLife = life;
  1147. beamInfo.m_flWidth = width;
  1148. beamInfo.m_flEndWidth = endWidth;
  1149. beamInfo.m_flFadeLength = fadeLength;
  1150. beamInfo.m_flAmplitude = amplitude;
  1151. beamInfo.m_flBrightness = brightness;
  1152. beamInfo.m_flSpeed = speed;
  1153. beamInfo.m_nStartFrame = startFrame;
  1154. beamInfo.m_flFrameRate = framerate;
  1155. beamInfo.m_flRed = r;
  1156. beamInfo.m_flGreen = g;
  1157. beamInfo.m_flBlue = b;
  1158. beamInfo.m_nFlags = flags;
  1159. CreateBeamRing( beamInfo );
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. // Purpose: Create a beam ring between two entities.
  1163. // Input: beamInfo -
  1164. //-----------------------------------------------------------------------------
  1165. Beam_t *CViewRenderBeams::CreateBeamRing( BeamInfo_t &beamInfo )
  1166. {
  1167. // Don't start temporary beams out of the PVS
  1168. if ( beamInfo.m_flLife != 0 &&
  1169. ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->GetModel() == NULL ||
  1170. !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->GetModel() == NULL ) )
  1171. {
  1172. return NULL;
  1173. }
  1174. beamInfo.m_vecStart = vec3_origin;
  1175. beamInfo.m_vecEnd = vec3_origin;
  1176. Beam_t *pBeam = CreateGenericBeam( beamInfo );
  1177. if ( !pBeam )
  1178. return NULL;
  1179. pBeam->type = TE_BEAMRING;
  1180. pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
  1181. pBeam->entity[0] = beamInfo.m_pStartEnt;
  1182. pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
  1183. pBeam->entity[1] = beamInfo.m_pEndEnt;
  1184. pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
  1185. SetBeamAttributes( pBeam, beamInfo );
  1186. if ( beamInfo.m_flLife == 0 )
  1187. {
  1188. pBeam->flags |= FBEAM_FOREVER;
  1189. }
  1190. UpdateBeam( pBeam, 0 );
  1191. return pBeam;
  1192. }
  1193. //-----------------------------------------------------------------------------
  1194. // Purpose: Free dead trails associated with beam
  1195. // Input : **ppparticles -
  1196. //-----------------------------------------------------------------------------
  1197. void CViewRenderBeams::FreeDeadTrails( BeamTrail_t **trail )
  1198. {
  1199. BeamTrail_t *kill;
  1200. BeamTrail_t *p;
  1201. // kill all the ones hanging direcly off the base pointer
  1202. for ( ;; )
  1203. {
  1204. kill = *trail;
  1205. if (kill && kill->die < gpGlobals->curtime)
  1206. {
  1207. *trail = kill->next;
  1208. kill->next = m_pFreeTrails;
  1209. m_pFreeTrails = kill;
  1210. continue;
  1211. }
  1212. break;
  1213. }
  1214. // kill off all the others
  1215. for (p=*trail ; p ; p=p->next)
  1216. {
  1217. for ( ;; )
  1218. {
  1219. kill = p->next;
  1220. if (kill && kill->die < gpGlobals->curtime)
  1221. {
  1222. p->next = kill->next;
  1223. kill->next = m_pFreeTrails;
  1224. m_pFreeTrails = kill;
  1225. continue;
  1226. }
  1227. break;
  1228. }
  1229. }
  1230. }
  1231. //-----------------------------------------------------------------------------
  1232. // Updates beam state
  1233. //-----------------------------------------------------------------------------
  1234. void CViewRenderBeams::UpdateBeam( Beam_t *pbeam, float frametime, C_Beam *pcbeam )
  1235. {
  1236. if ( pbeam->modelIndex < 0 )
  1237. {
  1238. pbeam->die = gpGlobals->curtime;
  1239. return;
  1240. }
  1241. // if we are paused, force random numbers used by noise to generate the same value every frame
  1242. if ( frametime == 0.0f )
  1243. {
  1244. beamRandom.SetSeed( (int)gpGlobals->curtime );
  1245. }
  1246. // If FBEAM_ONLYNOISEONCE is set, we don't want to move once we've first calculated noise
  1247. if ( !(pbeam->flags & FBEAM_ONLYNOISEONCE ) )
  1248. {
  1249. pbeam->freq += frametime;
  1250. }
  1251. else
  1252. {
  1253. pbeam->freq += frametime * beamRandom.RandomFloat(1,2);
  1254. }
  1255. // OPTIMIZE: Do this every frame?
  1256. // UNDONE: Do this differentially somehow?
  1257. // Generate fractal noise
  1258. pbeam->rgNoise[0] = 0;
  1259. pbeam->rgNoise[NOISE_DIVISIONS] = 0;
  1260. if ( pbeam->amplitude != 0 )
  1261. {
  1262. if ( !(pbeam->flags & FBEAM_ONLYNOISEONCE ) || !pbeam->m_bCalculatedNoise )
  1263. {
  1264. if ( pbeam->flags & FBEAM_SINENOISE )
  1265. {
  1266. SineNoise( pbeam->rgNoise, NOISE_DIVISIONS );
  1267. }
  1268. else
  1269. {
  1270. Noise( pbeam->rgNoise, NOISE_DIVISIONS, 1.0 );
  1271. }
  1272. pbeam->m_bCalculatedNoise = true;
  1273. }
  1274. }
  1275. // update end points
  1276. if ( pbeam->flags & (FBEAM_STARTENTITY|FBEAM_ENDENTITY) )
  1277. {
  1278. // Makes sure attachment[0] + attachment[1] are valid
  1279. if (!RecomputeBeamEndpoints( pbeam ))
  1280. return;
  1281. // clip if requested
  1282. if ( pcbeam && pcbeam->GetClipStyle() != CBeam::kNOCLIP )
  1283. {
  1284. ClipBeam( pcbeam, pbeam );
  1285. }
  1286. // Compute segments from the new endpoints
  1287. VectorSubtract( pbeam->attachment[1], pbeam->attachment[0], pbeam->delta );
  1288. if ( pbeam->amplitude >= 0.50 )
  1289. pbeam->segments = VectorLength( pbeam->delta ) * 0.25 + 3; // one per 4 pixels
  1290. else
  1291. pbeam->segments = VectorLength( pbeam->delta ) * 0.075 + 3; // one per 16 pixels
  1292. }
  1293. // Get position data for spline beam
  1294. switch ( pbeam->type )
  1295. {
  1296. case TE_BEAMSPLINE:
  1297. {
  1298. // Why isn't attachment[0] being computed?
  1299. for (int i=1; i < pbeam->numAttachments; i++)
  1300. {
  1301. if (!ComputeBeamEntPosition( pbeam->entity[i], pbeam->attachmentIndex[i], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[i] ))
  1302. {
  1303. // This should never happen, but if for some reason the attachment doesn't exist,
  1304. // as a safety measure copy in the location of the previous attachment point (rather than bailing)
  1305. VectorCopy( pbeam->attachment[i-1], pbeam->attachment[i] );
  1306. }
  1307. }
  1308. }
  1309. break;
  1310. case TE_BEAMRINGPOINT:
  1311. {
  1312. //
  1313. float dr = pbeam->end_radius - pbeam->start_radius;
  1314. if ( dr != 0.0f )
  1315. {
  1316. float frac = 1.0f;
  1317. // Go some portion of the way there based on life
  1318. float remaining = pbeam->die - gpGlobals->curtime;
  1319. if ( remaining < pbeam->life && pbeam->life > 0.0f )
  1320. {
  1321. frac = remaining / pbeam->life;
  1322. }
  1323. frac = MIN( 1.0f, frac );
  1324. frac = MAX( 0.0f, frac );
  1325. frac = 1.0f - frac;
  1326. // Start pos
  1327. Vector endpos = pbeam->attachment[ 2 ];
  1328. endpos.x += ( pbeam->start_radius + frac * dr ) / 2.0f;
  1329. Vector startpos = pbeam->attachment[ 2 ];
  1330. startpos.x -= ( pbeam->start_radius + frac * dr ) / 2.0f;
  1331. pbeam->attachment[ 0 ] = startpos;
  1332. pbeam->attachment[ 1 ] = endpos;
  1333. VectorSubtract( pbeam->attachment[1], pbeam->attachment[0], pbeam->delta );
  1334. if (pbeam->amplitude >= 0.50)
  1335. pbeam->segments = VectorLength( pbeam->delta ) * 0.25 + 3; // one per 4 pixels
  1336. else
  1337. pbeam->segments = VectorLength( pbeam->delta ) * 0.075 + 3; // one per 16 pixels
  1338. }
  1339. }
  1340. break;
  1341. case TE_BEAMPOINTS:
  1342. // UNDONE: Build culling volumes for other types of beams
  1343. if ( !CullBeam( pbeam->attachment[0], pbeam->attachment[1], 0 ) )
  1344. return;
  1345. break;
  1346. }
  1347. // update life cycle
  1348. pbeam->t = pbeam->freq + (pbeam->die - gpGlobals->curtime);
  1349. if (pbeam->t != 0)
  1350. {
  1351. pbeam->t = pbeam->freq / pbeam->t;
  1352. }
  1353. else
  1354. {
  1355. pbeam->t = 1.0f;
  1356. }
  1357. // ------------------------------------------
  1358. // check for zero fadeLength (means no fade)
  1359. // ------------------------------------------
  1360. if (pbeam->fadeLength == 0)
  1361. {
  1362. Assert( pbeam->delta.IsValid() );
  1363. pbeam->fadeLength = pbeam->delta.Length();
  1364. }
  1365. }
  1366. //-----------------------------------------------------------------------------
  1367. // Purpose: Update beams created by temp entity system
  1368. //-----------------------------------------------------------------------------
  1369. void CViewRenderBeams::UpdateTempEntBeams( void )
  1370. {
  1371. VPROF_("UpdateTempEntBeams", 2, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
  1372. if ( !m_pActiveBeams )
  1373. return;
  1374. // Get frame time
  1375. float frametime = gpGlobals->frametime;
  1376. if ( frametime == 0.0f )
  1377. return;
  1378. // Draw temporary entity beams
  1379. Beam_t* pPrev = 0;
  1380. Beam_t* pNext;
  1381. for ( Beam_t* pBeam = m_pActiveBeams; pBeam ; pBeam = pNext )
  1382. {
  1383. // Need to store the next one since we may delete this one
  1384. pNext = pBeam->next;
  1385. // Retire old beams
  1386. if ( !(pBeam->flags & FBEAM_FOREVER) &&
  1387. pBeam->die <= gpGlobals->curtime )
  1388. {
  1389. // Reset links
  1390. if ( pPrev )
  1391. {
  1392. pPrev->next = pNext;
  1393. }
  1394. else
  1395. {
  1396. m_pActiveBeams = pNext;
  1397. }
  1398. // Free the beam
  1399. BeamFree( pBeam );
  1400. pBeam = NULL;
  1401. continue;
  1402. }
  1403. // Update beam state
  1404. UpdateBeam( pBeam, frametime );
  1405. // Compute bounds for the beam
  1406. pBeam->ComputeBounds();
  1407. // Indicates the beam moved
  1408. if ( pBeam->m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE )
  1409. {
  1410. ClientLeafSystem()->RenderableChanged( pBeam->m_hRenderHandle );
  1411. }
  1412. pPrev = pBeam;
  1413. }
  1414. }
  1415. //-----------------------------------------------------------------------------
  1416. // Purpose: Draw helper for beam follow beams
  1417. // Input : *pbeam -
  1418. // frametime -
  1419. // *color -
  1420. //-----------------------------------------------------------------------------
  1421. void CViewRenderBeams::DrawBeamFollow( const model_t* pSprite, Beam_t *pbeam,
  1422. int frame, int rendermode, float frametime, const float* color, float flHDRColorScale )
  1423. {
  1424. BeamTrail_t *particles;
  1425. BeamTrail_t *pnew;
  1426. float div;
  1427. Vector delta;
  1428. Vector screenLast;
  1429. Vector screen;
  1430. FreeDeadTrails( &pbeam->trail );
  1431. particles = pbeam->trail;
  1432. pnew = NULL;
  1433. div = 0;
  1434. if ( pbeam->flags & FBEAM_STARTENTITY )
  1435. {
  1436. if (particles)
  1437. {
  1438. VectorSubtract( particles->org, pbeam->attachment[0], delta );
  1439. div = VectorLength( delta );
  1440. if (div >= 32 && m_pFreeTrails)
  1441. {
  1442. pnew = m_pFreeTrails;
  1443. m_pFreeTrails = pnew->next;
  1444. }
  1445. }
  1446. else if (m_pFreeTrails)
  1447. {
  1448. pnew = m_pFreeTrails;
  1449. m_pFreeTrails = pnew->next;
  1450. div = 0;
  1451. }
  1452. }
  1453. if (pnew)
  1454. {
  1455. VectorCopy( pbeam->attachment[0], pnew->org );
  1456. pnew->die = gpGlobals->curtime + pbeam->amplitude;
  1457. VectorCopy( vec3_origin, pnew->vel );
  1458. pbeam->die = gpGlobals->curtime + pbeam->amplitude;
  1459. pnew->next = particles;
  1460. pbeam->trail = pnew;
  1461. particles = pnew;
  1462. }
  1463. if (!particles)
  1464. {
  1465. return;
  1466. }
  1467. if (!pnew && div != 0)
  1468. {
  1469. VectorCopy( pbeam->attachment[0], delta );
  1470. debugoverlay->ScreenPosition( pbeam->attachment[0], screenLast );
  1471. debugoverlay->ScreenPosition( particles->org, screen );
  1472. }
  1473. else if (particles && particles->next)
  1474. {
  1475. VectorCopy( particles->org, delta );
  1476. debugoverlay->ScreenPosition( particles->org, screenLast );
  1477. debugoverlay->ScreenPosition( particles->next->org, screen );
  1478. particles = particles->next;
  1479. }
  1480. else
  1481. {
  1482. return;
  1483. }
  1484. // Draw it
  1485. ::DrawBeamFollow( pSprite, pbeam->trail, frame, rendermode, delta, screen, screenLast,
  1486. pbeam->die, pbeam->attachment[0], pbeam->flags, pbeam->width,
  1487. pbeam->amplitude, pbeam->freq, (float*)color );
  1488. // Drift popcorn trail if there is a velocity
  1489. particles = pbeam->trail;
  1490. while (particles)
  1491. {
  1492. VectorMA( particles->org, frametime, particles->vel, particles->org );
  1493. particles = particles->next;
  1494. }
  1495. }
  1496. //------------------------------------------------------------------------------
  1497. // Purpose : Draw beam with a halo
  1498. // Input :
  1499. // Output :
  1500. //------------------------------------------------------------------------------
  1501. void CViewRenderBeams::DrawBeamWithHalo( Beam_t* pbeam,
  1502. int frame,
  1503. int rendermode,
  1504. float* color,
  1505. float* srcColor,
  1506. const model_t *sprite,
  1507. const model_t *halosprite,
  1508. float flHDRColorScale )
  1509. {
  1510. Vector beamDir = pbeam->attachment[1] - pbeam->attachment[0];
  1511. VectorNormalize( beamDir );
  1512. Vector localDir = CurrentViewOrigin() - pbeam->attachment[0];
  1513. VectorNormalize( localDir );
  1514. float dotpr = DotProduct( beamDir, localDir );
  1515. float fade;
  1516. if ( dotpr < 0.0f )
  1517. {
  1518. fade = 0;
  1519. }
  1520. else
  1521. {
  1522. fade = dotpr * 2.0f;
  1523. }
  1524. float distToLine;
  1525. Vector out;
  1526. // Find out how close we are to the "line" of the spotlight
  1527. CalcClosestPointOnLine( CurrentViewOrigin(), pbeam->attachment[0], pbeam->attachment[0] + ( beamDir * 2 ), out, &distToLine );
  1528. distToLine = ( CurrentViewOrigin() - out ).Length();
  1529. float scaleColor[3];
  1530. float dotScale = 1.0f;
  1531. // Use beam width
  1532. float distThreshold = pbeam->width * 4.0f;
  1533. if ( distToLine < distThreshold )
  1534. {
  1535. dotScale = RemapVal( distToLine, distThreshold, pbeam->width, 1.0f, 0.0f );
  1536. dotScale = clamp( dotScale, 0, 1 );
  1537. }
  1538. scaleColor[0] = color[0] * dotScale;
  1539. scaleColor[1] = color[1] * dotScale;
  1540. scaleColor[2] = color[2] * dotScale;
  1541. if( pbeam->flags & FBEAM_HALOBEAM )
  1542. {
  1543. DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode, pbeam->attachment[0],
  1544. pbeam->delta, pbeam->width, pbeam->endWidth, pbeam->amplitude, pbeam->freq, pbeam->speed,
  1545. pbeam->segments, pbeam->flags, scaleColor, pbeam->fadeLength, flHDRColorScale );
  1546. }
  1547. else
  1548. {
  1549. // Draw primary beam just shy of its end so it doesn't clip
  1550. DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode, pbeam->attachment[0],
  1551. pbeam->delta, pbeam->width, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed,
  1552. 2, pbeam->flags, scaleColor, pbeam->fadeLength, flHDRColorScale );
  1553. }
  1554. Vector vSource = pbeam->attachment[0];
  1555. pixelvis_queryparams_t params;
  1556. params.Init( vSource, pbeam->m_haloProxySize );
  1557. float haloFractionVisible = PixelVisibility_FractionVisible( params, pbeam->m_queryHandleHalo );
  1558. if ( fade && haloFractionVisible > 0.0f )
  1559. {
  1560. //NOTENOTE: This is kinda funky when moving away and to the backside -- jdw
  1561. float haloScale = RemapVal( distToLine, distThreshold, pbeam->width*0.5f, 1.0f, 2.0f );
  1562. haloScale = clamp( haloScale, 1.0f, 2.0f );
  1563. haloScale *= pbeam->haloScale;
  1564. float colorFade = fade*fade;
  1565. colorFade = clamp( colorFade, 0, 1 );
  1566. float haloColor[3];
  1567. VectorScale( color, colorFade * haloFractionVisible, haloColor );
  1568. BeamDrawHalo( halosprite, frame, kRenderGlow, vSource, haloScale, haloColor, flHDRColorScale );
  1569. }
  1570. }
  1571. //------------------------------------------------------------------------------
  1572. // Purpose : Draw a beam based upon the viewpoint
  1573. //------------------------------------------------------------------------------
  1574. void CViewRenderBeams::DrawLaser( Beam_t *pbeam, int frame, int rendermode, float *color, const model_t *sprite, const model_t *halosprite, float flHDRColorScale )
  1575. {
  1576. float color2[3];
  1577. VectorCopy( color, color2 );
  1578. Vector vecForward;
  1579. Vector beamDir = pbeam->attachment[1] - pbeam->attachment[0];
  1580. VectorNormalize( beamDir );
  1581. AngleVectors( CurrentViewAngles(), &vecForward );
  1582. float flDot = DotProduct(beamDir, vecForward);
  1583. // abort if the player's looking along it away from the source
  1584. if ( flDot > 0 )
  1585. {
  1586. return;
  1587. }
  1588. else
  1589. {
  1590. // Fade the beam if the player's not looking at the source
  1591. float flFade = pow( flDot, 10 );
  1592. // Fade the beam based on the player's proximity to the beam
  1593. Vector localDir = CurrentViewOrigin() - pbeam->attachment[0];
  1594. flDot = DotProduct( beamDir, localDir );
  1595. Vector vecProjection = flDot * beamDir;
  1596. float flDistance = ( localDir - vecProjection ).Length();
  1597. if ( flDistance > 30 )
  1598. {
  1599. flDistance = 1 - ((flDistance - 30) / 64);
  1600. if ( flDistance <= 0 )
  1601. {
  1602. flFade = 0;
  1603. }
  1604. else
  1605. {
  1606. flFade *= pow( flDistance, 3 );
  1607. }
  1608. }
  1609. if (flFade < (1.0f / 255.0f))
  1610. return;
  1611. VectorScale( color2, flFade, color2 );
  1612. //engine->Con_NPrintf( 6, "Fade: %f", flFade );
  1613. //engine->Con_NPrintf( 7, "Dist: %f", flDistance );
  1614. }
  1615. DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode, pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->endWidth, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags, color2, pbeam->fadeLength);
  1616. }
  1617. //------------------------------------------------------------------------------
  1618. // Purpose : Draw a fibrous tesla beam
  1619. //------------------------------------------------------------------------------
  1620. void CViewRenderBeams::DrawTesla( Beam_t *pbeam, int frame, int rendermode, float *color, const model_t *sprite, float flHDRColorScale )
  1621. {
  1622. DrawTeslaSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode, pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->endWidth, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags, color, pbeam->fadeLength, flHDRColorScale );
  1623. }
  1624. //-----------------------------------------------------------------------------
  1625. // Purpose: Draw all beam entities
  1626. // Input : *pbeam -
  1627. // frametime -
  1628. //-----------------------------------------------------------------------------
  1629. void CViewRenderBeams::DrawBeam( Beam_t *pbeam )
  1630. {
  1631. Assert( pbeam->delta.IsValid() );
  1632. if ( !r_DrawBeams.GetInt() )
  1633. return;
  1634. // Don't draw really short beams
  1635. if (pbeam->delta.Length() < 0.1)
  1636. {
  1637. return;
  1638. }
  1639. const model_t *sprite;
  1640. const model_t *halosprite = NULL;
  1641. if ( pbeam->modelIndex < 0 )
  1642. {
  1643. pbeam->die = gpGlobals->curtime;
  1644. return;
  1645. }
  1646. sprite = modelinfo->GetModel( pbeam->modelIndex );
  1647. if ( !sprite )
  1648. {
  1649. return;
  1650. }
  1651. halosprite = modelinfo->GetModel( pbeam->haloIndex );
  1652. int frame = ( ( int )( pbeam->frame + gpGlobals->curtime * pbeam->frameRate) % pbeam->frameCount );
  1653. int rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd;
  1654. // set color
  1655. float srcColor[3];
  1656. float color[3];
  1657. srcColor[0] = pbeam->r;
  1658. srcColor[1] = pbeam->g;
  1659. srcColor[2] = pbeam->b;
  1660. if ( pbeam->flags & FBEAM_FADEIN )
  1661. {
  1662. VectorScale( srcColor, pbeam->t, color );
  1663. }
  1664. else if ( pbeam->flags & FBEAM_FADEOUT )
  1665. {
  1666. VectorScale( srcColor, ( 1.0f - pbeam->t ), color );
  1667. }
  1668. else
  1669. {
  1670. VectorCopy( srcColor, color );
  1671. }
  1672. VectorScale( color, (1/255.0), color );
  1673. VectorCopy( color, srcColor );
  1674. VectorScale( color, ((float)pbeam->brightness / 255.0), color );
  1675. switch( pbeam->type )
  1676. {
  1677. case TE_BEAMDISK:
  1678. DrawDisk( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode,
  1679. pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
  1680. pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
  1681. break;
  1682. case TE_BEAMCYLINDER:
  1683. DrawCylinder( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode,
  1684. pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
  1685. pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
  1686. break;
  1687. case TE_BEAMPOINTS:
  1688. {
  1689. if (halosprite)
  1690. {
  1691. DrawBeamWithHalo( pbeam, frame, rendermode, color, srcColor, sprite, halosprite, pbeam->m_flHDRColorScale );
  1692. }
  1693. else
  1694. {
  1695. DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode,
  1696. pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->endWidth,
  1697. pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments,
  1698. pbeam->flags, color, pbeam->fadeLength, pbeam->m_flHDRColorScale );
  1699. }
  1700. }
  1701. break;
  1702. case TE_BEAMFOLLOW:
  1703. DrawBeamFollow( sprite, pbeam, frame, rendermode, gpGlobals->frametime, color, pbeam->m_flHDRColorScale );
  1704. break;
  1705. case TE_BEAMRING:
  1706. case TE_BEAMRINGPOINT:
  1707. DrawRing( NOISE_DIVISIONS, pbeam->rgNoise, Noise, sprite, frame, rendermode,
  1708. pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
  1709. pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
  1710. break;
  1711. case TE_BEAMSPLINE:
  1712. DrawSplineSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, halosprite,
  1713. pbeam->haloScale, frame, rendermode, pbeam->numAttachments,
  1714. pbeam->attachment, pbeam->width, pbeam->endWidth, pbeam->amplitude,
  1715. pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags, color, pbeam->fadeLength, pbeam->m_flHDRColorScale );
  1716. break;
  1717. case TE_BEAMLASER:
  1718. DrawLaser( pbeam, frame, rendermode, color, sprite, halosprite, pbeam->m_flHDRColorScale );
  1719. break;
  1720. case TE_BEAMTESLA:
  1721. DrawTesla( pbeam, frame, rendermode, color, sprite, pbeam->m_flHDRColorScale );
  1722. break;
  1723. default:
  1724. DevWarning( 1, "CViewRenderBeams::DrawBeam: Unknown beam type %i\n", pbeam->type );
  1725. break;
  1726. }
  1727. }
  1728. //-----------------------------------------------------------------------------
  1729. // Purpose: Update the beam
  1730. //-----------------------------------------------------------------------------
  1731. void CViewRenderBeams::UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo )
  1732. {
  1733. pBeam->attachment[0] = beamInfo.m_vecStart;
  1734. pBeam->attachment[1] = beamInfo.m_vecEnd;
  1735. pBeam->delta = beamInfo.m_vecEnd - beamInfo.m_vecStart;
  1736. Assert( pBeam->delta.IsValid() );
  1737. SetBeamAttributes( pBeam, beamInfo );
  1738. }
  1739. //-----------------------------------------------------------------------------
  1740. // Recomputes beam endpoints..
  1741. //-----------------------------------------------------------------------------
  1742. bool CViewRenderBeams::RecomputeBeamEndpoints( Beam_t *pbeam )
  1743. {
  1744. if ( pbeam->flags & FBEAM_STARTENTITY )
  1745. {
  1746. if (ComputeBeamEntPosition( pbeam->entity[0], pbeam->attachmentIndex[0], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[0] ))
  1747. {
  1748. pbeam->flags |= FBEAM_STARTVISIBLE;
  1749. }
  1750. else if (! (pbeam->flags & FBEAM_FOREVER))
  1751. {
  1752. pbeam->flags &= ~(FBEAM_STARTENTITY);
  1753. }
  1754. else
  1755. {
  1756. // DevWarning( 1,"can't find start entity\n");
  1757. // return false;
  1758. }
  1759. // If we've never seen the start entity, don't display
  1760. if ( !(pbeam->flags & FBEAM_STARTVISIBLE) )
  1761. return false;
  1762. }
  1763. if ( pbeam->flags & FBEAM_ENDENTITY )
  1764. {
  1765. if (ComputeBeamEntPosition( pbeam->entity[1], pbeam->attachmentIndex[1], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[1] ))
  1766. {
  1767. pbeam->flags |= FBEAM_ENDVISIBLE;
  1768. }
  1769. else if (! (pbeam->flags & FBEAM_FOREVER))
  1770. {
  1771. pbeam->flags &= ~(FBEAM_ENDENTITY);
  1772. pbeam->die = gpGlobals->curtime;
  1773. return false;
  1774. }
  1775. else
  1776. {
  1777. return false;
  1778. }
  1779. // If we've never seen the end entity, don't display
  1780. if ( !(pbeam->flags & FBEAM_ENDVISIBLE) )
  1781. return false;
  1782. }
  1783. return true;
  1784. }
  1785. #include "debugoverlay_shared.h"
  1786. #ifdef VPROF_ENABLED
  1787. ConVar cl_beam_test_traces( "cl_beam_test_traces", "0", FCVAR_DEVELOPMENTONLY, "Enable debug overlay on traces that determine where the client-side visible env_beam is drawn. Has no bearing on the server-side damage-causing part of the beam." );
  1788. static inline bool BeamDebugOverlay() { return cl_beam_test_traces.GetBool(); }
  1789. #else
  1790. static inline bool BeamDebugOverlay() { return false; }
  1791. #endif
  1792. void CViewRenderBeams::ClipBeam( C_Beam * RESTRICT pcbeam, Beam_t * RESTRICT pbeam )
  1793. {
  1794. // Assert( pbeam->GetClipStyle() != C_Beam::kNOCLIP );
  1795. int colmask = 0;
  1796. int colgroup = COLLISION_GROUP_NONE;
  1797. switch ( pcbeam->GetClipStyle() )
  1798. {
  1799. case C_Beam::kGEOCLIP:
  1800. colmask = CONTENTS_SOLID; // lasers go through gates and windows.
  1801. break;
  1802. case C_Beam::kMODELCLIP:
  1803. colmask = MASK_SOLID;
  1804. break;
  1805. default:
  1806. AssertMsg1(false, "Unknown beam clipping type %d\n", pcbeam->GetClipStyle() );
  1807. return;
  1808. }
  1809. trace_t tr;
  1810. Vector &vstart = pbeam->attachment[0];
  1811. Vector &vend = pbeam->attachment[1];
  1812. // start the trace from a few inches ahead of the start position (in case of coplanarity)
  1813. // use a fast estimated normalize ( i'll push this into mathlib later )
  1814. Vector delta = vend - vstart;
  1815. delta *= 8.0f * FastRSqrtFast((delta).LengthSqr()) ;
  1816. if ( BeamDebugOverlay() )
  1817. {
  1818. NDebugOverlay::Line( vstart + delta, vend, 255, 255, 0, true, 0.2f );
  1819. }
  1820. UTIL_TraceLine( vstart + delta , vend, colmask, NULL, colgroup, &tr );
  1821. if ( tr.fraction < 1.0f )
  1822. {
  1823. // move the endpoint to wherever the trace stopped
  1824. // if ( test_spam.GetBool() ) Msg( "(%s) %s\n", tr.startsolid ? "x" : " ", tr.m_pEnt->GetDebugName() );
  1825. if ( BeamDebugOverlay() )
  1826. NDebugOverlay::Cross( tr.endpos, 8, 255, 255, 0, false, 0.2f );
  1827. vend = tr.endpos;
  1828. }
  1829. }
  1830. //-----------------------------------------------------------------------------
  1831. // Draws a single beam
  1832. //-----------------------------------------------------------------------------
  1833. void CViewRenderBeams::DrawBeam( C_Beam* pbeam, const RenderableInstance_t &instance, ITraceFilter *pEntityBeamTraceFilter )
  1834. {
  1835. if ( !r_DrawBeams.GetInt() )
  1836. return;
  1837. Beam_t beam;
  1838. // Set up the beam.
  1839. int beamType = pbeam->GetType();
  1840. BeamInfo_t beamInfo;
  1841. beamInfo.m_vecStart = pbeam->GetAbsStartPos();
  1842. beamInfo.m_vecEnd = pbeam->GetAbsEndPos();
  1843. beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
  1844. beamInfo.m_nModelIndex = pbeam->GetModelIndex();
  1845. beamInfo.m_nHaloIndex = pbeam->m_nHaloIndex;
  1846. beamInfo.m_flHaloScale = pbeam->m_fHaloScale;
  1847. beamInfo.m_flLife = 0;
  1848. beamInfo.m_flWidth = pbeam->GetWidth();
  1849. beamInfo.m_flEndWidth = pbeam->GetEndWidth();
  1850. beamInfo.m_flFadeLength = pbeam->GetFadeLength();
  1851. beamInfo.m_flAmplitude = pbeam->GetNoise();
  1852. beamInfo.m_flBrightness = instance.m_nAlpha * (pbeam->GetRenderAlpha() / 255.0f);
  1853. beamInfo.m_flSpeed = pbeam->GetScrollRate();
  1854. beamInfo.m_nFlags = pbeam->GetBeamFlags();
  1855. if ( pbeam->GetBeamFlags() & FBEAM_REVERSED )
  1856. {
  1857. V_swap( beamInfo.m_vecStart, beamInfo.m_vecEnd );
  1858. V_swap( beamInfo.m_flWidth, beamInfo.m_flEndWidth );
  1859. }
  1860. SetupBeam( &beam, beamInfo );
  1861. beamInfo.m_nStartFrame = pbeam->m_fStartFrame;
  1862. beamInfo.m_flFrameRate = pbeam->m_flFrameRate;
  1863. beamInfo.m_flRed = pbeam->GetRenderColorR();
  1864. beamInfo.m_flGreen = pbeam->GetRenderColorG();
  1865. beamInfo.m_flBlue = pbeam->GetRenderColorB();
  1866. SetBeamAttributes( &beam, beamInfo );
  1867. if ( pbeam->m_nHaloIndex > 0 )
  1868. {
  1869. // HACKHACK: heuristic to estimate proxy size. Revisit this!
  1870. float size = 1.0f + (pbeam->m_fHaloScale * pbeam->m_fWidth / pbeam->m_fEndWidth);
  1871. size = clamp( size, 1.0f, 8.0f );
  1872. beam.m_queryHandleHalo = &pbeam->m_queryHandleHalo;
  1873. beam.m_haloProxySize = size;
  1874. }
  1875. else
  1876. {
  1877. beam.m_queryHandleHalo = NULL;
  1878. }
  1879. // Handle code from relinking.
  1880. switch( beamType )
  1881. {
  1882. case BEAM_ENTS:
  1883. {
  1884. beam.type = TE_BEAMPOINTS;
  1885. beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
  1886. beam.entity[0] = pbeam->m_hAttachEntity[0];
  1887. beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
  1888. beam.entity[1] = pbeam->m_hAttachEntity[1];
  1889. beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
  1890. beam.numAttachments = pbeam->m_nNumBeamEnts;
  1891. break;
  1892. }
  1893. case BEAM_LASER:
  1894. {
  1895. beam.type = TE_BEAMLASER;
  1896. beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
  1897. beam.entity[0] = pbeam->m_hAttachEntity[0];
  1898. beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
  1899. beam.entity[1] = pbeam->m_hAttachEntity[1];
  1900. beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
  1901. beam.numAttachments = pbeam->m_nNumBeamEnts;
  1902. break;
  1903. }
  1904. case BEAM_SPLINE:
  1905. {
  1906. beam.type = TE_BEAMSPLINE;
  1907. beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
  1908. beam.numAttachments = pbeam->m_nNumBeamEnts;
  1909. for (int i=0;i<beam.numAttachments;i++)
  1910. {
  1911. beam.entity[i] = pbeam->m_hAttachEntity[i];
  1912. beam.attachmentIndex[i] = pbeam->m_nAttachIndex[i];
  1913. }
  1914. break;
  1915. }
  1916. case BEAM_ENTPOINT:
  1917. {
  1918. beam.type = TE_BEAMPOINTS;
  1919. beam.flags = 0;
  1920. beam.entity[0] = pbeam->m_hAttachEntity[0];
  1921. beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
  1922. beam.entity[1] = pbeam->m_hAttachEntity[1];
  1923. beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
  1924. if ( beam.entity[0].Get() )
  1925. {
  1926. beam.flags |= FBEAM_STARTENTITY;
  1927. }
  1928. if ( beam.entity[1].Get() )
  1929. {
  1930. beam.flags |= FBEAM_ENDENTITY;
  1931. }
  1932. beam.numAttachments = pbeam->m_nNumBeamEnts;
  1933. break;
  1934. }
  1935. case BEAM_POINTS:
  1936. // Already set up
  1937. break;
  1938. }
  1939. beam.flags |= pbeam->GetBeamFlags() & (FBEAM_SINENOISE|FBEAM_SOLID|FBEAM_SHADEIN|FBEAM_SHADEOUT|FBEAM_NOTILE);
  1940. if ( beam.entity[0] )
  1941. {
  1942. // don't draw viewmodel effects in reflections
  1943. if ( CurrentViewID() == VIEW_REFLECTION )
  1944. {
  1945. if ( g_pClientLeafSystem->IsRenderingWithViewModels( beam.entity[0]->RenderHandle() ) )
  1946. return;
  1947. }
  1948. }
  1949. beam.m_flHDRColorScale = pbeam->GetHDRColorScale();
  1950. // per-frame update
  1951. UpdateBeam( &beam, gpGlobals->frametime, pbeam );
  1952. // draw!
  1953. DrawBeam( &beam );
  1954. }