aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/view_beams.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/view_beams.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/view_beams.cpp')
-rw-r--r--mp/src/game/client/view_beams.cpp2353
1 files changed, 2353 insertions, 0 deletions
diff --git a/mp/src/game/client/view_beams.cpp b/mp/src/game/client/view_beams.cpp
new file mode 100644
index 00000000..980c591e
--- /dev/null
+++ b/mp/src/game/client/view_beams.cpp
@@ -0,0 +1,2353 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "iviewrender_beams.h"
+#include "tempentity.h"
+#include "beam_shared.h"
+#include "ivieweffects.h"
+#include "beamdraw.h"
+#include "engine/ivdebugoverlay.h"
+#include "engine/ivmodelinfo.h"
+#include "view.h"
+#include "fx.h"
+#include "tier0/icommandline.h"
+#include "tier0/vprof.h"
+#include "c_pixel_visibility.h"
+#include "iviewrender.h"
+#include "view_shared.h"
+#include "viewrender.h"
+
+#ifdef PORTAL
+ #include "prop_portal_shared.h"
+#endif
+
+ConVar r_DrawBeams( "r_DrawBeams", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" );
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+bool g_BeamCreationAllowed = false;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : state -
+//-----------------------------------------------------------------------------
+void SetBeamCreationAllowed( bool state )
+{
+ g_BeamCreationAllowed = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool BeamCreationAllowed( void )
+{
+ return g_BeamCreationAllowed;
+}
+
+extern IViewEffects *vieweffects;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements beam rendering apis
+//-----------------------------------------------------------------------------
+class CViewRenderBeams : public IViewRenderBeams
+{
+// Construction
+public:
+ CViewRenderBeams( void );
+ virtual ~CViewRenderBeams( void );
+
+// Implement IViewRenderBeams
+public:
+ virtual void InitBeams( void );
+ virtual void ShutdownBeams( void );
+ virtual void ClearBeams( void );
+
+ // Updates the state of the temp ent beams
+ virtual void UpdateTempEntBeams();
+
+ virtual void DrawBeam( C_Beam* pbeam, ITraceFilter *pEntityBeamTraceFilter = NULL );
+ virtual void DrawBeam( Beam_t *pbeam );
+
+ virtual void KillDeadBeams( C_BaseEntity *pDeadEntity );
+
+ virtual Beam_t *CreateBeamEnts( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamEntPoint( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamPoints( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamRing( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamRingPoint( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamCirclePoints( BeamInfo_t &beamInfo );
+ virtual Beam_t *CreateBeamFollow( BeamInfo_t &beamInfo );
+
+ virtual void CreateBeamEnts( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float endWidth, float fadeLength, float amplitude,
+ float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b, int type = -1 );
+ virtual void CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, const Vector* pEnd,
+ int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float endWidth, float fadeLength, float amplitude,
+ float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b );
+ virtual void CreateBeamPoints( Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float endWidth, float fadeLength, float amplitude,
+ float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b );
+ virtual void CreateBeamRing( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float endWidth, float fadeLength, float amplitude,
+ float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b, int flags );
+ virtual void CreateBeamRingPoint( const Vector& center, float start_radius, float end_radius, int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float m_nEndWidth, float m_nFadeLength, float amplitude,
+ float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b, int flags );
+ virtual void CreateBeamCirclePoints( int type, Vector& start, Vector& end,
+ int modelIndex, int haloIndex, float haloScale, float life, float width,
+ float endWidth, float fadeLength, float amplitude, float brightness, float speed,
+ int startFrame, float framerate, float r, float g, float b );
+ virtual void CreateBeamFollow( int startEnt, int modelIndex, int haloIndex, float haloScale,
+ float life, float width, float endWidth, float fadeLength, float r, float g, float b,
+ float brightness );
+
+ virtual void FreeBeam( Beam_t *pBeam ) { BeamFree( pBeam ); }
+ virtual void UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo );
+
+private:
+ void FreeDeadTrails( BeamTrail_t **trail );
+ void UpdateBeam( Beam_t *pbeam, float frametime );
+ void DrawBeamWithHalo( Beam_t* pbeam,int frame,int rendermode,float *color, float *srcColor, const model_t *sprite,const model_t *halosprite, float flHDRColorScale );
+ void DrawBeamFollow( const model_t* pSprite, Beam_t *pbeam, int frame, int rendermode, float frametime, const float* color, float flHDRColorScale = 1.0f );
+ void DrawLaser( Beam_t* pBeam, int frame, int rendermode, float* color, model_t const* sprite, model_t const* halosprite, float flHDRColorScale = 1.0f );
+ void DrawTesla( Beam_t* pBeam, int frame, int rendermode, float* color, model_t const* sprite, float flHDRColorScale = 1.0f );
+
+ bool RecomputeBeamEndpoints( Beam_t *pbeam );
+
+ int CullBeam( const Vector &start, const Vector &end, int pvsOnly );
+
+ // Creation
+ Beam_t *CreateGenericBeam( BeamInfo_t &beamInfo );
+ void SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo );
+ void SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo );
+
+ // Memory Alloc/Free
+ Beam_t* BeamAlloc( bool bRenderable );
+ void BeamFree( Beam_t* pBeam );
+
+// DATA
+private:
+ enum
+ {
+
+#ifndef _XBOX
+ // default max # of particles at one time
+ DEFAULT_PARTICLES = 2048,
+#else
+ DEFAULT_PARTICLES = 1024,
+#endif
+
+ // no fewer than this no matter what's on the command line
+ MIN_PARTICLES = 512,
+
+#ifndef _XBOX
+ // Maximum length of the free list.
+ BEAM_FREELIST_MAX = 32
+#else
+ BEAM_FREELIST_MAX = 4
+#endif
+
+ };
+
+ Beam_t *m_pActiveBeams;
+ Beam_t *m_pFreeBeams;
+ int m_nBeamFreeListLength;
+
+ BeamTrail_t *m_pBeamTrails;
+ BeamTrail_t *m_pActiveTrails;
+ BeamTrail_t *m_pFreeTrails;
+ int m_nNumBeamTrails;
+};
+
+// Expose interface to rest of client .dll
+static CViewRenderBeams s_ViewRenderBeams;
+IViewRenderBeams *beams = ( IViewRenderBeams * )&s_ViewRenderBeams;
+
+CUniformRandomStream beamRandom;
+//-----------------------------------------------------------------------------
+// Global methods
+//-----------------------------------------------------------------------------
+
+// freq2 += step * 0.1;
+// Fractal noise generator, power of 2 wavelength
+static void Noise( float *noise, int divs, float scale )
+{
+ int div2;
+
+ div2 = divs >> 1;
+
+ if ( divs < 2 )
+ return;
+
+ // Noise is normalized to +/- scale
+ noise[ div2 ] = (noise[0] + noise[divs]) * 0.5 + scale * beamRandom.RandomFloat(-1, 1);
+ if ( div2 > 1 )
+ {
+ Noise( &noise[div2], div2, scale * 0.5 );
+ Noise( noise, div2, scale * 0.5 );
+ }
+}
+
+static void SineNoise( float *noise, int divs )
+{
+ int i;
+ float freq;
+ float step = M_PI / (float)divs;
+
+ freq = 0;
+ for ( i = 0; i < divs; i++ )
+ {
+ noise[i] = sin( freq );
+ freq += step;
+ }
+}
+
+bool ComputeBeamEntPosition( C_BaseEntity *pEnt, int nAttachment, bool bInterpretAttachmentIndexAsHitboxIndex, Vector& pt )
+{
+ // NOTE: This will *leave* the pt at its current value, essential for
+ // beam follow ents what want to stick around a little after their ent has died
+ if (!pEnt)
+ return false;
+
+ if ( !bInterpretAttachmentIndexAsHitboxIndex )
+ {
+ QAngle angles;
+ if ( pEnt->GetAttachment( nAttachment, pt, angles ) )
+ return true;
+ }
+ else
+ {
+ C_BaseAnimating *pAnimating = pEnt->GetBaseAnimating();
+ if ( pAnimating )
+ {
+ studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
+ if (pStudioHdr)
+ {
+ mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
+ if ( set && (set->numhitboxes >= nAttachment) && (nAttachment > 0) )
+ {
+ matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
+ if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
+ {
+ mstudiobbox_t *pHitbox = set->pHitbox( nAttachment - 1 );
+ Vector vecViewPt = MainViewOrigin();
+ Vector vecLocalViewPt;
+ VectorITransform( vecViewPt, *hitboxbones[ pHitbox->bone ], vecLocalViewPt );
+
+ Vector vecLocalClosestPt;
+ CalcClosestPointOnAABB( pHitbox->bbmin, pHitbox->bbmax, vecLocalViewPt, vecLocalClosestPt );
+
+ VectorTransform( vecLocalClosestPt, *hitboxbones[ pHitbox->bone ], pt );
+
+// MatrixGetColumn( *hitboxbones[ pHitbox->bone ], 3, pt );
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // Player origins are at their feet
+ if ( pEnt->IsPlayer() )
+ {
+ pt = pEnt->WorldSpaceCenter();
+ }
+ else
+ {
+ VectorCopy( pEnt->GetRenderOrigin(), pt );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Methods of Beam_t
+//
+//-----------------------------------------------------------------------------
+
+Beam_t::Beam_t()
+{
+#ifdef PORTAL
+ m_bDrawInMainRender = true;
+ m_bDrawInPortalRender = true;
+#endif
+
+ Reset();
+}
+
+
+void Beam_t::Reset()
+{
+ m_Mins.Init(0,0,0);
+ m_Maxs.Init(0,0,0);
+ type = 0;
+ flags = 0;
+ trail = 0;
+ m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE;
+ m_bCalculatedNoise = false;
+ m_queryHandleHalo = NULL;
+ m_flHDRColorScale = 1.0f;
+}
+
+
+const Vector& Beam_t::GetRenderOrigin( void )
+{
+ if ((type == TE_BEAMRING) || (type == TE_BEAMRINGPOINT))
+ {
+ // return the center of the ring
+ static Vector org;
+ VectorMA( attachment[0], 0.5f, delta, org );
+ return org;
+ }
+
+ return attachment[0];
+}
+
+const QAngle& Beam_t::GetRenderAngles( void )
+{
+ return vec3_angle;
+}
+
+const matrix3x4_t &Beam_t::RenderableToWorldTransform()
+{
+ static matrix3x4_t mat;
+ SetIdentityMatrix( mat );
+ PositionMatrix( GetRenderOrigin(), mat );
+ return mat;
+}
+
+
+void Beam_t::GetRenderBounds( Vector& mins, Vector& maxs )
+{
+ VectorCopy( m_Mins, mins );
+ VectorCopy( m_Maxs, maxs );
+}
+
+
+void Beam_t::ComputeBounds( )
+{
+ switch( type )
+ {
+ case TE_BEAMSPLINE:
+ {
+ // Here, we gotta look at all the attachments....
+ Vector attachmentDelta;
+ m_Mins.Init( 0,0,0 );
+ m_Maxs.Init( 0,0,0 );
+
+ for (int i=1; i < numAttachments; i++)
+ {
+ VectorSubtract( attachment[i], attachment[0], attachmentDelta );
+ m_Mins = m_Mins.Min( attachmentDelta );
+ m_Maxs = m_Maxs.Max( attachmentDelta );
+ }
+ }
+ break;
+
+ case TE_BEAMDISK:
+ case TE_BEAMCYLINDER:
+ {
+ // FIXME: This isn't quite right for the cylinder
+
+ // Here, delta[2] is the radius
+ int radius = delta[2];
+ m_Mins.Init( -radius, -radius, -radius );
+ m_Maxs.Init( radius, radius, radius );
+ }
+ break;
+
+ case TE_BEAMRING:
+ case TE_BEAMRINGPOINT:
+ {
+ int radius = delta.Length() * 0.5f;
+ m_Mins.Init( -radius, -radius, -radius );
+ m_Maxs.Init( radius, radius, radius );
+ }
+ break;
+
+ case TE_BEAMPOINTS:
+ default:
+ {
+ // Just use the delta
+ for (int i = 0; i < 3; ++i)
+ {
+ if (delta[i] > 0.0f)
+ {
+ m_Mins[i] = 0.0f;
+ m_Maxs[i] = delta[i];
+ }
+ else
+ {
+ m_Mins[i] = delta[i];
+ m_Maxs[i] = 0.0f;
+ }
+ }
+ }
+ break;
+ }
+
+ // Deal with beam follow
+ Vector org = GetRenderOrigin();
+ Vector followDelta;
+ BeamTrail_t* pFollow = trail;
+ while (pFollow)
+ {
+ VectorSubtract( pFollow->org, org, followDelta );
+ m_Mins = m_Mins.Min( followDelta );
+ m_Maxs = m_Maxs.Max( followDelta );
+
+ pFollow = pFollow->next;
+ }
+}
+
+bool Beam_t::ShouldDraw( void )
+{
+ return true;
+}
+
+bool Beam_t::IsTransparent( void )
+{
+ return true;
+}
+
+void Beam_t::ComputeFxBlend( )
+{
+ // Do nothing, they're always 255
+}
+
+int Beam_t::GetFxBlend( )
+{
+ return 255;
+}
+
+extern bool g_bRenderingScreenshot;
+extern ConVar r_drawviewmodel;
+
+int Beam_t::DrawModel( int flags )
+{
+#ifdef PORTAL
+ if ( ( !g_pPortalRender->IsRenderingPortal() && !m_bDrawInMainRender ) ||
+ ( g_pPortalRender->IsRenderingPortal() && !m_bDrawInPortalRender ) )
+ {
+ return 0;
+ }
+#endif //#ifdef PORTAL
+
+ // Tracker 16432: If rendering a savegame screenshot don't draw beams
+ // who have viewmodels as their attached entity
+ if ( g_bRenderingScreenshot || !r_drawviewmodel.GetBool() )
+ {
+ // If the beam is attached
+ for (int i=0;i<MAX_BEAM_ENTS;i++)
+ {
+ C_BaseViewModel *vm = dynamic_cast<C_BaseViewModel *>(entity[i].Get());
+ if ( vm )
+ {
+ return 0;
+ }
+ }
+ }
+
+ s_ViewRenderBeams.DrawBeam( this );
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Implementation of CViewRenderBeams
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor:
+//-----------------------------------------------------------------------------
+
+CViewRenderBeams::CViewRenderBeams( void ) : m_pBeamTrails(0)
+{
+ m_pFreeBeams = NULL;
+ m_pActiveBeams = NULL;
+ m_nBeamFreeListLength = 0;
+}
+
+CViewRenderBeams::~CViewRenderBeams( void )
+{
+ ClearBeams();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize beam system and beam trails for follow beams
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::InitBeams( void )
+{
+ int p = CommandLine()->ParmValue("-particles", -1);
+ if ( p >= 0 )
+ {
+ m_nNumBeamTrails = MAX( p, MIN_PARTICLES );
+ }
+ else
+ {
+ m_nNumBeamTrails = DEFAULT_PARTICLES;
+ }
+
+ m_pBeamTrails = (BeamTrail_t *)new BeamTrail_t[ m_nNumBeamTrails ];
+ Assert( m_pBeamTrails );
+
+ // Clear them out
+ ClearBeams();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear out all beams
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::ClearBeams( void )
+{
+ Beam_t *next = NULL;
+ for( ; m_pActiveBeams; m_pActiveBeams = next )
+ {
+ next = m_pActiveBeams->next;
+ delete m_pActiveBeams;
+ }
+
+ for( ; m_pFreeBeams; m_pFreeBeams = next )
+ {
+ next = m_pFreeBeams->next;
+ delete m_pFreeBeams;
+ }
+
+ m_nBeamFreeListLength = 0;
+
+ if ( m_nNumBeamTrails )
+ {
+ // Also clear any particles used by beams
+ m_pFreeTrails = &m_pBeamTrails[0];
+ m_pActiveTrails = NULL;
+
+ for (int i=0 ;i<m_nNumBeamTrails ; i++)
+ {
+ m_pBeamTrails[i].next = &m_pBeamTrails[i+1];
+ }
+ m_pBeamTrails[m_nNumBeamTrails-1].next = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shut down beam system
+//-----------------------------------------------------------------------------
+
+void CViewRenderBeams::ShutdownBeams( void )
+{
+ if (m_pBeamTrails)
+ {
+ delete[] m_pBeamTrails;
+ m_pActiveTrails = NULL;
+ m_pBeamTrails = NULL;
+ m_pFreeTrails = NULL;
+ m_nNumBeamTrails = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Try and allocate a free beam
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::BeamAlloc( bool bRenderable )
+{
+ Beam_t* pBeam = NULL;
+
+ if ( m_pFreeBeams )
+ {
+ pBeam = m_pFreeBeams;
+ m_pFreeBeams = pBeam->next;
+ m_nBeamFreeListLength--;
+ }
+ else
+ {
+ pBeam = new Beam_t();
+ if( !pBeam )
+ {
+ DevMsg( "ERROR: failed to alloc Beam_t!\n" );
+ Assert( pBeam );
+ }
+ }
+ pBeam->next = m_pActiveBeams;
+ m_pActiveBeams = pBeam;
+
+ if ( bRenderable )
+ {
+ // Hook it into the rendering system...
+ ClientLeafSystem()->AddRenderable( pBeam, RENDER_GROUP_TRANSLUCENT_ENTITY );
+ }
+ else
+ {
+ pBeam->m_hRenderHandle = INVALID_CLIENT_RENDER_HANDLE;
+ }
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Free the beam.
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::BeamFree( Beam_t* pBeam )
+{
+ // Free particles that have died off.
+ FreeDeadTrails( &pBeam->trail );
+
+ // Remove it from the rendering system...
+ ClientLeafSystem()->RemoveRenderable( pBeam->m_hRenderHandle );
+
+ // Clear us out
+ pBeam->Reset();
+
+ if( m_nBeamFreeListLength < BEAM_FREELIST_MAX )
+ {
+ m_nBeamFreeListLength++;
+
+ // Now link into free list;
+ pBeam->next = m_pFreeBeams;
+ m_pFreeBeams = pBeam;
+ }
+ else
+ {
+ delete pBeam;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Iterates through active list and kills beams associated with deadEntity
+// Input : deadEntity -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::KillDeadBeams( C_BaseEntity *pDeadEntity )
+{
+ Beam_t *pbeam;
+ Beam_t *pnewlist;
+ Beam_t *pnext;
+ BeamTrail_t *pHead; // Build a new list to replace m_pActiveBeams.
+
+ pbeam = m_pActiveBeams; // Old list.
+ pnewlist = NULL; // New list.
+
+ while (pbeam)
+ {
+ pnext = pbeam->next;
+ if (pbeam->entity[0] != pDeadEntity ) // Link into new list.
+ {
+ pbeam->next = pnewlist;
+ pnewlist = pbeam;
+
+ pbeam = pnext;
+ continue;
+ }
+
+ pbeam->flags &= ~(FBEAM_STARTENTITY | FBEAM_ENDENTITY);
+ if ( pbeam->type != TE_BEAMFOLLOW )
+ {
+ // Die Die Die!
+ pbeam->die = gpGlobals->curtime - 0.1;
+
+ // Kill off particles
+ pHead = pbeam->trail;
+ while (pHead)
+ {
+ pHead->die = gpGlobals->curtime - 0.1;
+ pHead = pHead->next;
+ }
+
+ // Free the beam
+ BeamFree( pbeam );
+ }
+ else
+ {
+ // Stay active
+ pbeam->next = pnewlist;
+ pnewlist = pbeam;
+ }
+ pbeam = pnext;
+ }
+
+ // We now have a new list with the bogus stuff released.
+ m_pActiveBeams = pnewlist;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill in values to beam structure.
+// Input: pBeam -
+// beamInfo -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo )
+{
+ const model_t *pSprite = modelinfo->GetModel( beamInfo.m_nModelIndex );
+ if ( !pSprite )
+ return;
+
+ pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType;
+ pBeam->modelIndex = beamInfo.m_nModelIndex;
+ pBeam->haloIndex = beamInfo.m_nHaloIndex;
+ pBeam->haloScale = beamInfo.m_flHaloScale;
+ pBeam->frame = 0;
+ pBeam->frameRate = 0;
+ pBeam->frameCount = modelinfo->GetModelFrameCount( pSprite );
+ pBeam->freq = gpGlobals->curtime * beamInfo.m_flSpeed;
+ pBeam->die = gpGlobals->curtime + beamInfo.m_flLife;
+ pBeam->width = beamInfo.m_flWidth;
+ pBeam->endWidth = beamInfo.m_flEndWidth;
+ pBeam->fadeLength = beamInfo.m_flFadeLength;
+ pBeam->amplitude = beamInfo.m_flAmplitude;
+ pBeam->brightness = beamInfo.m_flBrightness;
+ pBeam->speed = beamInfo.m_flSpeed;
+ pBeam->life = beamInfo.m_flLife;
+ pBeam->flags = 0;
+
+ VectorCopy( beamInfo.m_vecStart, pBeam->attachment[0] );
+ VectorCopy( beamInfo.m_vecEnd, pBeam->attachment[1] );
+ VectorSubtract( beamInfo.m_vecEnd, beamInfo.m_vecStart, pBeam->delta );
+ Assert( pBeam->delta.IsValid() );
+
+ if ( beamInfo.m_nSegments == -1 )
+ {
+ if ( pBeam->amplitude >= 0.50 )
+ {
+ pBeam->segments = VectorLength( pBeam->delta ) * 0.25 + 3; // one per 4 pixels
+ }
+ else
+ {
+ pBeam->segments = VectorLength( pBeam->delta ) * 0.075 + 3; // one per 16 pixels
+ }
+ }
+ else
+ {
+ pBeam->segments = beamInfo.m_nSegments;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set beam color and frame data.
+// Input: pBeam -
+// beamInfo -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo )
+{
+ pBeam->frame = ( float )beamInfo.m_nStartFrame;
+ pBeam->frameRate = beamInfo.m_flFrameRate;
+ pBeam->flags |= beamInfo.m_nFlags;
+
+ pBeam->r = beamInfo.m_flRed;
+ pBeam->g = beamInfo.m_flGreen;
+ pBeam->b = beamInfo.m_flBlue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cull beam by bbox
+// Input : *start -
+// *end -
+// pvsOnly -
+// Output : int
+//-----------------------------------------------------------------------------
+
+int CViewRenderBeams::CullBeam( const Vector &start, const Vector &end, int pvsOnly )
+{
+ Vector mins, maxs;
+ int i;
+
+ for ( i = 0; i < 3; i++ )
+ {
+ if ( start[i] < end[i] )
+ {
+ mins[i] = start[i];
+ maxs[i] = end[i];
+ }
+ else
+ {
+ mins[i] = end[i];
+ maxs[i] = start[i];
+ }
+
+ // Don't let it be zero sized
+ if ( mins[i] == maxs[i] )
+ {
+ maxs[i] += 1;
+ }
+ }
+
+ // Check bbox
+ if ( engine->IsBoxVisible( mins, maxs ) )
+ {
+ if ( pvsOnly || !engine->CullBox( mins, maxs ) )
+ {
+ // Beam is visible
+ return 1;
+ }
+ }
+
+ // Beam is not visible
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocate and setup a generic beam.
+// Input: beamInfo -
+// Output: Beam_t
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateGenericBeam( BeamInfo_t &beamInfo )
+{
+#if 0
+ if ( BeamCreationAllowed() == false )
+ {
+ //NOTENOTE: If you've hit this, you may not add a beam where you have attempted to.
+ // Most often this means that you have added it in an entity's DrawModel function.
+ // Move this to the ClientThink function instead!
+
+ DevMsg( "ERROR: Beam created too late in frame!\n" );
+ Assert(0);
+ return NULL;
+ }
+#endif
+
+ Beam_t *pBeam = BeamAlloc( beamInfo.m_bRenderable );
+ if ( !pBeam )
+ return NULL;
+
+ // In case we fail.
+ pBeam->die = gpGlobals->curtime;
+
+ // Need a valid model.
+ if ( beamInfo.m_nModelIndex < 0 )
+ return NULL;
+
+ // Set it up
+ SetupBeam( pBeam, beamInfo );
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam between two ents
+// Input : startEnt -
+// endEnt -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// BEAMENT_ENTITY(startEnt -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamEnts( int startEnt, int endEnt, int modelIndex,
+ int haloIndex, float haloScale, float life, float width, float endWidth,
+ float fadeLength, float amplitude, float brightness, float speed,
+ int startFrame, float framerate, float r, float g, float b, int type )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_nType = type;
+ beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
+ beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
+ beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( endEnt ) );
+ beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt );
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+
+ CreateBeamEnts( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam between two entities.
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamEnts( BeamInfo_t &beamInfo )
+{
+ // Don't start temporary beams out of the PVS
+ if ( beamInfo.m_flLife != 0 &&
+ ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->GetModel() == NULL ||
+ !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->GetModel() == NULL) )
+ {
+ return NULL;
+ }
+
+ beamInfo.m_vecStart = vec3_origin;
+ beamInfo.m_vecEnd = vec3_origin;
+
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType;
+ pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
+
+ pBeam->entity[0] = beamInfo.m_pStartEnt;
+ pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
+ pBeam->entity[1] = beamInfo.m_pEndEnt;
+ pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
+
+ // Attributes.
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ UpdateBeam( pBeam, 0 );
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a beam between an entity and a point
+// Input : startEnt -
+// *end -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// r -
+// g -
+// b -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, const Vector* pEnd,
+ int modelIndex, int haloIndex, float haloScale, float life, float width,
+ float endWidth, float fadeLength, float amplitude, float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b )
+{
+ BeamInfo_t beamInfo;
+
+ if ( nStartEntity <= 0 )
+ {
+ beamInfo.m_vecStart = pStart ? *pStart : vec3_origin;
+ beamInfo.m_pStartEnt = NULL;
+ }
+ else
+ {
+ beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( nStartEntity ) );
+ beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( nStartEntity );
+
+ // Don't start beams out of the PVS
+ if ( !beamInfo.m_pStartEnt )
+ return;
+ }
+
+ if ( nEndEntity <= 0 )
+ {
+ beamInfo.m_vecEnd = pEnd ? *pEnd : vec3_origin;
+ beamInfo.m_pEndEnt = NULL;
+ }
+ else
+ {
+ beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( nEndEntity ) );
+ beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( nEndEntity );
+
+ // Don't start beams out of the PVS
+ if ( !beamInfo.m_pEndEnt )
+ return;
+ }
+
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+
+ CreateBeamEntPoint( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a beam between an entity and a point.
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamEntPoint( BeamInfo_t &beamInfo )
+{
+ if ( beamInfo.m_flLife != 0 )
+ {
+ if ( beamInfo.m_pStartEnt && beamInfo.m_pStartEnt->GetModel() == NULL )
+ return NULL;
+
+ if ( beamInfo.m_pEndEnt && beamInfo.m_pEndEnt->GetModel() == NULL )
+ return NULL;
+ }
+
+ // Model index.
+ if ( ( beamInfo.m_pszModelName ) && ( beamInfo.m_nModelIndex == -1 ) )
+ {
+ beamInfo.m_nModelIndex = modelinfo->GetModelIndex( beamInfo.m_pszModelName );
+ }
+
+ if ( ( beamInfo.m_pszHaloName ) && ( beamInfo.m_nHaloIndex == -1 ) )
+ {
+ beamInfo.m_nHaloIndex = modelinfo->GetModelIndex( beamInfo.m_pszHaloName );
+ }
+
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = TE_BEAMPOINTS;
+ pBeam->flags = 0;
+
+ if ( beamInfo.m_pStartEnt )
+ {
+ pBeam->flags |= FBEAM_STARTENTITY;
+ pBeam->entity[0] = beamInfo.m_pStartEnt;
+ pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
+ beamInfo.m_vecStart = vec3_origin;
+ }
+ if ( beamInfo.m_pEndEnt )
+ {
+ pBeam->flags |= FBEAM_ENDENTITY;
+ pBeam->entity[1] = beamInfo.m_pEndEnt;
+ pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
+ beamInfo.m_vecEnd = vec3_origin;
+ }
+
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ UpdateBeam( pBeam, 0 );
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a beam between two points
+// Input : *start -
+// *end -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// r -
+// g -
+// b -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamPoints( Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale, float life, float width,
+ float endWidth, float fadeLength,float amplitude, float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_vecStart = start;
+ beamInfo.m_vecEnd = end;
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+
+ CreateBeamPoints( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a beam between two points.
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamPoints( BeamInfo_t &beamInfo )
+{
+ // Don't start temporary beams out of the PVS
+ if ( beamInfo.m_flLife != 0 && !CullBeam( beamInfo.m_vecStart, beamInfo.m_vecEnd, 1 ) )
+ return NULL;
+
+ // Model index.
+ if ( ( beamInfo.m_pszModelName ) && ( beamInfo.m_nModelIndex == -1 ) )
+ {
+ beamInfo.m_nModelIndex = modelinfo->GetModelIndex( beamInfo.m_pszModelName );
+ }
+
+ if ( ( beamInfo.m_pszHaloName ) && ( beamInfo.m_nHaloIndex == -1 ) )
+ {
+ beamInfo.m_nHaloIndex = modelinfo->GetModelIndex( beamInfo.m_pszHaloName );
+ }
+
+ // Create the new beam.
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ // Set beam initial state.
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a circular beam between two points
+// Input : type -
+// *start -
+// *end -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// r -
+// g -
+// b -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamCirclePoints( int type, Vector& start, Vector& end, int modelIndex, int haloIndex, float haloScale, float life, float width,
+ float endWidth, float fadeLength,float amplitude, float brightness, float speed, int startFrame,
+ float framerate, float r, float g, float b )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_nType = type;
+ beamInfo.m_vecStart = start;
+ beamInfo.m_vecEnd = end;
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+
+ CreateBeamCirclePoints( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a circular beam between two points.
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamCirclePoints( BeamInfo_t &beamInfo )
+{
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = beamInfo.m_nType;
+
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam which follows an entity
+// Input : startEnt -
+// modelIndex -
+// life -
+// width -
+// r -
+// g -
+// b -
+// brightness -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamFollow( int startEnt, int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth,
+ float fadeLength, float r, float g, float b, float brightness )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
+ beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+ beamInfo.m_flAmplitude = life;
+
+ CreateBeamFollow( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam which follows an entity.
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamFollow( BeamInfo_t &beamInfo )
+{
+ beamInfo.m_vecStart = vec3_origin;
+ beamInfo.m_vecEnd = vec3_origin;
+ beamInfo.m_flSpeed = 1.0f;
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = TE_BEAMFOLLOW;
+ pBeam->flags = FBEAM_STARTENTITY;
+ pBeam->entity[0] = beamInfo.m_pStartEnt;
+ pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
+
+ beamInfo.m_flFrameRate = 1.0f;
+ beamInfo.m_nStartFrame = 0;
+
+ SetBeamAttributes( pBeam, beamInfo );
+
+ UpdateBeam( pBeam, 0 );
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam ring between two entities
+// Input : startEnt -
+// endEnt -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// startEnt -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamRingPoint( const Vector& center, float start_radius, float end_radius,
+ int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth,
+ float fadeLength, float amplitude, float brightness, float speed, int startFrame, float framerate,
+ float r, float g, float b, int nFlags )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+ beamInfo.m_vecCenter = center;
+ beamInfo.m_flStartRadius = start_radius;
+ beamInfo.m_flEndRadius = end_radius;
+ beamInfo.m_nFlags = nFlags;
+
+ CreateBeamRingPoint( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam ring between two entities
+// Input: beamInfo -
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamRingPoint( BeamInfo_t &beamInfo )
+{
+ // ??
+ Vector endpos = beamInfo.m_vecCenter;
+
+ beamInfo.m_vecStart = beamInfo.m_vecCenter;
+ beamInfo.m_vecEnd = beamInfo.m_vecCenter;
+
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = TE_BEAMRINGPOINT;
+ pBeam->start_radius = beamInfo.m_flStartRadius;
+ pBeam->end_radius = beamInfo.m_flEndRadius;
+ pBeam->attachment[2] = beamInfo.m_vecCenter;
+
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam ring between two entities
+// Input : startEnt -
+// endEnt -
+// modelIndex -
+// life -
+// width -
+// amplitude -
+// brightness -
+// speed -
+// startFrame -
+// framerate -
+// startEnt -
+// Output : Beam_t
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::CreateBeamRing( int startEnt, int endEnt, int modelIndex, int haloIndex, float haloScale, float life, float width, float endWidth, float fadeLength,
+ float amplitude, float brightness, float speed, int startFrame, float framerate,
+ float r, float g, float b, int flags )
+{
+ BeamInfo_t beamInfo;
+
+ beamInfo.m_pStartEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( startEnt ) );
+ beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt );
+ beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( endEnt ) );
+ beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt );
+ beamInfo.m_nModelIndex = modelIndex;
+ beamInfo.m_nHaloIndex = haloIndex;
+ beamInfo.m_flHaloScale = haloScale;
+ beamInfo.m_flLife = life;
+ beamInfo.m_flWidth = width;
+ beamInfo.m_flEndWidth = endWidth;
+ beamInfo.m_flFadeLength = fadeLength;
+ beamInfo.m_flAmplitude = amplitude;
+ beamInfo.m_flBrightness = brightness;
+ beamInfo.m_flSpeed = speed;
+ beamInfo.m_nStartFrame = startFrame;
+ beamInfo.m_flFrameRate = framerate;
+ beamInfo.m_flRed = r;
+ beamInfo.m_flGreen = g;
+ beamInfo.m_flBlue = b;
+ beamInfo.m_nFlags = flags;
+
+ CreateBeamRing( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a beam ring between two entities.
+// Input: beamInfo -
+//-----------------------------------------------------------------------------
+Beam_t *CViewRenderBeams::CreateBeamRing( BeamInfo_t &beamInfo )
+{
+ // Don't start temporary beams out of the PVS
+ if ( beamInfo.m_flLife != 0 &&
+ ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->GetModel() == NULL ||
+ !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->GetModel() == NULL ) )
+ {
+ return NULL;
+ }
+
+ beamInfo.m_vecStart = vec3_origin;
+ beamInfo.m_vecEnd = vec3_origin;
+ Beam_t *pBeam = CreateGenericBeam( beamInfo );
+ if ( !pBeam )
+ return NULL;
+
+ pBeam->type = TE_BEAMRING;
+ pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
+ pBeam->entity[0] = beamInfo.m_pStartEnt;
+ pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment;
+ pBeam->entity[1] = beamInfo.m_pEndEnt;
+ pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment;
+
+ SetBeamAttributes( pBeam, beamInfo );
+ if ( beamInfo.m_flLife == 0 )
+ {
+ pBeam->flags |= FBEAM_FOREVER;
+ }
+
+ UpdateBeam( pBeam, 0 );
+
+ return pBeam;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Free dead trails associated with beam
+// Input : **ppparticles -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::FreeDeadTrails( BeamTrail_t **trail )
+{
+ BeamTrail_t *kill;
+ BeamTrail_t *p;
+
+ // kill all the ones hanging direcly off the base pointer
+ for ( ;; )
+ {
+ kill = *trail;
+ if (kill && kill->die < gpGlobals->curtime)
+ {
+ *trail = kill->next;
+ kill->next = m_pFreeTrails;
+ m_pFreeTrails = kill;
+ continue;
+ }
+ break;
+ }
+
+ // kill off all the others
+ for (p=*trail ; p ; p=p->next)
+ {
+ for ( ;; )
+ {
+ kill = p->next;
+ if (kill && kill->die < gpGlobals->curtime)
+ {
+ p->next = kill->next;
+ kill->next = m_pFreeTrails;
+ m_pFreeTrails = kill;
+ continue;
+ }
+ break;
+ }
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Updates beam state
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::UpdateBeam( Beam_t *pbeam, float frametime )
+{
+ if ( pbeam->modelIndex < 0 )
+ {
+ pbeam->die = gpGlobals->curtime;
+ return;
+ }
+
+ // if we are paused, force random numbers used by noise to generate the same value every frame
+ if ( frametime == 0.0f )
+ {
+ beamRandom.SetSeed( (int)gpGlobals->curtime );
+ }
+
+ // If FBEAM_ONLYNOISEONCE is set, we don't want to move once we've first calculated noise
+ if ( !(pbeam->flags & FBEAM_ONLYNOISEONCE ) )
+ {
+ pbeam->freq += frametime;
+ }
+ else
+ {
+ pbeam->freq += frametime * beamRandom.RandomFloat(1,2);
+ }
+
+ // OPTIMIZE: Do this every frame?
+ // UNDONE: Do this differentially somehow?
+ // Generate fractal noise
+ pbeam->rgNoise[0] = 0;
+ pbeam->rgNoise[NOISE_DIVISIONS] = 0;
+ if ( pbeam->amplitude != 0 )
+ {
+ if ( !(pbeam->flags & FBEAM_ONLYNOISEONCE ) || !pbeam->m_bCalculatedNoise )
+ {
+ if ( pbeam->flags & FBEAM_SINENOISE )
+ {
+ SineNoise( pbeam->rgNoise, NOISE_DIVISIONS );
+ }
+ else
+ {
+ Noise( pbeam->rgNoise, NOISE_DIVISIONS, 1.0 );
+ }
+
+ pbeam->m_bCalculatedNoise = true;
+ }
+ }
+
+ // update end points
+ if ( pbeam->flags & (FBEAM_STARTENTITY|FBEAM_ENDENTITY) )
+ {
+ // Makes sure attachment[0] + attachment[1] are valid
+ if (!RecomputeBeamEndpoints( pbeam ))
+ return;
+
+ // Compute segments from the new endpoints
+ VectorSubtract( pbeam->attachment[1], pbeam->attachment[0], pbeam->delta );
+ if ( pbeam->amplitude >= 0.50 )
+ pbeam->segments = VectorLength( pbeam->delta ) * 0.25 + 3; // one per 4 pixels
+ else
+ pbeam->segments = VectorLength( pbeam->delta ) * 0.075 + 3; // one per 16 pixels
+ }
+
+ // Get position data for spline beam
+ switch ( pbeam->type )
+ {
+ case TE_BEAMSPLINE:
+ {
+ // Why isn't attachment[0] being computed?
+ for (int i=1; i < pbeam->numAttachments; i++)
+ {
+ if (!ComputeBeamEntPosition( pbeam->entity[i], pbeam->attachmentIndex[i], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[i] ))
+ {
+ // This should never happen, but if for some reason the attachment doesn't exist,
+ // as a safety measure copy in the location of the previous attachment point (rather than bailing)
+ VectorCopy( pbeam->attachment[i-1], pbeam->attachment[i] );
+ }
+ }
+ }
+ break;
+
+ case TE_BEAMRINGPOINT:
+ {
+ //
+ float dr = pbeam->end_radius - pbeam->start_radius;
+ if ( dr != 0.0f )
+ {
+ float frac = 1.0f;
+ // Go some portion of the way there based on life
+ float remaining = pbeam->die - gpGlobals->curtime;
+ if ( remaining < pbeam->life && pbeam->life > 0.0f )
+ {
+ frac = remaining / pbeam->life;
+ }
+ frac = MIN( 1.0f, frac );
+ frac = MAX( 0.0f, frac );
+
+ frac = 1.0f - frac;
+
+ // Start pos
+ Vector endpos = pbeam->attachment[ 2 ];
+ endpos.x += ( pbeam->start_radius + frac * dr ) / 2.0f;
+ Vector startpos = pbeam->attachment[ 2 ];
+ startpos.x -= ( pbeam->start_radius + frac * dr ) / 2.0f;
+
+ pbeam->attachment[ 0 ] = startpos;
+ pbeam->attachment[ 1 ] = endpos;
+
+ VectorSubtract( pbeam->attachment[1], pbeam->attachment[0], pbeam->delta );
+ if (pbeam->amplitude >= 0.50)
+ pbeam->segments = VectorLength( pbeam->delta ) * 0.25 + 3; // one per 4 pixels
+ else
+ pbeam->segments = VectorLength( pbeam->delta ) * 0.075 + 3; // one per 16 pixels
+
+ }
+ }
+ break;
+
+ case TE_BEAMPOINTS:
+ // UNDONE: Build culling volumes for other types of beams
+ if ( !CullBeam( pbeam->attachment[0], pbeam->attachment[1], 0 ) )
+ return;
+ break;
+ }
+
+ // update life cycle
+ pbeam->t = pbeam->freq + (pbeam->die - gpGlobals->curtime);
+ if (pbeam->t != 0)
+ {
+ pbeam->t = pbeam->freq / pbeam->t;
+ }
+ else
+ {
+ pbeam->t = 1.0f;
+ }
+
+ // ------------------------------------------
+ // check for zero fadeLength (means no fade)
+ // ------------------------------------------
+ if (pbeam->fadeLength == 0)
+ {
+ Assert( pbeam->delta.IsValid() );
+ pbeam->fadeLength = pbeam->delta.Length();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Update beams created by temp entity system
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::UpdateTempEntBeams( void )
+{
+ VPROF_("UpdateTempEntBeams", 2, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
+ if ( !m_pActiveBeams )
+ return;
+
+ // Get frame time
+ float frametime = gpGlobals->frametime;
+
+ if ( frametime == 0.0f )
+ return;
+
+ // Draw temporary entity beams
+ Beam_t* pPrev = 0;
+ Beam_t* pNext;
+ for ( Beam_t* pBeam = m_pActiveBeams; pBeam ; pBeam = pNext )
+ {
+ // Need to store the next one since we may delete this one
+ pNext = pBeam->next;
+
+ // Retire old beams
+ if ( !(pBeam->flags & FBEAM_FOREVER) &&
+ pBeam->die <= gpGlobals->curtime )
+ {
+ // Reset links
+ if ( pPrev )
+ {
+ pPrev->next = pNext;
+ }
+ else
+ {
+ m_pActiveBeams = pNext;
+ }
+
+ // Free the beam
+ BeamFree( pBeam );
+
+ pBeam = NULL;
+ continue;
+ }
+
+ // Update beam state
+ UpdateBeam( pBeam, frametime );
+
+ // Compute bounds for the beam
+ pBeam->ComputeBounds();
+
+ // Indicates the beam moved
+ if ( pBeam->m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE )
+ {
+ ClientLeafSystem()->RenderableChanged( pBeam->m_hRenderHandle );
+ }
+
+ pPrev = pBeam;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw helper for beam follow beams
+// Input : *pbeam -
+// frametime -
+// *color -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::DrawBeamFollow( const model_t* pSprite, Beam_t *pbeam,
+ int frame, int rendermode, float frametime, const float* color, float flHDRColorScale )
+{
+ BeamTrail_t *particles;
+ BeamTrail_t *pnew;
+ float div;
+ Vector delta;
+
+ Vector screenLast;
+ Vector screen;
+
+ FreeDeadTrails( &pbeam->trail );
+
+ particles = pbeam->trail;
+ pnew = NULL;
+
+ div = 0;
+ if ( pbeam->flags & FBEAM_STARTENTITY )
+ {
+ if (particles)
+ {
+ VectorSubtract( particles->org, pbeam->attachment[0], delta );
+ div = VectorLength( delta );
+ if (div >= 32 && m_pFreeTrails)
+ {
+ pnew = m_pFreeTrails;
+ m_pFreeTrails = pnew->next;
+ }
+ }
+ else if (m_pFreeTrails)
+ {
+ pnew = m_pFreeTrails;
+ m_pFreeTrails = pnew->next;
+ div = 0;
+ }
+ }
+
+ if (pnew)
+ {
+ VectorCopy( pbeam->attachment[0], pnew->org );
+ pnew->die = gpGlobals->curtime + pbeam->amplitude;
+ VectorCopy( vec3_origin, pnew->vel );
+
+ pbeam->die = gpGlobals->curtime + pbeam->amplitude;
+ pnew->next = particles;
+ pbeam->trail = pnew;
+ particles = pnew;
+ }
+
+ if (!particles)
+ {
+ return;
+ }
+ if (!pnew && div != 0)
+ {
+ VectorCopy( pbeam->attachment[0], delta );
+ debugoverlay->ScreenPosition( pbeam->attachment[0], screenLast );
+ debugoverlay->ScreenPosition( particles->org, screen );
+ }
+ else if (particles && particles->next)
+ {
+ VectorCopy( particles->org, delta );
+ debugoverlay->ScreenPosition( particles->org, screenLast );
+ debugoverlay->ScreenPosition( particles->next->org, screen );
+ particles = particles->next;
+ }
+ else
+ {
+ return;
+ }
+
+ // Draw it
+ ::DrawBeamFollow( pSprite, pbeam->trail, frame, rendermode, delta, screen, screenLast,
+ pbeam->die, pbeam->attachment[0], pbeam->flags, pbeam->width,
+ pbeam->amplitude, pbeam->freq, (float*)color );
+
+ // Drift popcorn trail if there is a velocity
+ particles = pbeam->trail;
+ while (particles)
+ {
+ VectorMA( particles->org, frametime, particles->vel, particles->org );
+ particles = particles->next;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Draw beam with a halo
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CViewRenderBeams::DrawBeamWithHalo( Beam_t* pbeam,
+ int frame,
+ int rendermode,
+ float* color,
+ float* srcColor,
+ const model_t *sprite,
+ const model_t *halosprite,
+ float flHDRColorScale )
+{
+ Vector beamDir = pbeam->attachment[1] - pbeam->attachment[0];
+ VectorNormalize( beamDir );
+
+ Vector localDir = CurrentViewOrigin() - pbeam->attachment[0];
+ VectorNormalize( localDir );
+
+ float dotpr = DotProduct( beamDir, localDir );
+ float fade;
+
+ if ( dotpr < 0.0f )
+ {
+ fade = 0;
+ }
+ else
+ {
+ fade = dotpr * 2.0f;
+ }
+
+ float distToLine;
+ Vector out;
+
+ // Find out how close we are to the "line" of the spotlight
+ CalcClosestPointOnLine( CurrentViewOrigin(), pbeam->attachment[0], pbeam->attachment[0] + ( beamDir * 2 ), out, &distToLine );
+
+ distToLine = ( CurrentViewOrigin() - out ).Length();
+
+ float scaleColor[4];
+ float dotScale = 1.0f;
+
+ // Use beam width
+ float distThreshold = pbeam->width * 4.0f;
+
+ if ( distToLine < distThreshold )
+ {
+ dotScale = RemapVal( distToLine, distThreshold, pbeam->width, 1.0f, 0.0f );
+ dotScale = clamp( dotScale, 0.f, 1.f );
+ }
+
+ scaleColor[0] = color[0] * dotScale;
+ scaleColor[1] = color[1] * dotScale;
+ scaleColor[2] = color[2] * dotScale;
+ scaleColor[3] = color[3] * dotScale;
+
+ if( pbeam->flags & FBEAM_HALOBEAM )
+ {
+ 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, scaleColor, pbeam->fadeLength, flHDRColorScale );
+ }
+ else
+ {
+ // Draw primary beam just shy of its end so it doesn't clip
+ DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode, pbeam->attachment[0],
+ pbeam->delta, pbeam->width, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed,
+ 2, pbeam->flags, scaleColor, pbeam->fadeLength, flHDRColorScale );
+ }
+
+ Vector vSource = pbeam->attachment[0];
+
+ pixelvis_queryparams_t params;
+ params.Init( vSource, pbeam->m_haloProxySize );
+
+ float haloFractionVisible = PixelVisibility_FractionVisible( params, pbeam->m_queryHandleHalo );
+ if ( fade && haloFractionVisible > 0.0f )
+ {
+ //NOTENOTE: This is kinda funky when moving away and to the backside -- jdw
+ float haloScale = RemapVal( distToLine, distThreshold, pbeam->width*0.5f, 1.0f, 2.0f );
+
+ haloScale = clamp( haloScale, 1.0f, 2.0f );
+
+ haloScale *= pbeam->haloScale;
+
+ float colorFade = fade*fade;
+ colorFade = clamp( colorFade, 0.f, 1.f );
+
+ float haloColor[3];
+ VectorScale( srcColor, colorFade * haloFractionVisible, haloColor );
+
+ BeamDrawHalo( halosprite, frame, kRenderGlow, vSource, haloScale, haloColor, flHDRColorScale );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose : Draw a beam based upon the viewpoint
+//------------------------------------------------------------------------------
+void CViewRenderBeams::DrawLaser( Beam_t *pbeam, int frame, int rendermode, float *color, const model_t *sprite, const model_t *halosprite, float flHDRColorScale )
+{
+ float color2[3];
+ VectorCopy( color, color2 );
+
+ Vector vecForward;
+ Vector beamDir = pbeam->attachment[1] - pbeam->attachment[0];
+ VectorNormalize( beamDir );
+ AngleVectors( CurrentViewAngles(), &vecForward );
+ float flDot = DotProduct(beamDir, vecForward);
+
+ // abort if the player's looking along it away from the source
+ if ( flDot > 0 )
+ {
+ return;
+ }
+ else
+ {
+ // Fade the beam if the player's not looking at the source
+ float flFade = pow( flDot, 10 );
+
+ // Fade the beam based on the player's proximity to the beam
+ Vector localDir = CurrentViewOrigin() - pbeam->attachment[0];
+ flDot = DotProduct( beamDir, localDir );
+ Vector vecProjection = flDot * beamDir;
+ float flDistance = ( localDir - vecProjection ).Length();
+
+ if ( flDistance > 30 )
+ {
+ flDistance = 1 - ((flDistance - 30) / 64);
+ if ( flDistance <= 0 )
+ {
+ flFade = 0;
+ }
+ else
+ {
+ flFade *= pow( flDistance, 3 );
+ }
+ }
+
+ if (flFade < (1.0f / 255.0f))
+ return;
+
+ VectorScale( color2, flFade, color2 );
+
+ //engine->Con_NPrintf( 6, "Fade: %f", flFade );
+ //engine->Con_NPrintf( 7, "Dist: %f", flDistance );
+ }
+
+ 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);
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Draw a fibrous tesla beam
+//------------------------------------------------------------------------------
+void CViewRenderBeams::DrawTesla( Beam_t *pbeam, int frame, int rendermode, float *color, const model_t *sprite, float flHDRColorScale )
+{
+ 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 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw all beam entities
+// Input : *pbeam -
+// frametime -
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::DrawBeam( Beam_t *pbeam )
+{
+ Assert( pbeam->delta.IsValid() );
+
+ if ( !r_DrawBeams.GetInt() )
+ return;
+
+ // Don't draw really short beams
+ if (pbeam->delta.Length() < 0.1)
+ {
+ return;
+ }
+
+ const model_t *sprite;
+ const model_t *halosprite = NULL;
+
+ if ( pbeam->modelIndex < 0 )
+ {
+ pbeam->die = gpGlobals->curtime;
+ return;
+ }
+
+ sprite = modelinfo->GetModel( pbeam->modelIndex );
+ if ( !sprite )
+ {
+ return;
+ }
+
+ halosprite = modelinfo->GetModel( pbeam->haloIndex );
+
+ int frame = ( ( int )( pbeam->frame + gpGlobals->curtime * pbeam->frameRate) % pbeam->frameCount );
+ int rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd;
+
+ // set color
+ float srcColor[3];
+ float color[3];
+
+ srcColor[0] = pbeam->r;
+ srcColor[1] = pbeam->g;
+ srcColor[2] = pbeam->b;
+ if ( pbeam->flags & FBEAM_FADEIN )
+ {
+ VectorScale( srcColor, pbeam->t, color );
+ }
+ else if ( pbeam->flags & FBEAM_FADEOUT )
+ {
+ VectorScale( srcColor, ( 1.0f - pbeam->t ), color );
+ }
+ else
+ {
+ VectorCopy( srcColor, color );
+ }
+
+ VectorScale( color, (1/255.0), color );
+ VectorCopy( color, srcColor );
+ VectorScale( color, ((float)pbeam->brightness / 255.0), color );
+
+ switch( pbeam->type )
+ {
+ case TE_BEAMDISK:
+ DrawDisk( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode,
+ pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
+ pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMCYLINDER:
+ DrawCylinder( NOISE_DIVISIONS, pbeam->rgNoise, sprite, frame, rendermode,
+ pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
+ pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMPOINTS:
+ if (halosprite)
+ {
+ DrawBeamWithHalo( pbeam, frame, rendermode, color, srcColor, sprite, halosprite, pbeam->m_flHDRColorScale );
+ }
+ else
+ {
+ 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, color, pbeam->fadeLength, pbeam->m_flHDRColorScale );
+ }
+ break;
+
+ case TE_BEAMFOLLOW:
+ DrawBeamFollow( sprite, pbeam, frame, rendermode, gpGlobals->frametime, color, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMRING:
+ case TE_BEAMRINGPOINT:
+ DrawRing( NOISE_DIVISIONS, pbeam->rgNoise, Noise, sprite, frame, rendermode,
+ pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude,
+ pbeam->freq, pbeam->speed, pbeam->segments, color, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMSPLINE:
+ DrawSplineSegs( NOISE_DIVISIONS, pbeam->rgNoise, sprite, halosprite,
+ pbeam->haloScale, frame, rendermode, pbeam->numAttachments,
+ pbeam->attachment, pbeam->width, pbeam->endWidth, pbeam->amplitude,
+ pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags, color, pbeam->fadeLength, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMLASER:
+ DrawLaser( pbeam, frame, rendermode, color, sprite, halosprite, pbeam->m_flHDRColorScale );
+ break;
+
+ case TE_BEAMTESLA:
+ DrawTesla( pbeam, frame, rendermode, color, sprite, pbeam->m_flHDRColorScale );
+ break;
+
+ default:
+ DevWarning( 1, "CViewRenderBeams::DrawBeam: Unknown beam type %i\n", pbeam->type );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update the beam
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo )
+{
+ pBeam->attachment[0] = beamInfo.m_vecStart;
+ pBeam->attachment[1] = beamInfo.m_vecEnd;
+ pBeam->delta = beamInfo.m_vecEnd - beamInfo.m_vecStart;
+
+ Assert( pBeam->delta.IsValid() );
+
+ SetBeamAttributes( pBeam, beamInfo );
+}
+
+
+//-----------------------------------------------------------------------------
+// Recomputes beam endpoints..
+//-----------------------------------------------------------------------------
+bool CViewRenderBeams::RecomputeBeamEndpoints( Beam_t *pbeam )
+{
+ if ( pbeam->flags & FBEAM_STARTENTITY )
+ {
+ if (ComputeBeamEntPosition( pbeam->entity[0], pbeam->attachmentIndex[0], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[0] ))
+ {
+ pbeam->flags |= FBEAM_STARTVISIBLE;
+ }
+ else if (! (pbeam->flags & FBEAM_FOREVER))
+ {
+ pbeam->flags &= ~(FBEAM_STARTENTITY);
+ }
+ else
+ {
+ // DevWarning( 1,"can't find start entity\n");
+// return false;
+ }
+
+ // If we've never seen the start entity, don't display
+ if ( !(pbeam->flags & FBEAM_STARTVISIBLE) )
+ return false;
+ }
+
+ if ( pbeam->flags & FBEAM_ENDENTITY )
+ {
+ if (ComputeBeamEntPosition( pbeam->entity[1], pbeam->attachmentIndex[1], (pbeam->flags & FBEAM_USE_HITBOXES) != 0, pbeam->attachment[1] ))
+ {
+ pbeam->flags |= FBEAM_ENDVISIBLE;
+ }
+ else if (! (pbeam->flags & FBEAM_FOREVER))
+ {
+ pbeam->flags &= ~(FBEAM_ENDENTITY);
+ pbeam->die = gpGlobals->curtime;
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+
+ // If we've never seen the end entity, don't display
+ if ( !(pbeam->flags & FBEAM_ENDVISIBLE) )
+ return false;
+ }
+
+ return true;
+}
+
+#ifdef PORTAL
+ bool bBeamDrawingThroughPortal = false;
+#endif
+
+//-----------------------------------------------------------------------------
+// Draws a single beam
+//-----------------------------------------------------------------------------
+void CViewRenderBeams::DrawBeam( C_Beam* pbeam, ITraceFilter *pEntityBeamTraceFilter )
+{
+ Beam_t beam;
+
+ // Set up the beam.
+ int beamType = pbeam->GetType();
+
+ BeamInfo_t beamInfo;
+ beamInfo.m_vecStart = pbeam->GetAbsStartPos();
+ beamInfo.m_vecEnd = pbeam->GetAbsEndPos();
+ beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
+ beamInfo.m_nModelIndex = pbeam->GetModelIndex();
+ beamInfo.m_nHaloIndex = pbeam->m_nHaloIndex;
+ beamInfo.m_flHaloScale = pbeam->m_fHaloScale;
+ beamInfo.m_flLife = 0;
+ beamInfo.m_flWidth = pbeam->GetWidth();
+ beamInfo.m_flEndWidth = pbeam->GetEndWidth();
+ beamInfo.m_flFadeLength = pbeam->GetFadeLength();
+ beamInfo.m_flAmplitude = pbeam->GetNoise();
+ beamInfo.m_flBrightness = pbeam->GetFxBlend();
+ beamInfo.m_flSpeed = pbeam->GetScrollRate();
+
+#ifdef PORTAL // Beams need to recursively draw through portals
+ // Trace to see if we've intersected a portal
+ float fEndFraction;
+ Ray_t rayBeam;
+
+ bool bIsReversed = ( pbeam->GetBeamFlags() & FBEAM_REVERSED ) != 0x0;
+
+ Vector vRayStartPoint, vRayEndPoint;
+
+ vRayStartPoint = beamInfo.m_vecStart;
+ vRayEndPoint = beamInfo.m_vecEnd;
+
+ if ( beamType == BEAM_ENTPOINT || beamType == BEAM_ENTS || beamType == BEAM_LASER )
+ {
+ ComputeBeamEntPosition( pbeam->m_hAttachEntity[0], pbeam->m_nAttachIndex[0], false, vRayStartPoint );
+ ComputeBeamEntPosition( pbeam->m_hAttachEntity[1], pbeam->m_nAttachIndex[1], false, vRayEndPoint );
+ }
+
+ if ( !bIsReversed )
+ rayBeam.Init( vRayStartPoint, vRayEndPoint );
+ else
+ rayBeam.Init( vRayEndPoint, vRayStartPoint );
+
+ CBaseEntity *pStartEntity = pbeam->GetStartEntityPtr();
+
+ CTraceFilterSkipClassname traceFilter( pStartEntity, "prop_energy_ball", COLLISION_GROUP_NONE );
+
+ if ( !pEntityBeamTraceFilter && pStartEntity )
+ pEntityBeamTraceFilter = pStartEntity->GetBeamTraceFilter();
+
+ CTraceFilterChain traceFilterChain( &traceFilter, pEntityBeamTraceFilter );
+
+ C_Prop_Portal *pPortal = UTIL_Portal_TraceRay_Beam( rayBeam, MASK_SHOT, &traceFilterChain, &fEndFraction );
+
+ // Get the point that we hit a portal or wall
+ Vector vEndPoint = rayBeam.m_Start + rayBeam.m_Delta * fEndFraction;
+
+ if ( pPortal )
+ {
+ // Prevent infinite recursion by lower the brightness each call
+ int iOldBrightness = pbeam->GetBrightness();
+
+ if ( iOldBrightness > 16 )
+ {
+ // Remember the old values of the beam before changing it for the next call
+ Vector vOldStart = pbeam->GetAbsStartPos();
+ Vector vOldEnd = pbeam->GetAbsEndPos();
+ //float fOldWidth = pbeam->GetEndWidth();
+ C_BaseEntity *pOldStartEntity = pbeam->GetStartEntityPtr();
+ C_BaseEntity *pOldEndEntity = pbeam->GetEndEntityPtr();
+ int iOldStartAttachment = pbeam->GetStartAttachment();
+ int iOldEndAttachment = pbeam->GetEndAttachment();
+ int iOldType = pbeam->GetType();
+
+ // Get the transformed positions of the sub beam in the other portal's space
+ Vector vTransformedStart, vTransformedEnd;
+ VMatrix matThisToLinked = pPortal->MatrixThisToLinked();
+ UTIL_Portal_PointTransform( matThisToLinked, vEndPoint, vTransformedStart );
+ UTIL_Portal_PointTransform( matThisToLinked, rayBeam.m_Start + rayBeam.m_Delta, vTransformedEnd );
+
+ // Set up the sub beam for the next call
+ pbeam->SetBrightness( iOldBrightness - 16 );
+ if ( bIsReversed )
+ pbeam->PointsInit( vTransformedEnd, vTransformedStart );
+ else
+ pbeam->PointsInit( vTransformedStart, vTransformedEnd );
+ if ( bIsReversed )
+ pbeam->SetEndWidth( pbeam->GetWidth() );
+ pbeam->SetStartEntity( pPortal->m_hLinkedPortal );
+
+ // Draw the sub beam
+ bBeamDrawingThroughPortal = true;
+ DrawBeam( pbeam, pEntityBeamTraceFilter );
+ bBeamDrawingThroughPortal = true;
+
+ // Restore the original values
+ pbeam->SetBrightness( iOldBrightness );
+ pbeam->SetStartPos( vOldStart );
+ pbeam->SetEndPos( vOldEnd );
+ //if ( bIsReversed )
+ // pbeam->SetEndWidth( fOldWidth );
+ if ( pOldStartEntity )
+ pbeam->SetStartEntity( pOldStartEntity );
+ if ( pOldEndEntity )
+ pbeam->SetEndEntity( pOldEndEntity );
+ pbeam->SetStartAttachment( iOldStartAttachment );
+ pbeam->SetEndAttachment( iOldEndAttachment );
+ pbeam->SetType( iOldType );
+
+ // Doesn't use a hallow or taper the beam because we recursed
+ beamInfo.m_nHaloIndex = 0;
+ if ( !bIsReversed )
+ beamInfo.m_flEndWidth = beamInfo.m_flWidth;
+ }
+ }
+
+ // Clip to the traced end point (portal or wall)
+ if ( bBeamDrawingThroughPortal )
+ {
+ if ( bIsReversed )
+ beamInfo.m_vecStart = vEndPoint;
+ else
+ beamInfo.m_vecEnd = vEndPoint;
+ }
+
+ bBeamDrawingThroughPortal = false;
+#endif
+
+ SetupBeam( &beam, beamInfo );
+
+ beamInfo.m_nStartFrame = pbeam->m_fStartFrame;
+ beamInfo.m_flFrameRate = pbeam->m_flFrameRate;
+ beamInfo.m_flRed = pbeam->m_clrRender->r;
+ beamInfo.m_flGreen = pbeam->m_clrRender->g;
+ beamInfo.m_flBlue = pbeam->m_clrRender->b;
+
+ SetBeamAttributes( &beam, beamInfo );
+
+ if ( pbeam->m_nHaloIndex > 0 )
+ {
+ // HACKHACK: heuristic to estimate proxy size. Revisit this!
+ float size = 1.0f + (pbeam->m_fHaloScale * pbeam->m_fWidth / pbeam->m_fEndWidth);
+ size = clamp( size, 1.0f, 8.0f );
+ beam.m_queryHandleHalo = &pbeam->m_queryHandleHalo;
+ beam.m_haloProxySize = size;
+ }
+ else
+ {
+ beam.m_queryHandleHalo = NULL;
+ }
+
+ // Handle code from relinking.
+ switch( beamType )
+ {
+ case BEAM_ENTS:
+ {
+ beam.type = TE_BEAMPOINTS;
+ beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
+ beam.entity[0] = pbeam->m_hAttachEntity[0];
+ beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
+ beam.entity[1] = pbeam->m_hAttachEntity[1];
+ beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
+ beam.numAttachments = pbeam->m_nNumBeamEnts;
+ break;
+ }
+ case BEAM_LASER:
+ {
+ beam.type = TE_BEAMLASER;
+ beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
+ beam.entity[0] = pbeam->m_hAttachEntity[0];
+ beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
+ beam.entity[1] = pbeam->m_hAttachEntity[1];
+ beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
+ beam.numAttachments = pbeam->m_nNumBeamEnts;
+ break;
+ }
+ case BEAM_SPLINE:
+ {
+ beam.type = TE_BEAMSPLINE;
+ beam.flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY;
+ beam.numAttachments = pbeam->m_nNumBeamEnts;
+ for (int i=0;i<beam.numAttachments;i++)
+ {
+ beam.entity[i] = pbeam->m_hAttachEntity[i];
+ beam.attachmentIndex[i] = pbeam->m_nAttachIndex[i];
+ }
+ break;
+ }
+ case BEAM_ENTPOINT:
+ {
+ beam.type = TE_BEAMPOINTS;
+ beam.flags = 0;
+ beam.entity[0] = pbeam->m_hAttachEntity[0];
+ beam.attachmentIndex[0] = pbeam->m_nAttachIndex[0];
+ beam.entity[1] = pbeam->m_hAttachEntity[1];
+ beam.attachmentIndex[1] = pbeam->m_nAttachIndex[1];
+ if ( beam.entity[0].Get() )
+ {
+ beam.flags |= FBEAM_STARTENTITY;
+ }
+ if ( beam.entity[1].Get() )
+ {
+ beam.flags |= FBEAM_ENDENTITY;
+ }
+ beam.numAttachments = pbeam->m_nNumBeamEnts;
+ break;
+ }
+ case BEAM_POINTS:
+ // Already set up
+ break;
+ }
+
+ beam.flags |= pbeam->GetBeamFlags() & (FBEAM_SINENOISE|FBEAM_SOLID|FBEAM_SHADEIN|FBEAM_SHADEOUT|FBEAM_NOTILE);
+
+ if ( beam.entity[0] )
+ {
+ // don't draw viewmodel effects in reflections
+ if ( CurrentViewID() == VIEW_REFLECTION )
+ {
+ int group = beam.entity[0]->GetRenderGroup();
+ if (group == RENDER_GROUP_VIEW_MODEL_TRANSLUCENT || group == RENDER_GROUP_VIEW_MODEL_OPAQUE)
+ return;
+ }
+ }
+
+ beam.m_flHDRColorScale = pbeam->GetHDRColorScale();
+
+ // Draw it
+ UpdateBeam( &beam, gpGlobals->frametime );
+ DrawBeam( &beam );
+}