aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/beamdraw.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/beamdraw.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/beamdraw.cpp')
-rw-r--r--mp/src/game/client/beamdraw.cpp3052
1 files changed, 1526 insertions, 1526 deletions
diff --git a/mp/src/game/client/beamdraw.cpp b/mp/src/game/client/beamdraw.cpp
index 27a27cd2..2bba8efe 100644
--- a/mp/src/game/client/beamdraw.cpp
+++ b/mp/src/game/client/beamdraw.cpp
@@ -1,1526 +1,1526 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-
-#include "cbase.h"
-#include "beamdraw.h"
-#include "enginesprite.h"
-#include "iviewrender_beams.h"
-#include "view.h"
-#include "iviewrender.h"
-#include "engine/ivmodelinfo.h"
-#include "fx_line.h"
-#include "materialsystem/imaterialvar.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-extern ConVar r_drawsprites;
-extern ConVar r_DrawBeams;
-
-static IMaterial *g_pBeamWireframeMaterial;
-
-//-----------------------------------------------------------------------------
-// Purpose: Retrieve sprite object and set it up for rendering
-// Input : *pSpriteModel -
-// frame -
-// rendermode -
-// Output : CEngineSprite
-//-----------------------------------------------------------------------------
-CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode )
-{
- CEngineSprite *psprite;
- IMaterial *material;
-
- psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( pSpriteModel );
- Assert( psprite );
-
- material = psprite->GetMaterial( (RenderMode_t)rendermode, frame );
- if( !material )
- return NULL;
-
- CMatRenderContextPtr pRenderContext( materials );
- if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 )
- {
- if ( !g_pBeamWireframeMaterial )
- g_pBeamWireframeMaterial = materials->FindMaterial( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER );
- pRenderContext->Bind( g_pBeamWireframeMaterial, NULL );
- return psprite;
- }
-
- pRenderContext->Bind( material );
- return psprite;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : pMaterial -
-// source -
-// color -
-//-----------------------------------------------------------------------------
-void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale )
-{
- static unsigned int nHDRColorScaleCache = 0;
- Vector point, screen;
-
- if( pMaterial )
- {
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
-
- // Transform source into screen space
- ScreenTransform( source, screen );
-
- meshBuilder.Color3fv (color);
- meshBuilder.TexCoord2f (0, 0, 1);
- VectorMA (source, -scale, CurrentViewUp(), point);
- VectorMA (point, -scale, CurrentViewRight(), point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color3fv (color);
- meshBuilder.TexCoord2f (0, 0, 0);
- VectorMA (source, scale, CurrentViewUp(), point);
- VectorMA (point, -scale, CurrentViewRight(), point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color3fv (color);
- meshBuilder.TexCoord2f (0, 1, 0);
- VectorMA (source, scale, CurrentViewUp(), point);
- VectorMA (point, scale, CurrentViewRight(), point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color3fv (color);
- meshBuilder.TexCoord2f (0, 1, 1);
- VectorMA (source, -scale, CurrentViewUp(), point);
- VectorMA (point, scale, CurrentViewRight(), point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.End();
- pMesh->Draw();
-}
-
-//-----------------------------------------------------------------------------
-// Assumes the material has already been bound
-//-----------------------------------------------------------------------------
-void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
-{
- unsigned char pColor[4] = { color.r, color.g, color.b, color.a };
-
- // Generate half-widths
- flWidth *= 0.5f;
- flHeight *= 0.5f;
-
- // Compute direction vectors for the sprite
- Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 );
- VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd );
- float flDist = VectorNormalize( fwd );
- if (flDist >= 1e-3)
- {
- CrossProduct( CurrentViewUp(), fwd, right );
- flDist = VectorNormalize( right );
- if (flDist >= 1e-3)
- {
- CrossProduct( fwd, right, up );
- }
- else
- {
- // In this case, fwd == g_vecVUp, it's right above or
- // below us in screen space
- CrossProduct( fwd, CurrentViewRight(), up );
- VectorNormalize( up );
- CrossProduct( up, fwd, right );
- }
- }
-
- CMeshBuilder meshBuilder;
- Vector point;
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
-
- meshBuilder.Color4ubv (pColor);
- meshBuilder.TexCoord2f (0, 0, 1);
- VectorMA (vecOrigin, -flHeight, up, point);
- VectorMA (point, -flWidth, right, point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color4ubv (pColor);
- meshBuilder.TexCoord2f (0, 0, 0);
- VectorMA (vecOrigin, flHeight, up, point);
- VectorMA (point, -flWidth, right, point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color4ubv (pColor);
- meshBuilder.TexCoord2f (0, 1, 0);
- VectorMA (vecOrigin, flHeight, up, point);
- VectorMA (point, flWidth, right, point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color4ubv (pColor);
- meshBuilder.TexCoord2f (0, 1, 1);
- VectorMA (vecOrigin, -flHeight, up, point);
- VectorMA (point, flWidth, right, point);
- meshBuilder.Position3fv (point.Base());
- meshBuilder.AdvanceVertex();
-
- meshBuilder.End();
- pMesh->Draw();
-}
-
-
-//-----------------------------------------------------------------------------
-// Compute vectors perpendicular to the beam
-//-----------------------------------------------------------------------------
-static void ComputeBeamPerpendicular( const Vector &vecBeamDelta, Vector *pPerp )
-{
- // Direction in worldspace of the center of the beam
- Vector vecBeamCenter = vecBeamDelta;
- VectorNormalize( vecBeamCenter );
-
- CrossProduct( CurrentViewForward(), vecBeamCenter, *pPerp );
- VectorNormalize( *pPerp );
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// *spritemodel -
-// frame -
-// rendermode -
-// source -
-// delta -
-// flags -
-// *color -
-// fadescale -
-//-----------------------------------------------------------------------------
-void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
- float frame, int rendermode, const Vector& source, const Vector& delta,
- float startWidth, float endWidth, float scale, float freq, float speed, int segments,
- int flags, float* color, float fadeLength, float flHDRColorScale )
-{
- int i, noiseIndex, noiseStep;
- float div, length, fraction, factor, vLast, vStep, brightness;
-
- Assert( fadeLength >= 0.0f );
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- if ( segments < 2 )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- length = VectorLength( delta );
- float flMaxWidth = MAX(startWidth, endWidth) * 0.5f;
- div = 1.0 / (segments-1);
-
- if ( length*div < flMaxWidth * 1.414 )
- {
- // Here, we have too many segments; we could get overlap... so lets have less segments
- segments = (int)(length / (flMaxWidth * 1.414)) + 1;
- if ( segments < 2 )
- {
- segments = 2;
- }
- }
-
- if ( segments > noise_divisions ) // UNDONE: Allow more segments?
- {
- segments = noise_divisions;
- }
-
- div = 1.0 / (segments-1);
- length *= 0.01;
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
-
- if ( flags & FBEAM_NOTILE )
- {
- // Don't tile
- vStep = div;
- }
- else
- {
- // Texture length texels per space pixel
- vStep = length*div;
- }
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
-
- if ( flags & FBEAM_SINENOISE )
- {
- if ( segments < 16 )
- {
- segments = 16;
- div = 1.0 / (segments-1);
- }
- scale *= 100;
- length = segments * (1.0/10);
- }
- else
- {
- scale *= length;
- }
-
- // Iterator to resample noise waveform (it needs to be generated in powers of 2)
- noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
- noiseIndex = 0;
-
- if ( flags & FBEAM_SINENOISE )
- {
- noiseIndex = 0;
- }
-
- brightness = 1.0;
- if ( flags & FBEAM_SHADEIN )
- {
- brightness = 0;
- }
-
- // What fraction of beam should be faded
- Assert( fadeLength >= 0.0f );
- float fadeFraction = fadeLength/ delta.Length();
-
- // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
- fadeFraction = clamp(fadeFraction,1.e-6f,1.f);
-
- // Choose two vectors that are perpendicular to the beam
- Vector perp1;
- ComputeBeamPerpendicular( delta, &perp1 );
-
- // Specify all the segments.
- CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
- CBeamSegDraw segDraw;
- segDraw.Start( pRenderContext, segments, NULL );
-
- for ( i = 0; i < segments; i++ )
- {
- Assert( noiseIndex < (noise_divisions<<16) );
- BeamSeg_t curSeg;
- curSeg.m_flAlpha = 1;
-
- fraction = i * div;
-
- // Fade in our out beam to fadeLength
-
- if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
- {
- if (fraction < 0.5)
- {
- brightness = 2*(fraction/fadeFraction);
- }
- else
- {
- brightness = 2*(1.0 - (fraction/fadeFraction));
- }
- }
- else if ( flags & FBEAM_SHADEIN )
- {
- brightness = fraction/fadeFraction;
- }
- else if ( flags & FBEAM_SHADEOUT )
- {
- brightness = 1.0 - (fraction/fadeFraction);
- }
-
- // clamps
- if (brightness < 0 )
- {
- brightness = 0;
- }
- else if (brightness > 1)
- {
- brightness = 1;
- }
-
- VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
-
- // UNDONE: Make this a spline instead of just a line?
- VectorMA( source, fraction, delta, curSeg.m_vPos );
-
- // Distort using noise
- if ( scale != 0 )
- {
- factor = prgNoise[noiseIndex>>16] * scale;
- if ( flags & FBEAM_SINENOISE )
- {
- float s, c;
- SinCos( fraction*M_PI*length + freq, &s, &c );
- VectorMA( curSeg.m_vPos, factor * s, CurrentViewUp(), curSeg.m_vPos );
- // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
- VectorMA( curSeg.m_vPos, factor * c, CurrentViewRight(), curSeg.m_vPos );
- }
- else
- {
- VectorMA( curSeg.m_vPos, factor, perp1, curSeg.m_vPos );
- }
- }
-
- // Specify the next segment.
- if( endWidth == startWidth )
- {
- curSeg.m_flWidth = startWidth * 2;
- }
- else
- {
- curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
- }
-
- curSeg.m_flTexCoord = vLast;
- segDraw.NextSeg( &curSeg );
-
-
- vLast += vStep; // Advance texture scroll (v axis only)
- noiseIndex += noiseStep;
- }
-
- segDraw.End();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CalcSegOrigin( Vector *vecOut, int iPoint, int noise_divisions, float *prgNoise,
- const Vector &source, const Vector& delta, const Vector &perp, int segments,
- float freq, float scale, float fraction, int flags )
-{
- Assert( segments > 1 );
-
- float factor;
- float length = VectorLength( delta ) * 0.01;
- float div = 1.0 / (segments-1);
-
- // Iterator to resample noise waveform (it needs to be generated in powers of 2)
- int noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
- int noiseIndex = (iPoint) * noiseStep;
-
- // Sine noise beams have different length calculations
- if ( flags & FBEAM_SINENOISE )
- {
- length = segments * (1.0/10);
- noiseIndex = 0;
- }
-
- // UNDONE: Make this a spline instead of just a line?
- VectorMA( source, fraction, delta, *vecOut );
-
- // Distort using noise
- if ( scale != 0 )
- {
- factor = prgNoise[noiseIndex>>16] * scale;
- if ( flags & FBEAM_SINENOISE )
- {
- float s, c;
- SinCos( fraction*M_PI*length + freq, &s, &c );
- VectorMA( *vecOut, factor * s, MainViewUp(), *vecOut );
- // Rotate the noise along the perpendicular axis a bit to keep the bolt from looking diagonal
- VectorMA( *vecOut, factor * c, MainViewRight(), *vecOut );
- }
- else
- {
- VectorMA( *vecOut, factor, perp, *vecOut );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// *spritemodel -
-// frame -
-// rendermode -
-// source -
-// delta -
-// flags -
-// *color -
-// fadescale -
-//-----------------------------------------------------------------------------
-void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
- float frame, int rendermode, const Vector& source, const Vector& delta,
- float startWidth, float endWidth, float scale, float freq, float speed, int segments,
- int flags, float* color, float fadeLength, float flHDRColorScale )
-{
- int i;
- float div, length, fraction, vLast, vStep, brightness;
-
- Assert( fadeLength >= 0.0f );
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- if ( segments < 2 )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- if ( segments > noise_divisions ) // UNDONE: Allow more segments?
- segments = noise_divisions;
-
- length = VectorLength( delta ) * 0.01;
- div = 1.0 / (segments-1);
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
- vStep = length*div; // Texture length texels per space pixel
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
-
- brightness = 1.0;
- if ( flags & FBEAM_SHADEIN )
- brightness = 0;
-
- // What fraction of beam should be faded
- Assert( fadeLength >= 0.0f );
- float fadeFraction = fadeLength/ delta.Length();
-
- // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
- fadeFraction = clamp(fadeFraction,1.e-6f,1.f);
-
- Vector perp;
- ComputeBeamPerpendicular( delta, &perp );
-
- // Specify all the segments.
- CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
- CBeamSegDraw segDraw;
- segDraw.Start( pRenderContext, segments, NULL );
-
- // Keep track of how many times we've branched
- int iBranches = 0;
-
- Vector vecStart, vecEnd;
- float flWidth = 0;
- float flEndWidth = 0;
-
- for ( i = 0; i < segments; i++ )
- {
- BeamSeg_t curSeg;
- curSeg.m_flAlpha = 1;
-
- fraction = i * div;
-
- // Fade in our out beam to fadeLength
-
- if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
- {
- if (fraction < 0.5)
- {
- brightness = 2*(fraction/fadeFraction);
- }
- else
- {
- brightness = 2*(1.0 - (fraction/fadeFraction));
- }
- }
- else if ( flags & FBEAM_SHADEIN )
- {
- brightness = fraction/fadeFraction;
- }
- else if ( flags & FBEAM_SHADEOUT )
- {
- brightness = 1.0 - (fraction/fadeFraction);
- }
-
- // clamps
- if (brightness < 0 )
- {
- brightness = 0;
- }
- else if (brightness > 1)
- {
- brightness = 1;
- }
-
- VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
-
- CalcSegOrigin( &curSeg.m_vPos, i, noise_divisions, prgNoise, source, delta, perp, segments, freq, scale, fraction, flags );
-
- // Specify the next segment.
- if( endWidth == startWidth )
- curSeg.m_flWidth = startWidth * 2;
- else
- curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
-
- // Reduce the width by the current number of branches we've had
- for ( int j = 0; i < iBranches; j++ )
- {
- curSeg.m_flWidth *= 0.5;
- }
-
- curSeg.m_flTexCoord = vLast;
-
- segDraw.NextSeg( &curSeg );
-
- vLast += vStep; // Advance texture scroll (v axis only)
-
- // Now see if we'd like to branch here
- // For now, always branch at the midpoint.
- // We could branch randomly, and multiple times per beam
- if ( i == (segments * 0.5) )
- {
- // Figure out what the new width would be
- // Halve the width because the beam is breaking in two, and halve it again because width is doubled above
- flWidth = curSeg.m_flWidth * 0.25;
- if ( flWidth > 1 )
- {
- iBranches++;
-
- // Get an endpoint for the new branch
- vecStart = curSeg.m_vPos;
- vecEnd = source + delta + (MainViewUp() * 32) + (MainViewRight() * 32);
- vecEnd -= vecStart;
-
- // Reduce the end width by the current number of branches we've had
- flEndWidth = endWidth;
- for ( int j = 0; i < iBranches; j++ )
- {
- flEndWidth *= 0.5;
- }
- }
- }
- }
-
- segDraw.End();
-
- // If we branched, draw the new beam too
- if ( iBranches )
- {
- DrawTeslaSegs( noise_divisions, prgNoise, spritemodel, frame, rendermode,
- vecStart, vecEnd, flWidth, flEndWidth, scale, freq, speed, segments,
- flags, color, fadeLength, flHDRColorScale );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// *beammodel -
-// *halomodel -
-// flHaloScale -
-// startWidth -
-// endWidth -
-// scale -
-// freq -
-// speed -
-// segments -
-// * -
-//-----------------------------------------------------------------------------
-
-void DrawSplineSegs( int noise_divisions, float *prgNoise,
- const model_t* beammodel, const model_t* halomodel, float flHaloScale,
- float frame, int rendermode, int numAttachments, Vector* attachment,
- float startWidth, float endWidth, float scale, float freq, float speed, int segments,
- int flags, float* color, float fadeLength, float flHDRColorScale )
-{
- int noiseIndex, noiseStep;
- float div, length, fraction, factor, vLast, vStep, brightness;
- float scaledColor[3];
-
- model_t *beamsprite = ( model_t *)beammodel;
- model_t *halosprite = ( model_t *)halomodel;
-
- CEngineSprite *pBeamSprite = Draw_SetSpriteTexture( beamsprite, frame, rendermode );
- if ( !pBeamSprite )
- return;
-
- // Figure out the number of segments.
- if ( segments < 2 )
- return;
-
- IMaterial *pMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- if ( segments > noise_divisions ) // UNDONE: Allow more segments?
- segments = noise_divisions;
-
- if ( flags & FBEAM_SINENOISE )
- {
- if ( segments < 16 )
- segments = 16;
- }
-
-
- IMaterial *pBeamMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
- CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
- CBeamSegDraw segDraw;
- segDraw.Start( pRenderContext, (segments-1)*(numAttachments-1), pBeamMaterial );
-
- CEngineSprite *pHaloSprite = (CEngineSprite *)modelinfo->GetModelExtraData( halosprite );
- IMaterial *pHaloMaterial = NULL;
- if ( pHaloSprite )
- {
- pHaloMaterial = pHaloSprite->GetMaterial( kRenderGlow );
- }
-
- //-----------------------------------------------------------
- // Calculate widthStep if start and end width are different
- //-----------------------------------------------------------
- float widthStep;
- if (startWidth != endWidth)
- {
- widthStep = (endWidth - startWidth)/numAttachments;
- }
- else
- {
- widthStep = 0;
- }
-
- // Calculate total length of beam
- float flBeamLength = (attachment[0]-attachment[numAttachments-1]).Length();
-
- // What fraction of beam should be faded
- float fadeFraction = fadeLength/flBeamLength;
- if (fadeFraction > 1)
- {
- fadeFraction = 1;
- }
- //---------------------------------------------------------------
- // Go through each attachment drawing spline beams between them
- //---------------------------------------------------------------
- Vector vLastPoint(0,0,0);
- Vector pPre; // attachment point before the current beam
- Vector pStart; // start of current beam
- Vector pEnd; // end of current beam
- Vector pNext; // attachment point after the current beam
-
- for (int j=0;j<numAttachments-1;j++)
- {
- if (j==0)
- {
- VectorCopy(attachment[0],pPre);
- VectorCopy(pPre,vLastPoint);
- }
- else
- {
- VectorCopy(attachment[j-1],pPre);
- }
-
- VectorCopy(attachment[j], pStart);
- VectorCopy(attachment[j+1], pEnd);
-
- if (j+2 >= numAttachments-1)
- {
- VectorCopy(attachment[j+1],pNext);
- }
- else
- {
- VectorCopy(attachment[j+2],pNext);
- }
-
- Vector vDelta;
- VectorSubtract(pEnd,pStart,vDelta);
- length = VectorLength( vDelta ) * 0.01;
- if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
- length = 0.5;
- div = 1.0 / (segments-1);
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
- vStep = length*div; // Texture length texels per space pixel
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
-
- if ( flags & FBEAM_SINENOISE )
- {
- scale = scale * 100;
- length = segments * (1.0/10);
- }
- else
- scale = scale * length;
-
- // -----------------------------------------------------------------------------
- // Iterator to resample noise waveform (it needs to be generated in powers of 2)
- // -----------------------------------------------------------------------------
- noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
- noiseIndex = noiseStep;
-
- if ( flags & FBEAM_SINENOISE )
- noiseIndex = 0;
-
- brightness = 1.0;
- if ( flags & FBEAM_SHADEIN )
- brightness = 0;
-
- BeamSeg_t seg;
- seg.m_flAlpha = 1;
-
- VectorScale( color, brightness, scaledColor );
- seg.m_vColor.Init( scaledColor[0], scaledColor[1], scaledColor[2] );
-
-
- // -------------------------------------------------
- // Calc start and end widths for this segment
- // -------------------------------------------------
- float startSegWidth = startWidth + (widthStep*j);
- float endSegWidth = startWidth + (widthStep*(j+1));
-
- // -------------------------------------------------
- // Now draw each segment
- // -------------------------------------------------
- float fBestFraction = -1;
- float bestDot = 0;
- for (int i = 1; i < segments; i++ )
- {
- fraction = i * div;
-
- // Fade in our out beam to fadeLength
- // BUG BUG: should be based on total lengh of beam not this particular fraction
- if ( flags & FBEAM_SHADEIN )
- {
- brightness = fraction/fadeFraction;
- if (brightness > 1)
- {
- brightness = 1;
- }
- }
- else if ( flags & FBEAM_SHADEOUT )
- {
- float fadeFraction = fadeLength/length;
- brightness = 1.0 - (fraction/fadeFraction);
- if (brightness < 0)
- {
- brightness = 0;
- }
- }
-
- // -----------------------------------------------------------
- // Calculate spline position
- // -----------------------------------------------------------
- Vector vTarget(0,0,0);
-
- Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fraction, vTarget );
-
- seg.m_vPos[0] = vTarget.x;
- seg.m_vPos[1] = vTarget.y;
- seg.m_vPos[2] = vTarget.z;
-
- // --------------------------------------------------------------
- // Keep track of segment most facing the player for halo effect
- // --------------------------------------------------------------
- if (pHaloMaterial)
- {
- Vector vBeamDir1;
- VectorSubtract(seg.m_vPos,vLastPoint,vBeamDir1);
- VectorNormalize(vBeamDir1);
-
- Vector vLookDir;
- VectorSubtract(CurrentViewOrigin(),seg.m_vPos,vLookDir);
- VectorNormalize(vLookDir);
-
- float dotpr = fabs(DotProduct(vBeamDir1,vLookDir));
- static float thresh = 0.85;
- if (dotpr > thresh && dotpr > bestDot)
- {
- bestDot = dotpr;
- fBestFraction = fraction;
- }
- VectorCopy(seg.m_vPos,vLastPoint);
- }
-
-
- // ----------------------
- // Distort using noise
- // ----------------------
- if ( scale != 0 )
- {
- factor = prgNoise[noiseIndex>>16] * scale;
- if ( flags & FBEAM_SINENOISE )
- {
- float s, c;
- SinCos( fraction*M_PI*length + freq, &s, &c );
- VectorMA( seg.m_vPos, factor * s, CurrentViewUp(), seg.m_vPos );
- // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
- VectorMA( seg.m_vPos, factor * c, CurrentViewRight(), seg.m_vPos );
- }
- else
- {
- VectorMA( seg.m_vPos, factor, CurrentViewUp(), seg.m_vPos );
- // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
- factor = prgNoise[noiseIndex>>16] * scale * cos(fraction*M_PI*3+freq);
- VectorMA( seg.m_vPos, factor, CurrentViewRight(), seg.m_vPos );
- }
- }
-
-
- // Scale width if non-zero spread
- if (startWidth != endWidth)
- seg.m_flWidth = ((fraction*(endSegWidth-startSegWidth))+startSegWidth)*2;
- else
- seg.m_flWidth = startWidth*2;
-
- seg.m_flTexCoord = vLast;
- segDraw.NextSeg( &seg );
-
- vLast += vStep; // Advance texture scroll (v axis only)
- noiseIndex += noiseStep;
- }
-
-
- // --------------------------------------------------------------
- // Draw halo on segment most facing the player
- // --------------------------------------------------------------
- if (false&&pHaloMaterial)
- {
- Vector vHaloPos(0,0,0);
- if (bestDot != 0)
- {
- Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fBestFraction, vHaloPos);
- }
- else
- {
- Vector vBeamDir1;
- VectorSubtract(pStart,pEnd,vBeamDir1);
- VectorNormalize(vBeamDir1);
-
- Vector vLookDir;
- VectorSubtract(CurrentViewOrigin(),pStart,vLookDir);
- VectorNormalize(vLookDir);
-
- bestDot = fabs(DotProduct(vBeamDir1,vLookDir));
- static float thresh = 0.85;
- if (bestDot > thresh)
- {
- fBestFraction = 0.5;
- VectorAdd(pStart,pEnd,vHaloPos);
- VectorScale(vHaloPos,0.5,vHaloPos);
- }
- }
- if (fBestFraction > 0)
- {
- float fade = pow(bestDot,60);
- if (fade > 1.0) fade = 1.0;
- float haloColor[3];
- VectorScale( color, fade, haloColor );
- pRenderContext->Bind(pHaloMaterial);
- float curWidth = (fBestFraction*(endSegWidth-startSegWidth))+startSegWidth;
- DrawHalo(pHaloMaterial,vHaloPos,flHaloScale*curWidth/endWidth,haloColor, flHDRColorScale);
- }
- }
- }
-
- segDraw.End();
-
- // ------------------------
- // Draw halo at end of beam
- // ------------------------
- if (pHaloMaterial)
- {
- pRenderContext->Bind(pHaloMaterial);
- DrawHalo(pHaloMaterial,pEnd,flHaloScale,scaledColor, flHDRColorScale);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *spritemodel -
-// frame -
-// rendermode -
-// source -
-// scale -
-// *color -
-//-----------------------------------------------------------------------------
-void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode,
- const Vector& source, float scale, float* color, float flHDRColorScale )
-{
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- DrawHalo( pSprite->GetMaterial( (RenderMode_t)rendermode ), source, scale, color, flHDRColorScale );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// *spritemodel -
-// frame -
-// rendermode -
-// source -
-// delta -
-// width -
-// scale -
-// freq -
-// speed -
-// segments -
-// *color -
-//-----------------------------------------------------------------------------
-void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel,
- float frame, int rendermode, const Vector& source, const Vector& delta,
- float width, float scale, float freq, float speed, int segments, float* color, float flHDRColorScale )
-{
- int i;
- float div, length, fraction, vLast, vStep;
- Vector point;
- float w;
- static unsigned int nHDRColorScaleCache = 0;
-
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- if ( segments < 2 )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- if ( segments > noise_divisions ) // UNDONE: Allow more segments?
- segments = noise_divisions;
-
- length = VectorLength( delta ) * 0.01;
- if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
- length = 0.5;
- div = 1.0 / (segments-1);
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
- vStep = length*div; // Texture length texels per space pixel
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
- scale = scale * length;
-
- w = freq * delta[2];
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
-
- // NOTE: We must force the degenerate triangles to be on the edge
- for ( i = 0; i < segments; i++ )
- {
- float s, c;
- fraction = i * div;
-
- point[0] = source[0];
- point[1] = source[1];
- point[2] = source[2];
-
- meshBuilder.Color3fv( color );
- meshBuilder.TexCoord2f( 0, 1.0, vLast );
- meshBuilder.Position3fv( point.Base() );
- meshBuilder.AdvanceVertex();
-
- SinCos( fraction * 2 * M_PI, &s, &c );
- point[0] = s * w + source[0];
- point[1] = c * w + source[1];
- point[2] = source[2];
-
- meshBuilder.Color3fv( color );
- meshBuilder.TexCoord2f( 0, 0.0, vLast );
- meshBuilder.Position3fv( point.Base() );
- meshBuilder.AdvanceVertex();
-
- vLast += vStep; // Advance texture scroll (v axis only)
- }
-
- meshBuilder.End( );
- pMesh->Draw();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// *spritemodel -
-// frame -
-// rendermode -
-// source -
-// delta -
-// width -
-// scale -
-// freq -
-// speed -
-// segments -
-// *color -
-//-----------------------------------------------------------------------------
-void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel,
- float frame, int rendermode, const Vector& source, const Vector& delta,
- float width, float scale, float freq, float speed, int segments,
- float* color, float flHDRColorScale )
-{
- int i;
- float div, length, fraction, vLast, vStep;
- Vector point;
-
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- if ( segments < 2 )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- if ( segments > noise_divisions ) // UNDONE: Allow more segments?
- segments = noise_divisions;
-
- length = VectorLength( delta ) * 0.01;
- if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
- length = 0.5;
- div = 1.0 / (segments-1);
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
- vStep = length*div; // Texture length texels per space pixel
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
- scale = scale * length;
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
-
- float radius = delta[2];
- for ( i = 0; i < segments; i++ )
- {
- float s, c;
- fraction = i * div;
- SinCos( fraction * 2 * M_PI, &s, &c );
-
- point[0] = s * freq * radius + source[0];
- point[1] = c * freq * radius + source[1];
- point[2] = source[2] + width;
-
- meshBuilder.Color3f( 0.0f, 0.0f, 0.0f );
- meshBuilder.TexCoord2f( 0, 1.0f, vLast );
- meshBuilder.Position3fv( point.Base() );
- meshBuilder.AdvanceVertex();
-
- point[0] = s * freq * (radius + width) + source[0];
- point[1] = c * freq * (radius + width) + source[1];
- point[2] = source[2] - width;
-
- meshBuilder.Color3fv( color );
- meshBuilder.TexCoord2f( 0, 0.0f, vLast );
- meshBuilder.Position3fv( point.Base() );
- meshBuilder.AdvanceVertex();
-
- vLast += vStep; // Advance texture scroll (v axis only)
- }
-
- meshBuilder.End();
- pMesh->Draw();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : noise_divisions -
-// *prgNoise -
-// (*pfnNoise -
-//-----------------------------------------------------------------------------
-void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ),
- const model_t* spritemodel, float frame, int rendermode,
- const Vector& source, const Vector& delta, float width,
- float amplitude, float freq, float speed, int segments, float *color, float flHDRColorScale )
-{
- int i, j, noiseIndex, noiseStep;
- float div, length, fraction, factor, vLast, vStep;
- Vector last1, last2, point, screen, screenLast(0,0,0), tmp, normal;
- Vector center, xaxis, yaxis, zaxis;
- float radius, x, y, scale;
- Vector d;
-
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- VectorCopy( delta, d );
-
- if ( segments < 2 )
- return;
-
- segments = segments * M_PI;
-
- if ( segments > noise_divisions * 8 ) // UNDONE: Allow more segments?
- segments = noise_divisions * 8;
-
- length = VectorLength( d ) * 0.01 * M_PI;
- if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
- length = 0.5;
- div = 1.0 / (segments-1);
-
- // UNDONE: Expose texture length scale factor to control "fuzziness"
- vStep = length*div/8.0; // Texture length texels per space pixel
-
- // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
- vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
- scale = amplitude * length / 8.0;
-
- // Iterator to resample noise waveform (it needs to be generated in powers of 2)
- noiseStep = (int)((noise_divisions-1) * div * 65536.0) * 8;
- noiseIndex = 0;
-
- VectorScale( d, 0.5, d );
- VectorAdd( source, d, center );
- zaxis[0] = 0; zaxis[1] = 0; zaxis[2] = 1;
-
- VectorCopy( d, xaxis );
- radius = VectorLength( xaxis );
-
- // cull beamring
- // --------------------------------
- // Compute box center +/- radius
- last1[0] = radius;
- last1[1] = radius;
- last1[2] = scale;
- VectorAdd( center, last1, tmp ); // maxs
- VectorSubtract( center, last1, screen ); // mins
-
- // Is that box in PVS && frustum?
- if ( !engine->IsBoxVisible( screen, tmp ) || engine->CullBox( screen, tmp ) )
- {
- return;
- }
-
- yaxis[0] = xaxis[1]; yaxis[1] = -xaxis[0]; yaxis[2] = 0;
- VectorNormalize( yaxis );
- VectorScale( yaxis, radius, yaxis );
-
- j = segments / 8;
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments) * 2 );
-
- for ( i = 0; i < segments + 1; i++ )
- {
- fraction = i * div;
- SinCos( fraction * 2 * M_PI, &x, &y );
-
- point[0] = xaxis[0] * x + yaxis[0] * y + center[0];
- point[1] = xaxis[1] * x + yaxis[1] * y + center[1];
- point[2] = xaxis[2] * x + yaxis[2] * y + center[2];
-
- // Distort using noise
- if ( scale != 0.0f )
- {
- factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale;
- VectorMA( point, factor, CurrentViewUp(), point );
-
- // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
- factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale * cos(fraction*M_PI*3*8+freq);
- VectorMA( point, factor, CurrentViewRight(), point );
- }
-
- // Transform point into screen space
- ScreenTransform( point, screen );
-
- if (i != 0)
- {
- // Build world-space normal to screen-space direction vector
- VectorSubtract( screen, screenLast, tmp );
- // We don't need Z, we're in screen space
- tmp[2] = 0;
- VectorNormalize( tmp );
- VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
- VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
-
- // Make a wide line
- VectorMA( point, width, normal, last1 );
- VectorMA( point, -width, normal, last2 );
-
- vLast += vStep; // Advance texture scroll (v axis only)
- meshBuilder.Color3fv( color );
- meshBuilder.TexCoord2f( 0, 1.0f, vLast );
- meshBuilder.Position3fv( last2.Base() );
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color3fv( color );
- meshBuilder.TexCoord2f( 0, 0.0f, vLast );
- meshBuilder.Position3fv( last1.Base() );
- meshBuilder.AdvanceVertex();
- }
- VectorCopy( screen, screenLast );
- noiseIndex += noiseStep;
-
- j--;
- if (j == 0 && amplitude != 0 )
- {
- j = segments / 8;
- (*pfnNoise)( prgNoise, noise_divisions, 1.0f );
- }
- }
-
- meshBuilder.End();
- pMesh->Draw();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : spritemodel -
-// *pHead -
-// delta -
-// *screen -
-// *screenLast -
-// die -
-// source -
-// flags -
-// width -
-// amplitude -
-// freq -
-// *color -
-//-----------------------------------------------------------------------------
-void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode,
- Vector& delta, Vector& screen, Vector& screenLast, float die,
- const Vector& source, int flags, float width, float amplitude,
- float freq, float* color, float flHDRColorScale )
-{
- float fraction;
- float div;
- float vLast = 0.0;
- float vStep = 1.0;
- Vector last1, last2, tmp, normal;
- float scaledColor[3];
-
- CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
- if ( !pSprite )
- return;
-
- IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
- if( pMaterial )
- {
- static unsigned int nHDRColorScaleCache = 0;
- IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
- if( pHDRColorScaleVar )
- {
- pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
- }
- }
-
- // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the
- // first beam segment for this trail
-
- // Build world-space normal to screen-space direction vector
- VectorSubtract( screen, screenLast, tmp );
- // We don't need Z, we're in screen space
- tmp[2] = 0;
- VectorNormalize( tmp );
- VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
- VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
-
- // Make a wide line
- VectorMA( delta, width, normal, last1 );
- VectorMA( delta, -width, normal, last2 );
-
- div = 1.0 / amplitude;
- fraction = ( die - gpGlobals->curtime ) * div;
- unsigned char nColor[3];
-
- VectorScale( color, fraction, scaledColor );
- nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
- nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
- nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
-
- // need to count the segments
- int count = 0;
- BeamTrail_t* pTraverse = pHead;
- while ( pTraverse )
- {
- ++count;
- pTraverse = pTraverse->next;
- }
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* pMesh = pRenderContext->GetDynamicMesh( );
-
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( pMesh, MATERIAL_QUADS, count );
-
- while (pHead)
- {
- // Msg("%.2f ", fraction );
- meshBuilder.Position3fv( last1.Base() );
- meshBuilder.Color3ubv( nColor );
- meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Position3fv( last2.Base() );
- meshBuilder.Color3ubv( nColor );
- meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
- meshBuilder.AdvanceVertex();
-
- // Transform point into screen space
- ScreenTransform( pHead->org, screen );
- // Build world-space normal to screen-space direction vector
- VectorSubtract( screen, screenLast, tmp );
- // We don't need Z, we're in screen space
- tmp[2] = 0;
- VectorNormalize( tmp );
- VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
- VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
-
- // Make a wide line
- VectorMA( pHead->org, width, normal, last1 );
- VectorMA( pHead->org, -width, normal, last2 );
-
- vLast += vStep; // Advance texture scroll (v axis only)
-
- if (pHead->next != NULL)
- {
- fraction = (pHead->die - gpGlobals->curtime) * div;
- VectorScale( color, fraction, scaledColor );
- nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
- nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
- nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
- }
- else
- {
- fraction = 0.0;
- nColor[0] = nColor[1] = nColor[2] = 0;
- }
-
- meshBuilder.Position3fv( last2.Base() );
- meshBuilder.Color3ubv( nColor );
- meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Position3fv( last1.Base() );
- meshBuilder.Color3ubv( nColor );
- meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
- meshBuilder.AdvanceVertex();
-
- VectorCopy( screen, screenLast );
-
- pHead = pHead->next;
- }
-
- meshBuilder.End();
- pMesh->Draw();
-}
-
-
-/*
-P0 = start
-P1 = control
-P2 = end
-P(t) = (1-t)^2 * P0 + 2t(1-t)*P1 + t^2 * P2
-*/
-void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale )
-{
- int subdivisions = 16;
-
- CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
- CBeamSegDraw beamDraw;
- beamDraw.Start( pRenderContext, subdivisions+1, NULL );
-
- BeamSeg_t seg;
- seg.m_flAlpha = 1.0;
- seg.m_flWidth = width;
-
- float t = 0;
- float u = fmod( scrollOffset, 1 );
- float dt = 1.0 / (float)subdivisions;
- for( int i = 0; i <= subdivisions; i++, t += dt )
- {
- float omt = (1-t);
- float p0 = omt*omt;
- float p1 = 2*t*omt;
- float p2 = t*t;
-
- seg.m_vPos = p0 * start + p1 * control + p2 * end;
- seg.m_flTexCoord = u - t;
- if ( i == 0 || i == subdivisions )
- {
- // HACK: fade out the ends a bit
- seg.m_vColor = vec3_origin;
- }
- else
- {
- seg.m_vColor = color;
- }
- beamDraw.NextSeg( &seg );
- }
-
- beamDraw.End();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "beamdraw.h"
+#include "enginesprite.h"
+#include "iviewrender_beams.h"
+#include "view.h"
+#include "iviewrender.h"
+#include "engine/ivmodelinfo.h"
+#include "fx_line.h"
+#include "materialsystem/imaterialvar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern ConVar r_drawsprites;
+extern ConVar r_DrawBeams;
+
+static IMaterial *g_pBeamWireframeMaterial;
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieve sprite object and set it up for rendering
+// Input : *pSpriteModel -
+// frame -
+// rendermode -
+// Output : CEngineSprite
+//-----------------------------------------------------------------------------
+CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode )
+{
+ CEngineSprite *psprite;
+ IMaterial *material;
+
+ psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( pSpriteModel );
+ Assert( psprite );
+
+ material = psprite->GetMaterial( (RenderMode_t)rendermode, frame );
+ if( !material )
+ return NULL;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 )
+ {
+ if ( !g_pBeamWireframeMaterial )
+ g_pBeamWireframeMaterial = materials->FindMaterial( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER );
+ pRenderContext->Bind( g_pBeamWireframeMaterial, NULL );
+ return psprite;
+ }
+
+ pRenderContext->Bind( material );
+ return psprite;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pMaterial -
+// source -
+// color -
+//-----------------------------------------------------------------------------
+void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale )
+{
+ static unsigned int nHDRColorScaleCache = 0;
+ Vector point, screen;
+
+ if( pMaterial )
+ {
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ // Transform source into screen space
+ ScreenTransform( source, screen );
+
+ meshBuilder.Color3fv (color);
+ meshBuilder.TexCoord2f (0, 0, 1);
+ VectorMA (source, -scale, CurrentViewUp(), point);
+ VectorMA (point, -scale, CurrentViewRight(), point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3fv (color);
+ meshBuilder.TexCoord2f (0, 0, 0);
+ VectorMA (source, scale, CurrentViewUp(), point);
+ VectorMA (point, -scale, CurrentViewRight(), point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3fv (color);
+ meshBuilder.TexCoord2f (0, 1, 0);
+ VectorMA (source, scale, CurrentViewUp(), point);
+ VectorMA (point, scale, CurrentViewRight(), point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3fv (color);
+ meshBuilder.TexCoord2f (0, 1, 1);
+ VectorMA (source, -scale, CurrentViewUp(), point);
+ VectorMA (point, scale, CurrentViewRight(), point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Assumes the material has already been bound
+//-----------------------------------------------------------------------------
+void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
+{
+ unsigned char pColor[4] = { color.r, color.g, color.b, color.a };
+
+ // Generate half-widths
+ flWidth *= 0.5f;
+ flHeight *= 0.5f;
+
+ // Compute direction vectors for the sprite
+ Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 );
+ VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd );
+ float flDist = VectorNormalize( fwd );
+ if (flDist >= 1e-3)
+ {
+ CrossProduct( CurrentViewUp(), fwd, right );
+ flDist = VectorNormalize( right );
+ if (flDist >= 1e-3)
+ {
+ CrossProduct( fwd, right, up );
+ }
+ else
+ {
+ // In this case, fwd == g_vecVUp, it's right above or
+ // below us in screen space
+ CrossProduct( fwd, CurrentViewRight(), up );
+ VectorNormalize( up );
+ CrossProduct( up, fwd, right );
+ }
+ }
+
+ CMeshBuilder meshBuilder;
+ Vector point;
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Color4ubv (pColor);
+ meshBuilder.TexCoord2f (0, 0, 1);
+ VectorMA (vecOrigin, -flHeight, up, point);
+ VectorMA (point, -flWidth, right, point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv (pColor);
+ meshBuilder.TexCoord2f (0, 0, 0);
+ VectorMA (vecOrigin, flHeight, up, point);
+ VectorMA (point, -flWidth, right, point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv (pColor);
+ meshBuilder.TexCoord2f (0, 1, 0);
+ VectorMA (vecOrigin, flHeight, up, point);
+ VectorMA (point, flWidth, right, point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv (pColor);
+ meshBuilder.TexCoord2f (0, 1, 1);
+ VectorMA (vecOrigin, -flHeight, up, point);
+ VectorMA (point, flWidth, right, point);
+ meshBuilder.Position3fv (point.Base());
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute vectors perpendicular to the beam
+//-----------------------------------------------------------------------------
+static void ComputeBeamPerpendicular( const Vector &vecBeamDelta, Vector *pPerp )
+{
+ // Direction in worldspace of the center of the beam
+ Vector vecBeamCenter = vecBeamDelta;
+ VectorNormalize( vecBeamCenter );
+
+ CrossProduct( CurrentViewForward(), vecBeamCenter, *pPerp );
+ VectorNormalize( *pPerp );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// *spritemodel -
+// frame -
+// rendermode -
+// source -
+// delta -
+// flags -
+// *color -
+// fadescale -
+//-----------------------------------------------------------------------------
+void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
+ float frame, int rendermode, const Vector& source, const Vector& delta,
+ float startWidth, float endWidth, float scale, float freq, float speed, int segments,
+ int flags, float* color, float fadeLength, float flHDRColorScale )
+{
+ int i, noiseIndex, noiseStep;
+ float div, length, fraction, factor, vLast, vStep, brightness;
+
+ Assert( fadeLength >= 0.0f );
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ if ( segments < 2 )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ length = VectorLength( delta );
+ float flMaxWidth = MAX(startWidth, endWidth) * 0.5f;
+ div = 1.0 / (segments-1);
+
+ if ( length*div < flMaxWidth * 1.414 )
+ {
+ // Here, we have too many segments; we could get overlap... so lets have less segments
+ segments = (int)(length / (flMaxWidth * 1.414)) + 1;
+ if ( segments < 2 )
+ {
+ segments = 2;
+ }
+ }
+
+ if ( segments > noise_divisions ) // UNDONE: Allow more segments?
+ {
+ segments = noise_divisions;
+ }
+
+ div = 1.0 / (segments-1);
+ length *= 0.01;
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+
+ if ( flags & FBEAM_NOTILE )
+ {
+ // Don't tile
+ vStep = div;
+ }
+ else
+ {
+ // Texture length texels per space pixel
+ vStep = length*div;
+ }
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+
+ if ( flags & FBEAM_SINENOISE )
+ {
+ if ( segments < 16 )
+ {
+ segments = 16;
+ div = 1.0 / (segments-1);
+ }
+ scale *= 100;
+ length = segments * (1.0/10);
+ }
+ else
+ {
+ scale *= length;
+ }
+
+ // Iterator to resample noise waveform (it needs to be generated in powers of 2)
+ noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
+ noiseIndex = 0;
+
+ if ( flags & FBEAM_SINENOISE )
+ {
+ noiseIndex = 0;
+ }
+
+ brightness = 1.0;
+ if ( flags & FBEAM_SHADEIN )
+ {
+ brightness = 0;
+ }
+
+ // What fraction of beam should be faded
+ Assert( fadeLength >= 0.0f );
+ float fadeFraction = fadeLength/ delta.Length();
+
+ // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
+ fadeFraction = clamp(fadeFraction,1.e-6f,1.f);
+
+ // Choose two vectors that are perpendicular to the beam
+ Vector perp1;
+ ComputeBeamPerpendicular( delta, &perp1 );
+
+ // Specify all the segments.
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ CBeamSegDraw segDraw;
+ segDraw.Start( pRenderContext, segments, NULL );
+
+ for ( i = 0; i < segments; i++ )
+ {
+ Assert( noiseIndex < (noise_divisions<<16) );
+ BeamSeg_t curSeg;
+ curSeg.m_flAlpha = 1;
+
+ fraction = i * div;
+
+ // Fade in our out beam to fadeLength
+
+ if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
+ {
+ if (fraction < 0.5)
+ {
+ brightness = 2*(fraction/fadeFraction);
+ }
+ else
+ {
+ brightness = 2*(1.0 - (fraction/fadeFraction));
+ }
+ }
+ else if ( flags & FBEAM_SHADEIN )
+ {
+ brightness = fraction/fadeFraction;
+ }
+ else if ( flags & FBEAM_SHADEOUT )
+ {
+ brightness = 1.0 - (fraction/fadeFraction);
+ }
+
+ // clamps
+ if (brightness < 0 )
+ {
+ brightness = 0;
+ }
+ else if (brightness > 1)
+ {
+ brightness = 1;
+ }
+
+ VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
+
+ // UNDONE: Make this a spline instead of just a line?
+ VectorMA( source, fraction, delta, curSeg.m_vPos );
+
+ // Distort using noise
+ if ( scale != 0 )
+ {
+ factor = prgNoise[noiseIndex>>16] * scale;
+ if ( flags & FBEAM_SINENOISE )
+ {
+ float s, c;
+ SinCos( fraction*M_PI*length + freq, &s, &c );
+ VectorMA( curSeg.m_vPos, factor * s, CurrentViewUp(), curSeg.m_vPos );
+ // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
+ VectorMA( curSeg.m_vPos, factor * c, CurrentViewRight(), curSeg.m_vPos );
+ }
+ else
+ {
+ VectorMA( curSeg.m_vPos, factor, perp1, curSeg.m_vPos );
+ }
+ }
+
+ // Specify the next segment.
+ if( endWidth == startWidth )
+ {
+ curSeg.m_flWidth = startWidth * 2;
+ }
+ else
+ {
+ curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
+ }
+
+ curSeg.m_flTexCoord = vLast;
+ segDraw.NextSeg( &curSeg );
+
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+ noiseIndex += noiseStep;
+ }
+
+ segDraw.End();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CalcSegOrigin( Vector *vecOut, int iPoint, int noise_divisions, float *prgNoise,
+ const Vector &source, const Vector& delta, const Vector &perp, int segments,
+ float freq, float scale, float fraction, int flags )
+{
+ Assert( segments > 1 );
+
+ float factor;
+ float length = VectorLength( delta ) * 0.01;
+ float div = 1.0 / (segments-1);
+
+ // Iterator to resample noise waveform (it needs to be generated in powers of 2)
+ int noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
+ int noiseIndex = (iPoint) * noiseStep;
+
+ // Sine noise beams have different length calculations
+ if ( flags & FBEAM_SINENOISE )
+ {
+ length = segments * (1.0/10);
+ noiseIndex = 0;
+ }
+
+ // UNDONE: Make this a spline instead of just a line?
+ VectorMA( source, fraction, delta, *vecOut );
+
+ // Distort using noise
+ if ( scale != 0 )
+ {
+ factor = prgNoise[noiseIndex>>16] * scale;
+ if ( flags & FBEAM_SINENOISE )
+ {
+ float s, c;
+ SinCos( fraction*M_PI*length + freq, &s, &c );
+ VectorMA( *vecOut, factor * s, MainViewUp(), *vecOut );
+ // Rotate the noise along the perpendicular axis a bit to keep the bolt from looking diagonal
+ VectorMA( *vecOut, factor * c, MainViewRight(), *vecOut );
+ }
+ else
+ {
+ VectorMA( *vecOut, factor, perp, *vecOut );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// *spritemodel -
+// frame -
+// rendermode -
+// source -
+// delta -
+// flags -
+// *color -
+// fadescale -
+//-----------------------------------------------------------------------------
+void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
+ float frame, int rendermode, const Vector& source, const Vector& delta,
+ float startWidth, float endWidth, float scale, float freq, float speed, int segments,
+ int flags, float* color, float fadeLength, float flHDRColorScale )
+{
+ int i;
+ float div, length, fraction, vLast, vStep, brightness;
+
+ Assert( fadeLength >= 0.0f );
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ if ( segments < 2 )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ if ( segments > noise_divisions ) // UNDONE: Allow more segments?
+ segments = noise_divisions;
+
+ length = VectorLength( delta ) * 0.01;
+ div = 1.0 / (segments-1);
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+ vStep = length*div; // Texture length texels per space pixel
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+
+ brightness = 1.0;
+ if ( flags & FBEAM_SHADEIN )
+ brightness = 0;
+
+ // What fraction of beam should be faded
+ Assert( fadeLength >= 0.0f );
+ float fadeFraction = fadeLength/ delta.Length();
+
+ // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST!
+ fadeFraction = clamp(fadeFraction,1.e-6f,1.f);
+
+ Vector perp;
+ ComputeBeamPerpendicular( delta, &perp );
+
+ // Specify all the segments.
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ CBeamSegDraw segDraw;
+ segDraw.Start( pRenderContext, segments, NULL );
+
+ // Keep track of how many times we've branched
+ int iBranches = 0;
+
+ Vector vecStart, vecEnd;
+ float flWidth = 0;
+ float flEndWidth = 0;
+
+ for ( i = 0; i < segments; i++ )
+ {
+ BeamSeg_t curSeg;
+ curSeg.m_flAlpha = 1;
+
+ fraction = i * div;
+
+ // Fade in our out beam to fadeLength
+
+ if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) )
+ {
+ if (fraction < 0.5)
+ {
+ brightness = 2*(fraction/fadeFraction);
+ }
+ else
+ {
+ brightness = 2*(1.0 - (fraction/fadeFraction));
+ }
+ }
+ else if ( flags & FBEAM_SHADEIN )
+ {
+ brightness = fraction/fadeFraction;
+ }
+ else if ( flags & FBEAM_SHADEOUT )
+ {
+ brightness = 1.0 - (fraction/fadeFraction);
+ }
+
+ // clamps
+ if (brightness < 0 )
+ {
+ brightness = 0;
+ }
+ else if (brightness > 1)
+ {
+ brightness = 1;
+ }
+
+ VectorScale( *((Vector*)color), brightness, curSeg.m_vColor );
+
+ CalcSegOrigin( &curSeg.m_vPos, i, noise_divisions, prgNoise, source, delta, perp, segments, freq, scale, fraction, flags );
+
+ // Specify the next segment.
+ if( endWidth == startWidth )
+ curSeg.m_flWidth = startWidth * 2;
+ else
+ curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2;
+
+ // Reduce the width by the current number of branches we've had
+ for ( int j = 0; i < iBranches; j++ )
+ {
+ curSeg.m_flWidth *= 0.5;
+ }
+
+ curSeg.m_flTexCoord = vLast;
+
+ segDraw.NextSeg( &curSeg );
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+
+ // Now see if we'd like to branch here
+ // For now, always branch at the midpoint.
+ // We could branch randomly, and multiple times per beam
+ if ( i == (segments * 0.5) )
+ {
+ // Figure out what the new width would be
+ // Halve the width because the beam is breaking in two, and halve it again because width is doubled above
+ flWidth = curSeg.m_flWidth * 0.25;
+ if ( flWidth > 1 )
+ {
+ iBranches++;
+
+ // Get an endpoint for the new branch
+ vecStart = curSeg.m_vPos;
+ vecEnd = source + delta + (MainViewUp() * 32) + (MainViewRight() * 32);
+ vecEnd -= vecStart;
+
+ // Reduce the end width by the current number of branches we've had
+ flEndWidth = endWidth;
+ for ( int j = 0; i < iBranches; j++ )
+ {
+ flEndWidth *= 0.5;
+ }
+ }
+ }
+ }
+
+ segDraw.End();
+
+ // If we branched, draw the new beam too
+ if ( iBranches )
+ {
+ DrawTeslaSegs( noise_divisions, prgNoise, spritemodel, frame, rendermode,
+ vecStart, vecEnd, flWidth, flEndWidth, scale, freq, speed, segments,
+ flags, color, fadeLength, flHDRColorScale );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// *beammodel -
+// *halomodel -
+// flHaloScale -
+// startWidth -
+// endWidth -
+// scale -
+// freq -
+// speed -
+// segments -
+// * -
+//-----------------------------------------------------------------------------
+
+void DrawSplineSegs( int noise_divisions, float *prgNoise,
+ const model_t* beammodel, const model_t* halomodel, float flHaloScale,
+ float frame, int rendermode, int numAttachments, Vector* attachment,
+ float startWidth, float endWidth, float scale, float freq, float speed, int segments,
+ int flags, float* color, float fadeLength, float flHDRColorScale )
+{
+ int noiseIndex, noiseStep;
+ float div, length, fraction, factor, vLast, vStep, brightness;
+ float scaledColor[3];
+
+ model_t *beamsprite = ( model_t *)beammodel;
+ model_t *halosprite = ( model_t *)halomodel;
+
+ CEngineSprite *pBeamSprite = Draw_SetSpriteTexture( beamsprite, frame, rendermode );
+ if ( !pBeamSprite )
+ return;
+
+ // Figure out the number of segments.
+ if ( segments < 2 )
+ return;
+
+ IMaterial *pMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ if ( segments > noise_divisions ) // UNDONE: Allow more segments?
+ segments = noise_divisions;
+
+ if ( flags & FBEAM_SINENOISE )
+ {
+ if ( segments < 16 )
+ segments = 16;
+ }
+
+
+ IMaterial *pBeamMaterial = pBeamSprite->GetMaterial( (RenderMode_t)rendermode );
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ CBeamSegDraw segDraw;
+ segDraw.Start( pRenderContext, (segments-1)*(numAttachments-1), pBeamMaterial );
+
+ CEngineSprite *pHaloSprite = (CEngineSprite *)modelinfo->GetModelExtraData( halosprite );
+ IMaterial *pHaloMaterial = NULL;
+ if ( pHaloSprite )
+ {
+ pHaloMaterial = pHaloSprite->GetMaterial( kRenderGlow );
+ }
+
+ //-----------------------------------------------------------
+ // Calculate widthStep if start and end width are different
+ //-----------------------------------------------------------
+ float widthStep;
+ if (startWidth != endWidth)
+ {
+ widthStep = (endWidth - startWidth)/numAttachments;
+ }
+ else
+ {
+ widthStep = 0;
+ }
+
+ // Calculate total length of beam
+ float flBeamLength = (attachment[0]-attachment[numAttachments-1]).Length();
+
+ // What fraction of beam should be faded
+ float fadeFraction = fadeLength/flBeamLength;
+ if (fadeFraction > 1)
+ {
+ fadeFraction = 1;
+ }
+ //---------------------------------------------------------------
+ // Go through each attachment drawing spline beams between them
+ //---------------------------------------------------------------
+ Vector vLastPoint(0,0,0);
+ Vector pPre; // attachment point before the current beam
+ Vector pStart; // start of current beam
+ Vector pEnd; // end of current beam
+ Vector pNext; // attachment point after the current beam
+
+ for (int j=0;j<numAttachments-1;j++)
+ {
+ if (j==0)
+ {
+ VectorCopy(attachment[0],pPre);
+ VectorCopy(pPre,vLastPoint);
+ }
+ else
+ {
+ VectorCopy(attachment[j-1],pPre);
+ }
+
+ VectorCopy(attachment[j], pStart);
+ VectorCopy(attachment[j+1], pEnd);
+
+ if (j+2 >= numAttachments-1)
+ {
+ VectorCopy(attachment[j+1],pNext);
+ }
+ else
+ {
+ VectorCopy(attachment[j+2],pNext);
+ }
+
+ Vector vDelta;
+ VectorSubtract(pEnd,pStart,vDelta);
+ length = VectorLength( vDelta ) * 0.01;
+ if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
+ length = 0.5;
+ div = 1.0 / (segments-1);
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+ vStep = length*div; // Texture length texels per space pixel
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+
+ if ( flags & FBEAM_SINENOISE )
+ {
+ scale = scale * 100;
+ length = segments * (1.0/10);
+ }
+ else
+ scale = scale * length;
+
+ // -----------------------------------------------------------------------------
+ // Iterator to resample noise waveform (it needs to be generated in powers of 2)
+ // -----------------------------------------------------------------------------
+ noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f);
+ noiseIndex = noiseStep;
+
+ if ( flags & FBEAM_SINENOISE )
+ noiseIndex = 0;
+
+ brightness = 1.0;
+ if ( flags & FBEAM_SHADEIN )
+ brightness = 0;
+
+ BeamSeg_t seg;
+ seg.m_flAlpha = 1;
+
+ VectorScale( color, brightness, scaledColor );
+ seg.m_vColor.Init( scaledColor[0], scaledColor[1], scaledColor[2] );
+
+
+ // -------------------------------------------------
+ // Calc start and end widths for this segment
+ // -------------------------------------------------
+ float startSegWidth = startWidth + (widthStep*j);
+ float endSegWidth = startWidth + (widthStep*(j+1));
+
+ // -------------------------------------------------
+ // Now draw each segment
+ // -------------------------------------------------
+ float fBestFraction = -1;
+ float bestDot = 0;
+ for (int i = 1; i < segments; i++ )
+ {
+ fraction = i * div;
+
+ // Fade in our out beam to fadeLength
+ // BUG BUG: should be based on total lengh of beam not this particular fraction
+ if ( flags & FBEAM_SHADEIN )
+ {
+ brightness = fraction/fadeFraction;
+ if (brightness > 1)
+ {
+ brightness = 1;
+ }
+ }
+ else if ( flags & FBEAM_SHADEOUT )
+ {
+ float fadeFraction = fadeLength/length;
+ brightness = 1.0 - (fraction/fadeFraction);
+ if (brightness < 0)
+ {
+ brightness = 0;
+ }
+ }
+
+ // -----------------------------------------------------------
+ // Calculate spline position
+ // -----------------------------------------------------------
+ Vector vTarget(0,0,0);
+
+ Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fraction, vTarget );
+
+ seg.m_vPos[0] = vTarget.x;
+ seg.m_vPos[1] = vTarget.y;
+ seg.m_vPos[2] = vTarget.z;
+
+ // --------------------------------------------------------------
+ // Keep track of segment most facing the player for halo effect
+ // --------------------------------------------------------------
+ if (pHaloMaterial)
+ {
+ Vector vBeamDir1;
+ VectorSubtract(seg.m_vPos,vLastPoint,vBeamDir1);
+ VectorNormalize(vBeamDir1);
+
+ Vector vLookDir;
+ VectorSubtract(CurrentViewOrigin(),seg.m_vPos,vLookDir);
+ VectorNormalize(vLookDir);
+
+ float dotpr = fabs(DotProduct(vBeamDir1,vLookDir));
+ static float thresh = 0.85;
+ if (dotpr > thresh && dotpr > bestDot)
+ {
+ bestDot = dotpr;
+ fBestFraction = fraction;
+ }
+ VectorCopy(seg.m_vPos,vLastPoint);
+ }
+
+
+ // ----------------------
+ // Distort using noise
+ // ----------------------
+ if ( scale != 0 )
+ {
+ factor = prgNoise[noiseIndex>>16] * scale;
+ if ( flags & FBEAM_SINENOISE )
+ {
+ float s, c;
+ SinCos( fraction*M_PI*length + freq, &s, &c );
+ VectorMA( seg.m_vPos, factor * s, CurrentViewUp(), seg.m_vPos );
+ // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
+ VectorMA( seg.m_vPos, factor * c, CurrentViewRight(), seg.m_vPos );
+ }
+ else
+ {
+ VectorMA( seg.m_vPos, factor, CurrentViewUp(), seg.m_vPos );
+ // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
+ factor = prgNoise[noiseIndex>>16] * scale * cos(fraction*M_PI*3+freq);
+ VectorMA( seg.m_vPos, factor, CurrentViewRight(), seg.m_vPos );
+ }
+ }
+
+
+ // Scale width if non-zero spread
+ if (startWidth != endWidth)
+ seg.m_flWidth = ((fraction*(endSegWidth-startSegWidth))+startSegWidth)*2;
+ else
+ seg.m_flWidth = startWidth*2;
+
+ seg.m_flTexCoord = vLast;
+ segDraw.NextSeg( &seg );
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+ noiseIndex += noiseStep;
+ }
+
+
+ // --------------------------------------------------------------
+ // Draw halo on segment most facing the player
+ // --------------------------------------------------------------
+ if (false&&pHaloMaterial)
+ {
+ Vector vHaloPos(0,0,0);
+ if (bestDot != 0)
+ {
+ Catmull_Rom_Spline(pPre, pStart, pEnd, pNext, fBestFraction, vHaloPos);
+ }
+ else
+ {
+ Vector vBeamDir1;
+ VectorSubtract(pStart,pEnd,vBeamDir1);
+ VectorNormalize(vBeamDir1);
+
+ Vector vLookDir;
+ VectorSubtract(CurrentViewOrigin(),pStart,vLookDir);
+ VectorNormalize(vLookDir);
+
+ bestDot = fabs(DotProduct(vBeamDir1,vLookDir));
+ static float thresh = 0.85;
+ if (bestDot > thresh)
+ {
+ fBestFraction = 0.5;
+ VectorAdd(pStart,pEnd,vHaloPos);
+ VectorScale(vHaloPos,0.5,vHaloPos);
+ }
+ }
+ if (fBestFraction > 0)
+ {
+ float fade = pow(bestDot,60);
+ if (fade > 1.0) fade = 1.0;
+ float haloColor[3];
+ VectorScale( color, fade, haloColor );
+ pRenderContext->Bind(pHaloMaterial);
+ float curWidth = (fBestFraction*(endSegWidth-startSegWidth))+startSegWidth;
+ DrawHalo(pHaloMaterial,vHaloPos,flHaloScale*curWidth/endWidth,haloColor, flHDRColorScale);
+ }
+ }
+ }
+
+ segDraw.End();
+
+ // ------------------------
+ // Draw halo at end of beam
+ // ------------------------
+ if (pHaloMaterial)
+ {
+ pRenderContext->Bind(pHaloMaterial);
+ DrawHalo(pHaloMaterial,pEnd,flHaloScale,scaledColor, flHDRColorScale);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *spritemodel -
+// frame -
+// rendermode -
+// source -
+// scale -
+// *color -
+//-----------------------------------------------------------------------------
+void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode,
+ const Vector& source, float scale, float* color, float flHDRColorScale )
+{
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ DrawHalo( pSprite->GetMaterial( (RenderMode_t)rendermode ), source, scale, color, flHDRColorScale );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// *spritemodel -
+// frame -
+// rendermode -
+// source -
+// delta -
+// width -
+// scale -
+// freq -
+// speed -
+// segments -
+// *color -
+//-----------------------------------------------------------------------------
+void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel,
+ float frame, int rendermode, const Vector& source, const Vector& delta,
+ float width, float scale, float freq, float speed, int segments, float* color, float flHDRColorScale )
+{
+ int i;
+ float div, length, fraction, vLast, vStep;
+ Vector point;
+ float w;
+ static unsigned int nHDRColorScaleCache = 0;
+
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ if ( segments < 2 )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ if ( segments > noise_divisions ) // UNDONE: Allow more segments?
+ segments = noise_divisions;
+
+ length = VectorLength( delta ) * 0.01;
+ if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
+ length = 0.5;
+ div = 1.0 / (segments-1);
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+ vStep = length*div; // Texture length texels per space pixel
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+ scale = scale * length;
+
+ w = freq * delta[2];
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
+
+ // NOTE: We must force the degenerate triangles to be on the edge
+ for ( i = 0; i < segments; i++ )
+ {
+ float s, c;
+ fraction = i * div;
+
+ point[0] = source[0];
+ point[1] = source[1];
+ point[2] = source[2];
+
+ meshBuilder.Color3fv( color );
+ meshBuilder.TexCoord2f( 0, 1.0, vLast );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ SinCos( fraction * 2 * M_PI, &s, &c );
+ point[0] = s * w + source[0];
+ point[1] = c * w + source[1];
+ point[2] = source[2];
+
+ meshBuilder.Color3fv( color );
+ meshBuilder.TexCoord2f( 0, 0.0, vLast );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+ }
+
+ meshBuilder.End( );
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// *spritemodel -
+// frame -
+// rendermode -
+// source -
+// delta -
+// width -
+// scale -
+// freq -
+// speed -
+// segments -
+// *color -
+//-----------------------------------------------------------------------------
+void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel,
+ float frame, int rendermode, const Vector& source, const Vector& delta,
+ float width, float scale, float freq, float speed, int segments,
+ float* color, float flHDRColorScale )
+{
+ int i;
+ float div, length, fraction, vLast, vStep;
+ Vector point;
+
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ if ( segments < 2 )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ if ( segments > noise_divisions ) // UNDONE: Allow more segments?
+ segments = noise_divisions;
+
+ length = VectorLength( delta ) * 0.01;
+ if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
+ length = 0.5;
+ div = 1.0 / (segments-1);
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+ vStep = length*div; // Texture length texels per space pixel
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+ scale = scale * length;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments - 1) * 2 );
+
+ float radius = delta[2];
+ for ( i = 0; i < segments; i++ )
+ {
+ float s, c;
+ fraction = i * div;
+ SinCos( fraction * 2 * M_PI, &s, &c );
+
+ point[0] = s * freq * radius + source[0];
+ point[1] = c * freq * radius + source[1];
+ point[2] = source[2] + width;
+
+ meshBuilder.Color3f( 0.0f, 0.0f, 0.0f );
+ meshBuilder.TexCoord2f( 0, 1.0f, vLast );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ point[0] = s * freq * (radius + width) + source[0];
+ point[1] = c * freq * (radius + width) + source[1];
+ point[2] = source[2] - width;
+
+ meshBuilder.Color3fv( color );
+ meshBuilder.TexCoord2f( 0, 0.0f, vLast );
+ meshBuilder.Position3fv( point.Base() );
+ meshBuilder.AdvanceVertex();
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : noise_divisions -
+// *prgNoise -
+// (*pfnNoise -
+//-----------------------------------------------------------------------------
+void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ),
+ const model_t* spritemodel, float frame, int rendermode,
+ const Vector& source, const Vector& delta, float width,
+ float amplitude, float freq, float speed, int segments, float *color, float flHDRColorScale )
+{
+ int i, j, noiseIndex, noiseStep;
+ float div, length, fraction, factor, vLast, vStep;
+ Vector last1, last2, point, screen, screenLast(0,0,0), tmp, normal;
+ Vector center, xaxis, yaxis, zaxis;
+ float radius, x, y, scale;
+ Vector d;
+
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ VectorCopy( delta, d );
+
+ if ( segments < 2 )
+ return;
+
+ segments = segments * M_PI;
+
+ if ( segments > noise_divisions * 8 ) // UNDONE: Allow more segments?
+ segments = noise_divisions * 8;
+
+ length = VectorLength( d ) * 0.01 * M_PI;
+ if ( length < 0.5 ) // Don't lose all of the noise/texture on short beams
+ length = 0.5;
+ div = 1.0 / (segments-1);
+
+ // UNDONE: Expose texture length scale factor to control "fuzziness"
+ vStep = length*div/8.0; // Texture length texels per space pixel
+
+ // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam
+ vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
+ scale = amplitude * length / 8.0;
+
+ // Iterator to resample noise waveform (it needs to be generated in powers of 2)
+ noiseStep = (int)((noise_divisions-1) * div * 65536.0) * 8;
+ noiseIndex = 0;
+
+ VectorScale( d, 0.5, d );
+ VectorAdd( source, d, center );
+ zaxis[0] = 0; zaxis[1] = 0; zaxis[2] = 1;
+
+ VectorCopy( d, xaxis );
+ radius = VectorLength( xaxis );
+
+ // cull beamring
+ // --------------------------------
+ // Compute box center +/- radius
+ last1[0] = radius;
+ last1[1] = radius;
+ last1[2] = scale;
+ VectorAdd( center, last1, tmp ); // maxs
+ VectorSubtract( center, last1, screen ); // mins
+
+ // Is that box in PVS && frustum?
+ if ( !engine->IsBoxVisible( screen, tmp ) || engine->CullBox( screen, tmp ) )
+ {
+ return;
+ }
+
+ yaxis[0] = xaxis[1]; yaxis[1] = -xaxis[0]; yaxis[2] = 0;
+ VectorNormalize( yaxis );
+ VectorScale( yaxis, radius, yaxis );
+
+ j = segments / 8;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (segments) * 2 );
+
+ for ( i = 0; i < segments + 1; i++ )
+ {
+ fraction = i * div;
+ SinCos( fraction * 2 * M_PI, &x, &y );
+
+ point[0] = xaxis[0] * x + yaxis[0] * y + center[0];
+ point[1] = xaxis[1] * x + yaxis[1] * y + center[1];
+ point[2] = xaxis[2] * x + yaxis[2] * y + center[2];
+
+ // Distort using noise
+ if ( scale != 0.0f )
+ {
+ factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale;
+ VectorMA( point, factor, CurrentViewUp(), point );
+
+ // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal
+ factor = prgNoise[(noiseIndex>>16) & 0x7F] * scale * cos(fraction*M_PI*3*8+freq);
+ VectorMA( point, factor, CurrentViewRight(), point );
+ }
+
+ // Transform point into screen space
+ ScreenTransform( point, screen );
+
+ if (i != 0)
+ {
+ // Build world-space normal to screen-space direction vector
+ VectorSubtract( screen, screenLast, tmp );
+ // We don't need Z, we're in screen space
+ tmp[2] = 0;
+ VectorNormalize( tmp );
+ VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
+ VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
+
+ // Make a wide line
+ VectorMA( point, width, normal, last1 );
+ VectorMA( point, -width, normal, last2 );
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+ meshBuilder.Color3fv( color );
+ meshBuilder.TexCoord2f( 0, 1.0f, vLast );
+ meshBuilder.Position3fv( last2.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3fv( color );
+ meshBuilder.TexCoord2f( 0, 0.0f, vLast );
+ meshBuilder.Position3fv( last1.Base() );
+ meshBuilder.AdvanceVertex();
+ }
+ VectorCopy( screen, screenLast );
+ noiseIndex += noiseStep;
+
+ j--;
+ if (j == 0 && amplitude != 0 )
+ {
+ j = segments / 8;
+ (*pfnNoise)( prgNoise, noise_divisions, 1.0f );
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : spritemodel -
+// *pHead -
+// delta -
+// *screen -
+// *screenLast -
+// die -
+// source -
+// flags -
+// width -
+// amplitude -
+// freq -
+// *color -
+//-----------------------------------------------------------------------------
+void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode,
+ Vector& delta, Vector& screen, Vector& screenLast, float die,
+ const Vector& source, int flags, float width, float amplitude,
+ float freq, float* color, float flHDRColorScale )
+{
+ float fraction;
+ float div;
+ float vLast = 0.0;
+ float vStep = 1.0;
+ Vector last1, last2, tmp, normal;
+ float scaledColor[3];
+
+ CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode );
+ if ( !pSprite )
+ return;
+
+ IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode );
+ if( pMaterial )
+ {
+ static unsigned int nHDRColorScaleCache = 0;
+ IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
+ if( pHDRColorScaleVar )
+ {
+ pHDRColorScaleVar->SetFloatValue( flHDRColorScale );
+ }
+ }
+
+ // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the
+ // first beam segment for this trail
+
+ // Build world-space normal to screen-space direction vector
+ VectorSubtract( screen, screenLast, tmp );
+ // We don't need Z, we're in screen space
+ tmp[2] = 0;
+ VectorNormalize( tmp );
+ VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
+ VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
+
+ // Make a wide line
+ VectorMA( delta, width, normal, last1 );
+ VectorMA( delta, -width, normal, last2 );
+
+ div = 1.0 / amplitude;
+ fraction = ( die - gpGlobals->curtime ) * div;
+ unsigned char nColor[3];
+
+ VectorScale( color, fraction, scaledColor );
+ nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
+ nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
+ nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
+
+ // need to count the segments
+ int count = 0;
+ BeamTrail_t* pTraverse = pHead;
+ while ( pTraverse )
+ {
+ ++count;
+ pTraverse = pTraverse->next;
+ }
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, count );
+
+ while (pHead)
+ {
+ // Msg("%.2f ", fraction );
+ meshBuilder.Position3fv( last1.Base() );
+ meshBuilder.Color3ubv( nColor );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( last2.Base() );
+ meshBuilder.Color3ubv( nColor );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ // Transform point into screen space
+ ScreenTransform( pHead->org, screen );
+ // Build world-space normal to screen-space direction vector
+ VectorSubtract( screen, screenLast, tmp );
+ // We don't need Z, we're in screen space
+ tmp[2] = 0;
+ VectorNormalize( tmp );
+ VectorScale( CurrentViewUp(), tmp[0], normal ); // Build point along noraml line (normal is -y, x)
+ VectorMA( normal, -tmp[1], CurrentViewRight(), normal );
+
+ // Make a wide line
+ VectorMA( pHead->org, width, normal, last1 );
+ VectorMA( pHead->org, -width, normal, last2 );
+
+ vLast += vStep; // Advance texture scroll (v axis only)
+
+ if (pHead->next != NULL)
+ {
+ fraction = (pHead->die - gpGlobals->curtime) * div;
+ VectorScale( color, fraction, scaledColor );
+ nColor[0] = (unsigned char)clamp( (int)(scaledColor[0] * 255.0f), 0, 255 );
+ nColor[1] = (unsigned char)clamp( (int)(scaledColor[1] * 255.0f), 0, 255 );
+ nColor[2] = (unsigned char)clamp( (int)(scaledColor[2] * 255.0f), 0, 255 );
+ }
+ else
+ {
+ fraction = 0.0;
+ nColor[0] = nColor[1] = nColor[2] = 0;
+ }
+
+ meshBuilder.Position3fv( last2.Base() );
+ meshBuilder.Color3ubv( nColor );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( last1.Base() );
+ meshBuilder.Color3ubv( nColor );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ VectorCopy( screen, screenLast );
+
+ pHead = pHead->next;
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+/*
+P0 = start
+P1 = control
+P2 = end
+P(t) = (1-t)^2 * P0 + 2t(1-t)*P1 + t^2 * P2
+*/
+void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale )
+{
+ int subdivisions = 16;
+
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ CBeamSegDraw beamDraw;
+ beamDraw.Start( pRenderContext, subdivisions+1, NULL );
+
+ BeamSeg_t seg;
+ seg.m_flAlpha = 1.0;
+ seg.m_flWidth = width;
+
+ float t = 0;
+ float u = fmod( scrollOffset, 1 );
+ float dt = 1.0 / (float)subdivisions;
+ for( int i = 0; i <= subdivisions; i++, t += dt )
+ {
+ float omt = (1-t);
+ float p0 = omt*omt;
+ float p1 = 2*t*omt;
+ float p2 = t*t;
+
+ seg.m_vPos = p0 * start + p1 * control + p2 * end;
+ seg.m_flTexCoord = u - t;
+ if ( i == 0 || i == subdivisions )
+ {
+ // HACK: fade out the ends a bit
+ seg.m_vColor = vec3_origin;
+ }
+ else
+ {
+ seg.m_vColor = color;
+ }
+ beamDraw.NextSeg( &seg );
+ }
+
+ beamDraw.End();
+}