From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/view_beams.cpp | 4706 ++++++++++++++++++------------------- 1 file changed, 2353 insertions(+), 2353 deletions(-) (limited to 'mp/src/game/client/view_beams.cpp') 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(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 ;inext; - 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;im_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(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 ;inext; + 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;im_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 ); +} -- cgit v1.2.3