diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/view_beams.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/view_beams.cpp')
| -rw-r--r-- | mp/src/game/client/view_beams.cpp | 4706 |
1 files changed, 2353 insertions, 2353 deletions
diff --git a/mp/src/game/client/view_beams.cpp b/mp/src/game/client/view_beams.cpp index 980c591e..d8881244 100644 --- a/mp/src/game/client/view_beams.cpp +++ b/mp/src/game/client/view_beams.cpp @@ -1,2353 +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 );
-}
+//========= 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 ); +} |