2013-04-19 02:52:48 +00:00
// this include must remain at the top of every CPP file
//Anything above this #include will be ignored by the compiler
# include "../qcommon/exe_headers.h"
# include "client.h"
# if !defined(FX_SCHEDULER_H_INC)
# include "FxScheduler.h"
# endif
# if !defined(G2_H_INC)
# include "../ghoul2/G2.h"
# include "../ghoul2/G2_local.h"
# endif
# ifdef VV_LIGHTING
# include "../renderer/tr_lightmanager.h"
# endif
extern int drawnFx ;
//--------------------------
//
// Base Effect Class
//
//--------------------------
CEffect : : CEffect ( void ) :
mMatImpactFX ( MATIMPACTFX_NONE ) ,
mMatImpactParm ( - 1 ) ,
mSoundVolume ( - 1 ) ,
mSoundRadius ( - 1 ) ,
mFlags ( 0 )
{
memset ( & mRefEnt , 0 , sizeof ( mRefEnt ) ) ;
}
//--------------------------
//
// Derived Particle Class
//
//--------------------------
//----------------------------
void CParticle : : Init ( void )
{
mRefEnt . radius = 0.0f ;
if ( mFlags & FX_PLAYER_VIEW )
{
mOrigin1 [ 0 ] = irand ( 0 , 639 ) ;
mOrigin1 [ 1 ] = irand ( 0 , 479 ) ;
}
}
//----------------------------
void CParticle : : Die ( void )
{
if ( mFlags & FX_DEATH_RUNS_FX & & ! ( mFlags & FX_KILL_ON_IMPACT ) )
{
vec3_t norm ;
// Man, this just seems so, like, uncool and stuff...
VectorSet ( norm , flrand ( - 1.0f , 1.0f ) , flrand ( - 1.0f , 1.0f ) , flrand ( - 1.0f , 1.0f ) ) ;
VectorNormalize ( norm ) ;
theFxScheduler . PlayEffect ( mDeathFxID , mOrigin1 , norm ) ;
}
}
//----------------------------
bool CParticle : : Cull ( void )
{
vec3_t dir ;
if ( mFlags & FX_PLAYER_VIEW )
{
// this will be drawn as a 2D effect so don't cull it
return false ;
}
// Get the direction to the view
VectorSubtract ( mOrigin1 , theFxHelper . refdef - > vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) < 0 ) // cg.cosHalfFOV * (len - mRadius) )
{
return true ;
}
// don't cull if this is hacked to show up close to the inview wpn
if ( mFlags & FX_DEPTH_HACK )
{
return false ;
}
// Can't be too close
float len = VectorLengthSquared ( dir ) ;
if ( len < fx_nearCull - > value )
{
return true ;
}
return false ;
}
//----------------------------
void CParticle : : Draw ( void )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set, but it can't hurt?
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
if ( mFlags & FX_PLAYER_VIEW )
{
vec4_t color ;
color [ 0 ] = mRefEnt . shaderRGBA [ 0 ] / 255.0 ;
color [ 1 ] = mRefEnt . shaderRGBA [ 1 ] / 255.0 ;
color [ 2 ] = mRefEnt . shaderRGBA [ 2 ] / 255.0 ;
color [ 3 ] = mRefEnt . shaderRGBA [ 3 ] / 255.0 ;
// add this 2D effect to the proper list. it will get drawn after the cgi.RenderScene call
theFxScheduler . Add2DEffect ( mOrigin1 [ 0 ] , mOrigin1 [ 1 ] , mRefEnt . radius , mRefEnt . radius , color , mRefEnt . customShader ) ;
}
else
{
// Add our refEntity to the scene
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
}
drawnFx + + ;
}
//----------------------------
// Update
//----------------------------
bool CParticle : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t org ;
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , org , ax ) )
{ //could not get bolt
return false ;
}
vec3_t realVel , realAccel ;
VectorMA ( org , mOrgOffset [ 0 ] , ax [ 0 ] , org ) ;
VectorMA ( org , mOrgOffset [ 1 ] , ax [ 1 ] , org ) ;
VectorMA ( org , mOrgOffset [ 2 ] , ax [ 2 ] , org ) ;
const float time = ( theFxHelper . mTime - mTimeStart ) * 0.001f ;
// calc the real velocity and accel vectors
VectorScale ( ax [ 0 ] , mVel [ 0 ] , realVel ) ;
VectorMA ( realVel , mVel [ 1 ] , ax [ 1 ] , realVel ) ;
VectorMA ( realVel , mVel [ 2 ] , ax [ 2 ] , realVel ) ;
//realVel[2] += 0.5f * mGravity * time;
VectorScale ( ax [ 0 ] , mAccel [ 0 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 1 ] , ax [ 1 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 2 ] , ax [ 2 ] , realAccel ) ;
// Get our real velocity at the current time, taking into account the effects of acceleartion. NOTE: not sure if this is even 100% correct math-wise
VectorMA ( realVel , time , realAccel , realVel ) ;
// Now move us to where we should be at the given time
VectorMA ( org , time , realVel , mOrigin1 ) ;
}
else if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
UpdateRotation ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
// Update Origin
//----------------------------
bool CParticle : : UpdateOrigin ( void )
{
vec3_t new_origin ;
VectorMA ( mVel , theFxHelper . mRealTime , mAccel , mVel ) ;
// Predict the new position
new_origin [ 0 ] = mOrigin1 [ 0 ] + ( theFxHelper . mRealTime * mVel [ 0 ] ) ; // + (theFxHelper.mHalfRealTimeSq * mVel[0]);
new_origin [ 1 ] = mOrigin1 [ 1 ] + ( theFxHelper . mRealTime * mVel [ 1 ] ) ; // + (theFxHelper.mHalfRealTimeSq * mVel[1]);
new_origin [ 2 ] = mOrigin1 [ 2 ] + ( theFxHelper . mRealTime * mVel [ 2 ] ) ; // + (theFxHelper.mHalfRealTimeSq * mVel[2]);
// Only perform physics if this object is tagged to do so
if ( ( mFlags & FX_APPLY_PHYSICS ) & & ! ( mFlags & FX_PLAYER_VIEW ) )
{
bool solid ;
if ( mFlags & FX_EXPENSIVE_PHYSICS )
{
solid = true ; // by setting this to true, we force a real trace to happen
}
else
{
// if this returns solid, we need to do a trace
if ( ! com_RMG | | com_RMG - > integer )
{ // don't do this call for RMG maps
TCGPointContents * data = ( TCGPointContents * ) cl . mSharedMemory ;
VectorCopy ( new_origin , data - > mPoint ) ;
data - > mPassEntityNum = ENTITYNUM_WORLD ;
// if this returns solid, we need to do a trace
solid = ! ! ( VM_Call ( cgvm , CG_POINT_CONTENTS ) & MASK_SOLID ) ;
}
else
{
solid = false ;
}
}
if ( solid )
{
trace_t trace ;
float dot ;
if ( mFlags & FX_USE_BBOX )
{
if ( mFlags & FX_GHOUL2_TRACE )
{
theFxHelper . G2Trace ( trace , mOrigin1 , mMin , mMax , new_origin , - 1 , MASK_SOLID ) ;
}
else
{
theFxHelper . Trace ( trace , mOrigin1 , mMin , mMax , new_origin , - 1 , MASK_SOLID ) ;
}
}
else
{
if ( mFlags & FX_GHOUL2_TRACE )
{
theFxHelper . G2Trace ( trace , mOrigin1 , NULL , NULL , new_origin , - 1 , MASK_PLAYERSOLID ) ;
}
else
{
theFxHelper . Trace ( trace , mOrigin1 , NULL , NULL , new_origin , - 1 , MASK_SOLID ) ;
}
}
// Hit something
if ( trace . startsolid | | trace . allsolid )
{
VectorClear ( mVel ) ;
VectorClear ( mAccel ) ;
if ( ( mFlags & FX_GHOUL2_TRACE ) & & ( mFlags & FX_IMPACT_RUNS_FX ) )
{
static vec3_t bsNormal = { 0 , 1 , 0 } ;
theFxScheduler . PlayEffect ( mImpactFxID , trace . endpos , bsNormal ) ;
}
mFlags & = ~ ( FX_APPLY_PHYSICS | FX_IMPACT_RUNS_FX ) ;
return true ;
}
else if ( trace . fraction < 1.0f ) //&& !trace.startsolid && !trace.allsolid )
{
if ( mFlags & FX_IMPACT_RUNS_FX & & ! ( trace . surfaceFlags & SURF_NOIMPACT ) )
{
theFxScheduler . PlayEffect ( mImpactFxID , trace . endpos , trace . plane . normal ) ;
}
// may need to interact with the material type we hit
theFxScheduler . MaterialImpact ( & trace , ( CEffect * ) this ) ;
if ( mFlags & FX_KILL_ON_IMPACT )
{
// time to die
return false ;
}
VectorMA ( mVel , theFxHelper . mRealTime * trace . fraction , mAccel , mVel ) ;
dot = DotProduct ( mVel , trace . plane . normal ) ;
VectorMA ( mVel , - 2.0f * dot , trace . plane . normal , mVel ) ;
VectorScale ( mVel , mElasticity , mVel ) ;
mElasticity * = 0.5f ;
// If the velocity is too low, make it stop moving, rotating, and turn off physics to avoid
// doing expensive operations when they aren't needed
//if ( trace.plane.normal[2] > 0.33f && mVel[2] < 10.0f )
if ( VectorLengthSquared ( mVel ) < 100.0f )
{
VectorClear ( mVel ) ;
VectorClear ( mAccel ) ;
mFlags & = ~ ( FX_APPLY_PHYSICS | FX_IMPACT_RUNS_FX ) ;
}
// Set the origin to the exact impact point
VectorMA ( trace . endpos , 1.0f , trace . plane . normal , mOrigin1 ) ;
return true ;
}
}
}
// No physics were done to this object, move it
VectorCopy ( new_origin , mOrigin1 ) ;
if ( mFlags & FX_PLAYER_VIEW )
{
if ( mOrigin1 [ 0 ] < 0 | | mOrigin1 [ 0 ] > 639 | | mOrigin1 [ 1 ] < 0 | | mOrigin1 [ 1 ] > 479 )
{
return false ;
}
}
return true ;
}
//----------------------------
// Update Size
//----------------------------
void CParticle : : UpdateSize ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
if ( ( mFlags & FX_SIZE_LINEAR ) )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP
if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_NONLINEAR )
{
if ( theFxHelper . mTime > mSizeParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mSizeParm ) / ( float ) ( mTimeEnd - mSizeParm ) ;
}
if ( mFlags & FX_SIZE_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mSizeParm ) ;
}
else if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_CLAMP )
{
if ( theFxHelper . mTime < mSizeParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mSizeParm - theFxHelper . mTime ) / ( float ) ( mSizeParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( ( mFlags & FX_SIZE_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_SIZE_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
mRefEnt . radius = ( mSizeStart * perc1 ) + ( mSizeEnd * ( 1.0f - perc1 ) ) ;
}
inline int VectorToInt ( vec3_t vec )
{
int tmp , retval ;
2013-04-25 04:09:08 +00:00
# ifdef _MSVC_VER
2013-04-19 02:52:48 +00:00
_asm
{
push edx
mov edx , [ vec ]
fld dword ptr [ edx + 0 ]
fld dword ptr [ edx + 4 ]
fld dword ptr [ edx + 8 ]
mov eax , 0xff00
fistp tmp
mov al , byte ptr [ tmp ]
shl eax , 16
fistp tmp
mov ah , byte ptr [ tmp ]
fistp tmp
mov al , byte ptr [ tmp ]
mov [ retval ] , eax
pop edx
}
2013-04-25 04:09:08 +00:00
# else
asm ( " flds %1; \n \t "
" flds %2; \n \t "
" flds %3; \n \t "
" fistp %4; \n \t "
" movb %4, %%al; \n \t "
" shl $16, %0; \n \t "
" fistp %4; \n \t "
" movb %4, %%ah; \n \t "
" fistp %4; \n \t "
" movb %4, %%al; \n \t "
: " =a " ( retval )
: " m " ( vec [ 0 ] ) , " m " ( vec [ 1 ] ) , " m " ( vec [ 2 ] ) , " m " ( tmp ) , " a " ( 0xff00 )
) ;
# endif
2013-04-19 02:52:48 +00:00
return ( retval ) ;
}
//----------------------------
// Update RGB
//----------------------------
void CParticle : : UpdateRGB ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
vec3_t res ;
if ( ( mFlags & FX_RGB_LINEAR ) )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP
if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_NONLINEAR )
{
if ( theFxHelper . mTime > mRGBParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mRGBParm ) / ( float ) ( mTimeEnd - mRGBParm ) ;
}
if ( ( mFlags & FX_RGB_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mRGBParm ) ;
}
else if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_CLAMP )
{
if ( theFxHelper . mTime < mRGBParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mRGBParm - theFxHelper . mTime ) / ( float ) ( mRGBParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( ( mFlags & FX_RGB_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_RGB_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
// Now get the correct color
VectorScale ( mRGBStart , perc1 , res ) ;
VectorMA ( res , 1.0f - perc1 , mRGBEnd , res ) ;
res [ 0 ] = Com_Clamp ( 0.0f , 1.0f , res [ 0 ] ) * 255.0f ;
res [ 1 ] = Com_Clamp ( 0.0f , 1.0f , res [ 1 ] ) * 255.0f ;
res [ 2 ] = Com_Clamp ( 0.0f , 1.0f , res [ 2 ] ) * 255.0f ;
* ( int * ) mRefEnt . shaderRGBA = VectorToInt ( res ) ;
}
//----------------------------
// Update Alpha
//----------------------------
void CParticle : : UpdateAlpha ( void )
{
int alpha ;
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
if ( ( mFlags & FX_ALPHA_LINEAR ) )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR, FX_WAVE, or FX_CLAMP
if ( ( mFlags & FX_ALPHA_PARM_MASK ) = = FX_ALPHA_NONLINEAR )
{
if ( theFxHelper . mTime > mAlphaParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mAlphaParm ) / ( float ) ( mTimeEnd - mAlphaParm ) ;
}
if ( ( mFlags & FX_ALPHA_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_ALPHA_PARM_MASK ) = = FX_ALPHA_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mAlphaParm ) ;
}
else if ( ( mFlags & FX_ALPHA_PARM_MASK ) = = FX_ALPHA_CLAMP )
{
if ( theFxHelper . mTime < mAlphaParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mAlphaParm - theFxHelper . mTime ) / ( float ) ( mAlphaParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( ( mFlags & FX_ALPHA_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
perc1 = ( mAlphaStart * perc1 ) + ( mAlphaEnd * ( 1.0f - perc1 ) ) ;
// We should be in the right range, but clamp to ensure
perc1 = Com_Clamp ( 0.0f , 1.0f , perc1 ) ;
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_ALPHA_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
alpha = Com_Clamp ( 0 , 255 , perc1 * 255.0f ) ;
if ( mFlags & FX_USE_ALPHA )
{
// should use this when using art that has an alpha channel
mRefEnt . shaderRGBA [ 3 ] = ( byte ) alpha ;
}
else
{
// Modulate the rgb fields by the alpha value to do the fade, works fine for additive blending
mRefEnt . shaderRGBA [ 0 ] = ( ( int ) mRefEnt . shaderRGBA [ 0 ] * alpha ) > > 8 ;
mRefEnt . shaderRGBA [ 1 ] = ( ( int ) mRefEnt . shaderRGBA [ 1 ] * alpha ) > > 8 ;
mRefEnt . shaderRGBA [ 2 ] = ( ( int ) mRefEnt . shaderRGBA [ 2 ] * alpha ) > > 8 ;
}
}
//--------------------------
void CParticle : : UpdateRotation ( void )
{
mRefEnt . rotation + = theFxHelper . mFrameTime * 0.01f * mRotationDelta ;
mRotationDelta * = ( 1.0f - ( theFxHelper . mFrameTime * 0.0007f ) ) ; // decay rotationDelta
}
//--------------------------------
//
// Derived Oriented Particle Class
//
//--------------------------------
COrientedParticle : : COrientedParticle ( void )
{
mRefEnt . reType = RT_ORIENTED_QUAD ;
}
//----------------------------
bool COrientedParticle : : Cull ( void )
{
vec3_t dir ;
// float len;
// Get the direction to the view
VectorSubtract ( mOrigin1 , theFxHelper . refdef - > vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
// len = VectorLengthSquared( dir );
// don't cull stuff that's associated with inview wpns
if ( mFlags & FX_DEPTH_HACK )
{
return false ;
}
// Can't be too close
// if ( len < fx_nearCull->value * fx_nearCull->value)
// {
// return true;
// }
return false ;
}
//----------------------------
void COrientedParticle : : Draw ( void )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
// Add our refEntity to the scene
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
if ( ! ( mFlags & FX_RELATIVE ) )
{
VectorCopy ( mNormal , mRefEnt . axis [ 0 ] ) ;
MakeNormalVectors ( mRefEnt . axis [ 0 ] , mRefEnt . axis [ 1 ] , mRefEnt . axis [ 2 ] ) ;
}
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}
//----------------------------
// Update
//----------------------------
bool COrientedParticle : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t org ;
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , org , ax ) )
{ //could not get bolt
return false ;
}
vec3_t realVel , realAccel ;
VectorMA ( org , mOrgOffset [ 0 ] , ax [ 0 ] , org ) ;
VectorMA ( org , mOrgOffset [ 1 ] , ax [ 1 ] , org ) ;
VectorMA ( org , mOrgOffset [ 2 ] , ax [ 2 ] , org ) ;
const float time = ( theFxHelper . mTime - mTimeStart ) * 0.001f ;
// calc the real velocity and accel vectors
VectorScale ( ax [ 0 ] , mVel [ 0 ] , realVel ) ;
VectorMA ( realVel , mVel [ 1 ] , ax [ 1 ] , realVel ) ;
VectorMA ( realVel , mVel [ 2 ] , ax [ 2 ] , realVel ) ;
// realVel[2] += 0.5f * mGravity * time;
VectorScale ( ax [ 0 ] , mAccel [ 0 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 1 ] , ax [ 1 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 2 ] , ax [ 2 ] , realAccel ) ;
// Get our real velocity at the current time, taking into account the effects of acceleartion. NOTE: not sure if this is even 100% correct math-wise
VectorMA ( realVel , time , realAccel , realVel ) ;
// Now move us to where we should be at the given time
VectorMA ( org , time , realVel , mOrigin1 ) ;
//use the normalOffset and add that to the actual normal of the bolt
//NOTE: not tested!!!
VectorCopy ( ax [ 0 ] , mRefEnt . axis [ 0 ] ) ;
VectorCopy ( ax [ 1 ] , mRefEnt . axis [ 1 ] ) ;
VectorCopy ( ax [ 2 ] , mRefEnt . axis [ 2 ] ) ;
//vec3_t offsetAngles;
//VectorSet( offsetAngles, 0, 90, 90 );
vec3_t offsetAxis [ 3 ] ;
//NOTE: mNormal is actually PITCH YAW and ROLL offsets
AnglesToAxis ( mNormal , offsetAxis ) ;
MatrixMultiply ( offsetAxis , ax , mRefEnt . axis ) ;
}
else if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
if ( ! Cull ( ) )
{ // Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
UpdateRotation ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
//
// Derived Line Class
//
//----------------------------
CLine : : CLine ( void )
{
mRefEnt . reType = RT_LINE ;
}
//----------------------------
void CLine : : Draw ( void )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set, but it can't hurt?
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
VectorCopy ( mOrigin2 , mRefEnt . oldorigin ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}
//----------------------------
bool CLine : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , mOrigin1 , ax ) )
{ //could not get bolt
return false ;
}
VectorAdd ( mOrigin1 , mOrgOffset , mOrigin1 ) ; //add the offset to the bolt point
VectorMA ( mOrigin1 , mVel [ 0 ] , ax [ 0 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mVel [ 1 ] , ax [ 1 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mVel [ 2 ] , ax [ 2 ] , mOrigin2 ) ;
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
//
// Derived Electricity Class
//
//----------------------------
CElectricity : : CElectricity ( void )
{
mRefEnt . reType = RT_ELECTRICITY ;
}
//----------------------------
void CElectricity : : Initialize ( void )
{
mRefEnt . frame = flrand ( 0.0f , 1.0f ) * 1265536.0f ;
mRefEnt . axis [ 0 ] [ 2 ] = theFxHelper . mTime + ( mTimeEnd - mTimeStart ) ; // endtime
if ( mFlags & FX_DEPTH_HACK )
{
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
if ( mFlags & FX_BRANCH )
{
mRefEnt . renderfx | = RF_FORKED ;
}
if ( mFlags & FX_TAPER )
{
mRefEnt . renderfx | = RF_TAPERED ;
}
if ( mFlags & FX_GROW )
{
mRefEnt . renderfx | = RF_GROW ;
}
}
//----------------------------
void CElectricity : : Draw ( void )
{
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
VectorCopy ( mOrigin2 , mRefEnt . oldorigin ) ;
mRefEnt . axis [ 0 ] [ 0 ] = mChaos ;
mRefEnt . axis [ 0 ] [ 1 ] = mTimeEnd - mTimeStart ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}
//----------------------------
bool CElectricity : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , mOrigin1 , ax ) )
{ //could not get bolt
return false ;
}
VectorAdd ( mOrigin1 , mOrgOffset , mOrigin1 ) ; //add the offset to the bolt point
VectorMA ( mOrigin1 , mVel [ 0 ] , ax [ 0 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mVel [ 1 ] , ax [ 1 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mVel [ 2 ] , ax [ 2 ] , mOrigin2 ) ;
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
//
// Derived Tail Class
//
//----------------------------
CTail : : CTail ( void )
{
mRefEnt . reType = RT_LINE ;
}
//----------------------------
void CTail : : Draw ( void )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}
//----------------------------
bool CTail : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t org ;
vec3_t ax [ 3 ] ;
if ( mModelNum > = 0 & & mBoltNum > = 0 ) //bolt style
{
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , org , ax ) )
{ //could not get bolt
return false ;
}
}
vec3_t realVel , realAccel ;
VectorMA ( org , mOrgOffset [ 0 ] , ax [ 0 ] , org ) ;
VectorMA ( org , mOrgOffset [ 1 ] , ax [ 1 ] , org ) ;
VectorMA ( org , mOrgOffset [ 2 ] , ax [ 2 ] , org ) ;
// calc the real velocity and accel vectors
// FIXME: if you want right and up movement in addition to the forward movement, you'll have to convert dir into a set of perp. axes and do some extra work
VectorScale ( ax [ 0 ] , mVel [ 0 ] , realVel ) ;
VectorMA ( realVel , mVel [ 1 ] , ax [ 1 ] , realVel ) ;
VectorMA ( realVel , mVel [ 2 ] , ax [ 2 ] , realVel ) ;
VectorScale ( ax [ 0 ] , mAccel [ 0 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 1 ] , ax [ 1 ] , realAccel ) ;
VectorMA ( realAccel , mAccel [ 2 ] , ax [ 2 ] , realAccel ) ;
const float time = ( theFxHelper . mTime - mTimeStart ) * 0.001f ;
// Get our real velocity at the current time, taking into account the effects of acceleration. NOTE: not sure if this is even 100% correct math-wise
VectorMA ( realVel , time , realAccel , realVel ) ;
// Now move us to where we should be at the given time
VectorMA ( org , time , realVel , mOrigin1 ) ;
// Just calc an old point some time in the past, doesn't really matter when
VectorMA ( org , ( time - 0.003f ) , realVel , mOldOrigin ) ;
}
# ifdef _SOF2DEV_
else if ( ! fx_freeze - > integer )
# else
else
# endif
{
VectorCopy ( mOrigin1 , mOldOrigin ) ;
}
if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateLength ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
CalcNewEndpoint ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
void CTail : : UpdateLength ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
if ( mFlags & FX_LENGTH_LINEAR )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE
if ( ( mFlags & FX_LENGTH_PARM_MASK ) = = FX_LENGTH_NONLINEAR )
{
if ( theFxHelper . mTime > mLengthParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mLengthParm ) / ( float ) ( mTimeEnd - mLengthParm ) ;
}
if ( mFlags & FX_LENGTH_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_LENGTH_PARM_MASK ) = = FX_LENGTH_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mLengthParm ) ;
}
else if ( ( mFlags & FX_LENGTH_PARM_MASK ) = = FX_LENGTH_CLAMP )
{
if ( theFxHelper . mTime < mLengthParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mLengthParm - theFxHelper . mTime ) / ( float ) ( mLengthParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( mFlags & FX_LENGTH_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_LENGTH_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
mLength = ( mLengthStart * perc1 ) + ( mLengthEnd * ( 1.0f - perc1 ) ) ;
}
//----------------------------
void CTail : : CalcNewEndpoint ( void )
{
vec3_t temp ;
// FIXME: Hmmm, this looks dumb when physics are on and a bounce happens
VectorSubtract ( mOldOrigin , mOrigin1 , temp ) ;
// I wish we didn't have to do a VectorNormalize every frame.....
VectorNormalize ( temp ) ;
VectorMA ( mOrigin1 , mLength , temp , mRefEnt . oldorigin ) ;
}
//----------------------------
//
// Derived Cylinder Class
//
//----------------------------
CCylinder : : CCylinder ( void )
{
mRefEnt . reType = RT_CYLINDER ;
mTraceEnd = qfalse ;
}
bool CCylinder : : Cull ( void )
{
if ( mTraceEnd )
{ //eh, don't cull variable-length cylinders
return false ;
}
return CTail : : Cull ( ) ;
}
void CCylinder : : UpdateLength ( void )
{
if ( mTraceEnd )
{
vec3_t temp ;
trace_t tr ;
VectorMA ( mOrigin1 , FX_MAX_TRACE_DIST , mRefEnt . axis [ 0 ] , temp ) ;
theFxHelper . Trace ( tr , mOrigin1 , NULL , NULL , temp , - 1 , MASK_SOLID ) ;
VectorSubtract ( tr . endpos , mOrigin1 , temp ) ;
mLength = VectorLength ( temp ) ;
}
else
{
CTail : : UpdateLength ( ) ;
}
}
//----------------------------
void CCylinder : : Draw ( void )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set, but it can't hurt?
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
VectorMA ( mOrigin1 , mLength , mRefEnt . axis [ 0 ] , mRefEnt . oldorigin ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}
//----------------------------
// Update Size2
//----------------------------
void CCylinder : : UpdateSize2 ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
if ( mFlags & FX_SIZE2_LINEAR )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE
if ( ( mFlags & FX_SIZE2_PARM_MASK ) = = FX_SIZE2_NONLINEAR )
{
if ( theFxHelper . mTime > mSize2Parm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mSize2Parm ) / ( float ) ( mTimeEnd - mSize2Parm ) ;
}
if ( ( mFlags & FX_SIZE2_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_SIZE2_PARM_MASK ) = = FX_SIZE2_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mSize2Parm ) ;
}
else if ( ( mFlags & FX_SIZE2_PARM_MASK ) = = FX_SIZE2_CLAMP )
{
if ( theFxHelper . mTime < mSize2Parm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mSize2Parm - theFxHelper . mTime ) / ( float ) ( mSize2Parm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( mFlags & FX_SIZE2_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_SIZE2_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
mRefEnt . rotation = ( mSize2Start * perc1 ) + ( mSize2End * ( 1.0f - perc1 ) ) ;
}
//----------------------------
bool CCylinder : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , mOrigin1 , ax ) )
{ //could not get bolt
return false ;
}
VectorAdd ( mOrigin1 , mOrgOffset , mOrigin1 ) ; //add the offset to the bolt point
VectorCopy ( ax [ 0 ] , mRefEnt . axis [ 0 ] ) ;
//FIXME: should mNormal be a modifier on the forward axis?
/*
VectorMA ( mOrigin1 , mNormal [ 0 ] , ax [ 0 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mNormal [ 1 ] , ax [ 1 ] , mOrigin2 ) ;
VectorMA ( mOrigin2 , mNormal [ 2 ] , ax [ 2 ] , mOrigin2 ) ;
*/
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateSize2 ( ) ;
UpdateLength ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
//
// Derived Emitter Class
//
//----------------------------
CEmitter : : CEmitter ( void )
{
// There may or may not be a model, but if there isn't one,
// we just won't bother adding the refEnt in our Draw func
mRefEnt . reType = RT_MODEL ;
}
//----------------------------
CEmitter : : ~ CEmitter ( void )
{
}
//----------------------------
// Draw
//----------------------------
void CEmitter : : Draw ( void )
{
// Emitters don't draw themselves, but they may need to add an attached model
if ( mFlags & FX_ATTACHED_MODEL )
{
mRefEnt . nonNormalizedAxes = qtrue ;
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
VectorScale ( mRefEnt . axis [ 0 ] , mRefEnt . radius , mRefEnt . axis [ 0 ] ) ;
VectorScale ( mRefEnt . axis [ 1 ] , mRefEnt . radius , mRefEnt . axis [ 1 ] ) ;
VectorScale ( mRefEnt . axis [ 2 ] , mRefEnt . radius , mRefEnt . axis [ 2 ] ) ;
theFxHelper . AddFxToScene ( ( miniRefEntity_t * ) 0 ) ; // I hate having to do this, but this needs to get added as a regular refEntity
theFxHelper . AddFxToScene ( & mRefEnt ) ;
}
// If we are emitting effects, we had better be careful because just calling it every cgame frame could
// either choke up the effects system on a fast machine, or look really nasty on a low end one.
if ( mFlags & FX_EMIT_FX )
{
vec3_t org , v ;
float ftime , time2 , step ;
int t , dif ;
# define TRAIL_RATE 12 // we "think" at about a 60hz rate
// Pick a target step distance and square it
step = mDensity + flrand ( - mVariance , mVariance ) ;
step * = step ;
dif = 0 ;
for ( t = mOldTime ; t < = theFxHelper . mTime ; t + = TRAIL_RATE )
{
dif + = TRAIL_RATE ;
// ?Not sure if it's better to update this before or after updating the origin
VectorMA ( mOldVelocity , dif * 0.001f , mAccel , v ) ;
// Calc the time differences
ftime = dif * 0.001f ;
time2 = ftime * ftime * 0.5f ;
// Predict the new position
org [ 0 ] = mOldOrigin [ 0 ] + ( ftime * v [ 0 ] ) + ( time2 * v [ 0 ] ) ;
org [ 1 ] = mOldOrigin [ 1 ] + ( ftime * v [ 1 ] ) + ( time2 * v [ 1 ] ) ;
org [ 2 ] = mOldOrigin [ 2 ] + ( ftime * v [ 2 ] ) + ( time2 * v [ 2 ] ) ;
// Is it time to draw an effect?
if ( DistanceSquared ( org , mOldOrigin ) > = step )
{
// Pick a new target step distance and square it
step = mDensity + flrand ( - mVariance , mVariance ) ;
step * = step ;
// We met the step criteria so, we should add in the effect
theFxScheduler . PlayEffect ( mEmitterFxID , org , mRefEnt . axis ) ;
VectorCopy ( org , mOldOrigin ) ;
VectorCopy ( v , mOldVelocity ) ;
dif = 0 ;
mOldTime = t ;
}
}
}
drawnFx + + ;
}
//----------------------------
bool CEmitter : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
// Use this to track if we've stopped moving
VectorCopy ( mOrigin1 , mOldOrigin ) ;
VectorCopy ( mVel , mOldVelocity ) ;
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
assert ( 0 ) ; //need this?
}
if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
bool moving = false ;
// If the thing is no longer moving, kill the angle delta, but don't do it too quickly or it will
// look very artificial. Don't do it too slowly or it will look like there is no friction.
if ( VectorCompare ( mOldOrigin , mOrigin1 ) )
{
VectorScale ( mAngleDelta , 0.7f , mAngleDelta ) ;
}
else
{
moving = true ;
}
if ( mFlags & FX_PAPER_PHYSICS )
{
// do this in a more framerate independant manner
float sc = ( 20.0f / theFxHelper . mFrameTime ) ;
// bah, evil clamping
if ( sc > = 1.0f )
{
sc = 1.0f ;
}
if ( moving )
{
// scale the velocity down, basically inducing drag. Acceleration ( gravity ) should keep it pulling down, which is what we want.
VectorScale ( mVel , ( sc * 0.8f + 0.2f ) * 0.92f , mVel ) ;
// add some chaotic motion based on the way we are oriented
VectorMA ( mVel , ( 1.5f - sc ) * 4.0f , mRefEnt . axis [ 0 ] , mVel ) ;
VectorMA ( mVel , ( 1.5f - sc ) * 4.0f , mRefEnt . axis [ 1 ] , mVel ) ;
}
// make us settle so we can lay flat
mAngles [ 0 ] * = ( 0.97f * ( sc * 0.4f + 0.6f ) ) ;
mAngles [ 2 ] * = ( 0.97f * ( sc * 0.4f + 0.6f ) ) ;
// decay our angle delta so we don't rotate as quickly
VectorScale ( mAngleDelta , ( 0.96f * ( sc * 0.1f + 0.9f ) ) , mAngleDelta ) ;
}
UpdateAngles ( ) ;
UpdateSize ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
void CEmitter : : UpdateAngles ( void )
{
VectorMA ( mAngles , theFxHelper . mFrameTime * 0.01f , mAngleDelta , mAngles ) ; // was 0.001f, but then you really have to jack up the delta to even notice anything
AnglesToAxis ( mAngles , mRefEnt . axis ) ;
}
//--------------------------
//
// Derived Light Class
//
//--------------------------
//----------------------------
void CLight : : Draw ( void )
{
# ifdef VV_LIGHTING
VVLightMan . RE_AddLightToScene ( mOrigin1 , mRefEnt . radius , mRefEnt . origin [ 0 ] , mRefEnt . origin [ 1 ] , mRefEnt . origin [ 2 ] ) ;
# else
theFxHelper . AddLightToScene ( mOrigin1 , mRefEnt . radius , mRefEnt . origin [ 0 ] , mRefEnt . origin [ 1 ] , mRefEnt . origin [ 2 ] ) ;
# endif
drawnFx + + ;
}
//----------------------------
// Update
//----------------------------
bool CLight : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( mFlags & FX_RELATIVE )
{
if ( ! mGhoul2 . IsValid ( ) )
{ // the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t ax [ 3 ] ;
// Get our current position and direction
if ( ! theFxHelper . GetOriginAxisFromBolt ( & mGhoul2 , mEntNum , mModelNum , mBoltNum , mOrigin1 , ax ) )
{ //could not get bolt
return false ;
}
VectorMA ( mOrigin1 , mOrgOffset [ 0 ] , ax [ 0 ] , mOrigin1 ) ;
VectorMA ( mOrigin1 , mOrgOffset [ 1 ] , ax [ 1 ] , mOrigin1 ) ;
VectorMA ( mOrigin1 , mOrgOffset [ 2 ] , ax [ 2 ] , mOrigin1 ) ;
}
UpdateSize ( ) ;
UpdateRGB ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
// Update Size
//----------------------------
void CLight : : UpdateSize ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
if ( mFlags & FX_SIZE_LINEAR )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE
if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_NONLINEAR )
{
if ( theFxHelper . mTime > mSizeParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mSizeParm ) / ( float ) ( mTimeEnd - mSizeParm ) ;
}
if ( ( mFlags & FX_SIZE_LINEAR ) )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mSizeParm ) ;
}
else if ( ( mFlags & FX_SIZE_PARM_MASK ) = = FX_SIZE_CLAMP )
{
if ( theFxHelper . mTime < mSizeParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mSizeParm - theFxHelper . mTime ) / ( float ) ( mSizeParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( mFlags & FX_SIZE_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_SIZE_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
mRefEnt . radius = ( mSizeStart * perc1 ) + ( mSizeEnd * ( 1.0f - perc1 ) ) ;
}
//----------------------------
// Update RGB
//----------------------------
void CLight : : UpdateRGB ( void )
{
// completely biased towards start if it doesn't get overridden
float perc1 = 1.0f , perc2 = 1.0f ;
vec3_t res ;
if ( mFlags & FX_RGB_LINEAR )
{
// calculate element biasing
perc1 = 1.0f - ( float ) ( theFxHelper . mTime - mTimeStart ) / ( float ) ( mTimeEnd - mTimeStart ) ;
}
// We can combine FX_LINEAR with _either_ FX_NONLINEAR or FX_WAVE
if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_NONLINEAR )
{
if ( theFxHelper . mTime > mRGBParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = 1.0f - ( float ) ( theFxHelper . mTime - mRGBParm ) / ( float ) ( mTimeEnd - mRGBParm ) ;
}
if ( mFlags & FX_RGB_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
else if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_WAVE )
{
// wave gen, with parm being the frequency multiplier
perc1 = perc1 * cosf ( ( theFxHelper . mTime - mTimeStart ) * mRGBParm ) ;
}
else if ( ( mFlags & FX_RGB_PARM_MASK ) = = FX_RGB_CLAMP )
{
if ( theFxHelper . mTime < mRGBParm )
{
// get percent done, using parm as the start of the non-linear fade
perc2 = ( float ) ( mRGBParm - theFxHelper . mTime ) / ( float ) ( mRGBParm - mTimeStart ) ;
}
else
{
perc2 = 0.0f ; // make it full size??
}
if ( mFlags & FX_RGB_LINEAR )
{
// do an even blend
perc1 = perc1 * 0.5f + perc2 * 0.5f ;
}
else
{
// just copy it over...sigh
perc1 = perc2 ;
}
}
// If needed, RAND can coexist with linear and either non-linear or wave.
if ( mFlags & FX_RGB_RAND )
{
// Random simply modulates the existing value
perc1 = flrand ( 0.0f , perc1 ) ;
}
// Now get the correct color
VectorScale ( mRGBStart , perc1 , res ) ;
VectorMA ( res , ( 1.0f - perc1 ) , mRGBEnd , mRefEnt . origin ) ;
}
//--------------------------
//
// Derived Trail Class
//
//--------------------------
# define NEW_MUZZLE 0
# define NEW_TIP 1
# define OLD_TIP 2
# define OLD_MUZZLE 3
//----------------------------
void CTrail : : Draw ( )
{
polyVert_t verts [ 3 ] ;
// vec3_t color;
// build the first tri out of the new muzzle...new tip...old muzzle
VectorCopy ( mVerts [ NEW_MUZZLE ] . origin , verts [ 0 ] . xyz ) ;
VectorCopy ( mVerts [ NEW_TIP ] . origin , verts [ 1 ] . xyz ) ;
VectorCopy ( mVerts [ OLD_MUZZLE ] . origin , verts [ 2 ] . xyz ) ;
// VectorScale( mVerts[NEW_MUZZLE].curRGB, mVerts[NEW_MUZZLE].curAlpha, color );
verts [ 0 ] . modulate [ 0 ] = mVerts [ NEW_MUZZLE ] . rgb [ 0 ] ;
verts [ 0 ] . modulate [ 1 ] = mVerts [ NEW_MUZZLE ] . rgb [ 1 ] ;
verts [ 0 ] . modulate [ 2 ] = mVerts [ NEW_MUZZLE ] . rgb [ 2 ] ;
verts [ 0 ] . modulate [ 3 ] = mVerts [ NEW_MUZZLE ] . alpha ;
// VectorScale( mVerts[NEW_TIP].curRGB, mVerts[NEW_TIP].curAlpha, color );
verts [ 1 ] . modulate [ 0 ] = mVerts [ NEW_TIP ] . rgb [ 0 ] ;
verts [ 1 ] . modulate [ 1 ] = mVerts [ NEW_TIP ] . rgb [ 1 ] ;
verts [ 1 ] . modulate [ 2 ] = mVerts [ NEW_TIP ] . rgb [ 2 ] ;
verts [ 1 ] . modulate [ 3 ] = mVerts [ NEW_TIP ] . alpha ;
// VectorScale( mVerts[OLD_MUZZLE].curRGB, mVerts[OLD_MUZZLE].curAlpha, color );
verts [ 2 ] . modulate [ 0 ] = mVerts [ OLD_MUZZLE ] . rgb [ 0 ] ;
verts [ 2 ] . modulate [ 1 ] = mVerts [ OLD_MUZZLE ] . rgb [ 1 ] ;
verts [ 2 ] . modulate [ 2 ] = mVerts [ OLD_MUZZLE ] . rgb [ 2 ] ;
verts [ 2 ] . modulate [ 3 ] = mVerts [ OLD_MUZZLE ] . alpha ;
verts [ 0 ] . st [ 0 ] = mVerts [ NEW_MUZZLE ] . curST [ 0 ] ;
verts [ 0 ] . st [ 1 ] = mVerts [ NEW_MUZZLE ] . curST [ 1 ] ;
verts [ 1 ] . st [ 0 ] = mVerts [ NEW_TIP ] . curST [ 0 ] ;
verts [ 1 ] . st [ 1 ] = mVerts [ NEW_TIP ] . curST [ 1 ] ;
verts [ 2 ] . st [ 0 ] = mVerts [ OLD_MUZZLE ] . curST [ 0 ] ;
verts [ 2 ] . st [ 1 ] = mVerts [ OLD_MUZZLE ] . curST [ 1 ] ;
// Add this tri
theFxHelper . AddPolyToScene ( mShader , 3 , verts ) ;
// build the second tri out of the old muzzle...old tip...new tip
VectorCopy ( mVerts [ OLD_MUZZLE ] . origin , verts [ 0 ] . xyz ) ;
VectorCopy ( mVerts [ OLD_TIP ] . origin , verts [ 1 ] . xyz ) ;
VectorCopy ( mVerts [ NEW_TIP ] . origin , verts [ 2 ] . xyz ) ;
// VectorScale( mVerts[OLD_MUZZLE].curRGB, mVerts[OLD_MUZZLE].curAlpha, color );
verts [ 0 ] . modulate [ 0 ] = mVerts [ OLD_MUZZLE ] . rgb [ 0 ] ;
verts [ 0 ] . modulate [ 1 ] = mVerts [ OLD_MUZZLE ] . rgb [ 1 ] ;
verts [ 0 ] . modulate [ 2 ] = mVerts [ OLD_MUZZLE ] . rgb [ 2 ] ;
verts [ 0 ] . modulate [ 3 ] = mVerts [ OLD_MUZZLE ] . alpha ;
// VectorScale( mVerts[OLD_TIP].curRGB, mVerts[OLD_TIP].curAlpha, color );
verts [ 1 ] . modulate [ 0 ] = mVerts [ OLD_TIP ] . rgb [ 0 ] ;
verts [ 1 ] . modulate [ 1 ] = mVerts [ OLD_TIP ] . rgb [ 1 ] ;
verts [ 1 ] . modulate [ 2 ] = mVerts [ OLD_TIP ] . rgb [ 2 ] ;
verts [ 0 ] . modulate [ 3 ] = mVerts [ OLD_TIP ] . alpha ;
// VectorScale( mVerts[NEW_TIP].curRGB, mVerts[NEW_TIP].curAlpha, color );
verts [ 2 ] . modulate [ 0 ] = mVerts [ NEW_TIP ] . rgb [ 0 ] ;
verts [ 2 ] . modulate [ 1 ] = mVerts [ NEW_TIP ] . rgb [ 1 ] ;
verts [ 2 ] . modulate [ 2 ] = mVerts [ NEW_TIP ] . rgb [ 2 ] ;
verts [ 0 ] . modulate [ 3 ] = mVerts [ NEW_TIP ] . alpha ;
verts [ 0 ] . st [ 0 ] = mVerts [ OLD_MUZZLE ] . curST [ 0 ] ;
verts [ 0 ] . st [ 1 ] = mVerts [ OLD_MUZZLE ] . curST [ 1 ] ;
verts [ 1 ] . st [ 0 ] = mVerts [ OLD_TIP ] . curST [ 0 ] ;
verts [ 1 ] . st [ 1 ] = mVerts [ OLD_TIP ] . curST [ 1 ] ;
verts [ 2 ] . st [ 0 ] = mVerts [ NEW_TIP ] . curST [ 0 ] ;
verts [ 2 ] . st [ 1 ] = mVerts [ NEW_TIP ] . curST [ 1 ] ;
// Add this tri
theFxHelper . AddPolyToScene ( mShader , 3 , verts ) ;
drawnFx + + ;
}
//----------------------------
// Update
//----------------------------
bool CTrail : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
float perc = ( float ) ( mTimeEnd - theFxHelper . mTime ) / ( float ) ( mTimeEnd - mTimeStart ) ;
for ( int t = 0 ; t < 4 ; t + + )
{
// mVerts[t].curAlpha = mVerts[t].alpha * perc + mVerts[t].destAlpha * ( 1.0f - perc );
// if ( mVerts[t].curAlpha < 0.0f )
// {
// mVerts[t].curAlpha = 0.0f;
// }
// VectorScale( mVerts[t].rgb, perc, mVerts[t].curRGB );
// VectorMA( mVerts[t].curRGB, ( 1.0f - perc ), mVerts[t].destrgb, mVerts[t].curRGB );
mVerts [ t ] . curST [ 0 ] = mVerts [ t ] . ST [ 0 ] * perc + mVerts [ t ] . destST [ 0 ] * ( 1.0f - perc ) ;
if ( mVerts [ t ] . curST [ 0 ] > 1.0f )
{
mVerts [ t ] . curST [ 0 ] = 1.0f ;
}
mVerts [ t ] . curST [ 1 ] = mVerts [ t ] . ST [ 1 ] * perc + mVerts [ t ] . destST [ 1 ] * ( 1.0f - perc ) ;
}
Draw ( ) ;
return true ;
}
//--------------------------
//
// Derived Poly Class
//
//--------------------------
//----------------------------
bool CPoly : : Cull ( void )
{
vec3_t dir ;
// Get the direction to the view
VectorSubtract ( mOrigin1 , theFxHelper . refdef - > vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
float len = VectorLengthSquared ( dir ) ;
// Can't be too close
if ( len < fx_nearCull - > value * fx_nearCull - > value )
{
return true ;
}
return false ;
}
//----------------------------
void CPoly : : Draw ( void )
{
polyVert_t verts [ MAX_CPOLY_VERTS ] ;
for ( int i = 0 ; i < mCount ; i + + )
{
// Add our midpoint and vert offset to get the actual vertex
VectorAdd ( mOrigin1 , mOrg [ i ] , verts [ i ] . xyz ) ;
// Assign the same color to each vert
* ( int * ) verts [ i ] . modulate = * ( int * ) mRefEnt . shaderRGBA ;
// Copy the ST coords
Vector2Copy ( mST [ i ] , verts [ i ] . st ) ;
}
// Add this poly
theFxHelper . AddPolyToScene ( mRefEnt . customShader , mCount , verts ) ;
drawnFx + + ;
}
//----------------------------
void CPoly : : CalcRotateMatrix ( void )
{
float cosX , cosZ ;
float sinX , sinZ ;
float rad ;
// rotate around Z
rad = DEG2RAD ( mRotDelta [ YAW ] * theFxHelper . mFrameTime * 0.01f ) ;
cosZ = cosf ( rad ) ;
sinZ = sinf ( rad ) ;
// rotate around X
rad = DEG2RAD ( mRotDelta [ PITCH ] * theFxHelper . mFrameTime * 0.01f ) ;
cosX = cosf ( rad ) ;
sinX = sinf ( rad ) ;
/*Pitch - aroundx Yaw - around z
1 0 0 c - s 0
0 c - s s c 0
0 s c 0 0 1
*/
mRot [ 0 ] [ 0 ] = cosZ ;
mRot [ 1 ] [ 0 ] = - sinZ ;
mRot [ 2 ] [ 0 ] = 0 ;
mRot [ 0 ] [ 1 ] = cosX * sinZ ;
mRot [ 1 ] [ 1 ] = cosX * cosZ ;
mRot [ 2 ] [ 1 ] = - sinX ;
mRot [ 0 ] [ 2 ] = sinX * sinZ ;
mRot [ 1 ] [ 2 ] = sinX * cosZ ;
mRot [ 2 ] [ 2 ] = cosX ;
/*
// ROLL is not supported unless anyone complains, if it needs to be added, use this format
Roll
c 0 s
0 1 0
- s 0 c
*/
mLastFrameTime = theFxHelper . mFrameTime ;
}
//--------------------------------
void CPoly : : Rotate ( void )
{
vec3_t temp [ MAX_CPOLY_VERTS ] ;
float dif = fabs ( ( float ) ( mLastFrameTime - theFxHelper . mFrameTime ) ) ;
if ( dif > 0.1f * mLastFrameTime )
{
CalcRotateMatrix ( ) ;
}
// Multiply our rotation matrix by each of the offset verts to get their new position
for ( int i = 0 ; i < mCount ; i + + )
{
VectorRotate ( mOrg [ i ] , mRot , temp [ i ] ) ;
VectorCopy ( temp [ i ] , mOrg [ i ] ) ;
}
}
//----------------------------
// Update
//----------------------------
bool CPoly : : Update ( void )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
// If our timestamp hasn't exired yet, we won't even consider doing any kind of motion
if ( theFxHelper . mTime > mTimeStamp )
{
vec3_t mOldOrigin ;
VectorCopy ( mOrigin1 , mOldOrigin ) ;
if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
// Only rotate whilst moving
if ( ! VectorCompare ( mOldOrigin , mOrigin1 ) )
{
Rotate ( ) ;
}
}
if ( ! Cull ( ) )
{
// Only update these if the thing is visible.
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
void CPoly : : PolyInit ( void )
{
if ( mCount < 3 )
{
return ;
}
int i ;
vec3_t org = { 0.0f , 0.0f , 0.0f } ;
// Find our midpoint
for ( i = 0 ; i < mCount ; i + + )
{
VectorAdd ( org , mOrg [ i ] , org ) ;
}
VectorScale ( org , ( float ) ( 1.0f / mCount ) , org ) ;
// now store our midpoint for physics purposes
VectorCopy ( org , mOrigin1 ) ;
// Now we process the passed in points and make it so that they aren't actually the point...
// rather, they are the offset from mOrigin1.
for ( i = 0 ; i < mCount ; i + + )
{
VectorSubtract ( mOrg [ i ] , mOrigin1 , mOrg [ i ] ) ;
}
CalcRotateMatrix ( ) ;
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - -
CBezier
Bezier curve line
- - - - - - - - - - - - - - - - - - - - - - - - -
*/
bool CBezier : : Cull ( void )
{
vec3_t dir ;
VectorSubtract ( mOrigin1 , theFxHelper . refdef - > vieworg , dir ) ;
//Check if it's in front of the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) > = 0 )
{
return false ; //don't cull
}
VectorSubtract ( mOrigin2 , theFxHelper . refdef - > vieworg , dir ) ;
//Check if it's in front of the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) > = 0 )
{
return false ;
}
VectorSubtract ( mControl1 , theFxHelper . refdef - > vieworg , dir ) ;
//Check if it's in front of the viewer
if ( ( DotProduct ( theFxHelper . refdef - > viewaxis [ 0 ] , dir ) ) > = 0 )
{
return false ;
}
return true ; //all points behind viewer
}
//----------------------------
bool CBezier : : Update ( void )
{
float ftime , time2 ;
ftime = theFxHelper . mFrameTime * 0.001f ;
time2 = ftime * ftime * 0.5f ;
mControl1 [ 0 ] = mControl1 [ 0 ] + ( ftime * mControl1Vel [ 0 ] ) + ( time2 * mControl1Vel [ 0 ] ) ;
mControl2 [ 0 ] = mControl2 [ 0 ] + ( ftime * mControl2Vel [ 0 ] ) + ( time2 * mControl2Vel [ 0 ] ) ;
mControl1 [ 1 ] = mControl1 [ 1 ] + ( ftime * mControl1Vel [ 1 ] ) + ( time2 * mControl1Vel [ 1 ] ) ;
mControl2 [ 1 ] = mControl2 [ 1 ] + ( ftime * mControl2Vel [ 1 ] ) + ( time2 * mControl2Vel [ 1 ] ) ;
mControl1 [ 2 ] = mControl1 [ 2 ] + ( ftime * mControl1Vel [ 2 ] ) + ( time2 * mControl1Vel [ 2 ] ) ;
mControl2 [ 2 ] = mControl2 [ 2 ] + ( ftime * mControl2Vel [ 2 ] ) + ( time2 * mControl2Vel [ 2 ] ) ;
if ( Cull ( ) = = false )
{
// Only update these if the thing is visible.
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
inline void CBezier : : DrawSegment ( vec3_t start , vec3_t end , float texcoord1 , float texcoord2 , float segPercent , float lastSegPercent )
{
vec3_t lineDir , cross , viewDir ;
static vec3_t lastEnd [ 2 ] ;
polyVert_t verts [ 4 ] ;
float scaleBottom = 0.0f , scaleTop = 0.0f ;
VectorSubtract ( end , start , lineDir ) ;
VectorSubtract ( end , theFxHelper . refdef - > vieworg , viewDir ) ;
CrossProduct ( lineDir , viewDir , cross ) ;
VectorNormalize ( cross ) ;
// scaleBottom is the width of the bottom edge of the quad, scaleTop is the width of the top edge
scaleBottom = ( mSizeStart + ( ( mSizeEnd - mSizeStart ) * lastSegPercent ) ) * 0.5f ;
scaleTop = ( mSizeStart + ( ( mSizeEnd - mSizeStart ) * segPercent ) ) * 0.5f ;
//Construct the oriented quad
if ( mInit )
{
VectorCopy ( lastEnd [ 0 ] , verts [ 0 ] . xyz ) ;
VectorCopy ( lastEnd [ 1 ] , verts [ 1 ] . xyz ) ;
}
else
{
VectorMA ( start , - scaleBottom , cross , verts [ 0 ] . xyz ) ;
VectorMA ( start , scaleBottom , cross , verts [ 1 ] . xyz ) ;
}
verts [ 0 ] . st [ 0 ] = 0.0f ;
verts [ 0 ] . st [ 1 ] = texcoord1 ;
verts [ 0 ] . modulate [ 0 ] = mRefEnt . shaderRGBA [ 0 ] * ( 1.0f - texcoord1 ) ;
verts [ 0 ] . modulate [ 1 ] = mRefEnt . shaderRGBA [ 1 ] * ( 1.0f - texcoord1 ) ;
verts [ 0 ] . modulate [ 2 ] = mRefEnt . shaderRGBA [ 2 ] * ( 1.0f - texcoord1 ) ;
verts [ 0 ] . modulate [ 3 ] = mRefEnt . shaderRGBA [ 3 ] ;
verts [ 1 ] . st [ 0 ] = 1.0f ;
verts [ 1 ] . st [ 1 ] = texcoord1 ;
verts [ 1 ] . modulate [ 0 ] = mRefEnt . shaderRGBA [ 0 ] * ( 1.0f - texcoord1 ) ;
verts [ 1 ] . modulate [ 1 ] = mRefEnt . shaderRGBA [ 1 ] * ( 1.0f - texcoord1 ) ;
verts [ 1 ] . modulate [ 2 ] = mRefEnt . shaderRGBA [ 2 ] * ( 1.0f - texcoord1 ) ;
verts [ 1 ] . modulate [ 3 ] = mRefEnt . shaderRGBA [ 3 ] ;
if ( texcoord1 = = 0.0f )
{
* ( int * ) verts [ 0 ] . modulate = 0 ;
* ( int * ) verts [ 1 ] . modulate = 0 ;
}
VectorMA ( end , scaleTop , cross , verts [ 2 ] . xyz ) ;
verts [ 2 ] . st [ 0 ] = 1.0f ;
verts [ 2 ] . st [ 1 ] = texcoord2 ;
verts [ 2 ] . modulate [ 0 ] = mRefEnt . shaderRGBA [ 0 ] * ( 1.0f - texcoord2 ) ;
verts [ 2 ] . modulate [ 1 ] = mRefEnt . shaderRGBA [ 1 ] * ( 1.0f - texcoord2 ) ;
verts [ 2 ] . modulate [ 2 ] = mRefEnt . shaderRGBA [ 2 ] * ( 1.0f - texcoord2 ) ;
verts [ 2 ] . modulate [ 3 ] = mRefEnt . shaderRGBA [ 3 ] ;
VectorMA ( end , - scaleTop , cross , verts [ 3 ] . xyz ) ;
verts [ 3 ] . st [ 0 ] = 0.0f ;
verts [ 3 ] . st [ 1 ] = texcoord2 ;
verts [ 3 ] . modulate [ 0 ] = mRefEnt . shaderRGBA [ 0 ] * ( 1.0f - texcoord2 ) ;
verts [ 3 ] . modulate [ 1 ] = mRefEnt . shaderRGBA [ 1 ] * ( 1.0f - texcoord2 ) ;
verts [ 3 ] . modulate [ 2 ] = mRefEnt . shaderRGBA [ 2 ] * ( 1.0f - texcoord2 ) ;
verts [ 3 ] . modulate [ 3 ] = mRefEnt . shaderRGBA [ 3 ] ;
theFxHelper . AddPolyToScene ( mRefEnt . customShader , 4 , verts ) ;
VectorCopy ( verts [ 2 ] . xyz , lastEnd [ 1 ] ) ;
VectorCopy ( verts [ 3 ] . xyz , lastEnd [ 0 ] ) ;
mInit = true ;
}
const float BEZIER_RESOLUTION = 16.0f ;
//----------------------------
void CBezier : : Draw ( void )
{
vec3_t pos , old_pos ;
float mu , mum1 ;
float incr = 1.0f / BEZIER_RESOLUTION , tex = 1.0f , tc1 , tc2 ;
int i = 0 ;
VectorCopy ( mOrigin1 , old_pos ) ;
mInit = false ; //Signify a new batch for vert gluing
float mum13 , mu3 , group1 , group2 ;
tc1 = 0.0f ;
for ( mu = incr ; mu < = 1.0f ; mu + = incr )
{
//Four point curve
mum1 = 1 - mu ;
mum13 = mum1 * mum1 * mum1 ;
mu3 = mu * mu * mu ;
group1 = 3 * mu * mum1 * mum1 ;
group2 = 3 * mu * mu * mum1 ;
for ( i = 0 ; i < 3 ; i + + )
{
pos [ i ] = mum13 * mOrigin1 [ i ] + group1 * mControl1 [ i ] + group2 * mControl2 [ i ] + mu3 * mOrigin2 [ i ] ;
}
tc2 = mu * tex ;
//Draw it
DrawSegment ( old_pos , pos , tc1 , tc2 , mu , mu - incr ) ;
VectorCopy ( pos , old_pos ) ;
tc1 = tc2 ;
}
drawnFx + + ;
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - -
CFlash
Full screen flash
- - - - - - - - - - - - - - - - - - - - - - - - -
*/
//----------------------------
bool CFlash : : Update ( void )
{
if ( UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
UpdateSize ( ) ;
mRefEnt . radius * = mRadiusModifier ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
return true ;
}
bool FX_WorldToScreen ( vec3_t worldCoord , float * x , float * y )
{
int xcenter , ycenter ;
vec3_t local , transformed ;
vec3_t vfwd , vright , vup ;
//NOTE: did it this way because most draw functions expect virtual 640x480 coords
// and adjust them for current resolution
xcenter = 640 / 2 ; //gives screen coords in virtual 640x480, to be adjusted when drawn
ycenter = 480 / 2 ; //gives screen coords in virtual 640x480, to be adjusted when drawn
VectorSubtract ( worldCoord , theFxHelper . refdef - > vieworg , local ) ;
AngleVectors ( theFxHelper . refdef - > viewangles , vfwd , vright , vup ) ;
transformed [ 0 ] = DotProduct ( local , vright ) ;
transformed [ 1 ] = DotProduct ( local , vup ) ;
transformed [ 2 ] = DotProduct ( local , vfwd ) ;
// Make sure Z is not negative.
if ( transformed [ 2 ] < 0.01 )
{
return false ;
}
// Simple convert to screen coords.
float xzi = xcenter / transformed [ 2 ] * ( 90.0 / theFxHelper . refdef - > fov_x ) ;
float yzi = ycenter / transformed [ 2 ] * ( 90.0 / theFxHelper . refdef - > fov_y ) ;
* x = ( xcenter + xzi * transformed [ 0 ] ) ;
* y = ( ycenter - yzi * transformed [ 1 ] ) ;
return true ;
}
//----------------------------
void CFlash : : Init ( void )
{
// 10/19/01 kef -- maybe we want to do something different here for localized flashes, but right
//now I want to be sure that whatever RGB changes occur to a non-localized flash will also occur
//to a localized flash (so I'll have the same initial RGBA values for both...I need them sync'd for an effect)
vec3_t dif ;
float mod = 1.0f , dis = 0.0f , maxRange = 900 ;
VectorSubtract ( mOrigin1 , theFxHelper . refdef - > vieworg , dif ) ;
dis = VectorNormalize ( dif ) ;
mod = DotProduct ( dif , theFxHelper . refdef - > viewaxis [ 0 ] ) ;
if ( dis > maxRange | | ( mod < 0.5f & & dis > 100 ) )
{
mod = 0.0f ;
}
else if ( mod < 0.5f & & dis < = 100 )
{
mod + = 1.1f ;
}
mod * = ( 1.0f - ( ( dis * dis ) / ( maxRange * maxRange ) ) ) ;
VectorScale ( mRGBStart , mod , mRGBStart ) ;
VectorScale ( mRGBEnd , mod , mRGBEnd ) ;
if ( mFlags & FX_LOCALIZED_FLASH )
{
FX_WorldToScreen ( mOrigin1 , & mScreenX , & mScreenY ) ;
// modify size of localized flash based on distance to effect (but not orientation)
if ( dis > 100 & & dis < maxRange )
{
mRadiusModifier = ( 1.0f - ( ( dis * dis ) / ( maxRange * maxRange ) ) ) ;
}
}
}
//----------------------------
void CFlash : : Draw ( void )
{
mRefEnt . reType = RT_SPRITE ;
if ( mFlags & FX_LOCALIZED_FLASH )
{
vec4_t color ;
color [ 0 ] = mRefEnt . shaderRGBA [ 0 ] / 255.0 ;
color [ 1 ] = mRefEnt . shaderRGBA [ 1 ] / 255.0 ;
color [ 2 ] = mRefEnt . shaderRGBA [ 2 ] / 255.0 ;
color [ 3 ] = mRefEnt . shaderRGBA [ 3 ] / 255.0 ;
// add this 2D effect to the proper list. it will get drawn after the cgi.RenderScene call
theFxScheduler . Add2DEffect ( mScreenX , mScreenY , mRefEnt . radius , mRefEnt . radius , color , mRefEnt . customShader ) ;
}
else
{
VectorCopy ( theFxHelper . refdef - > vieworg , mRefEnt . origin ) ;
VectorMA ( mRefEnt . origin , 12 , theFxHelper . refdef - > viewaxis [ 0 ] , mRefEnt . origin ) ;
mRefEnt . radius = 11.0f ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
}
drawnFx + + ;
}
void FX_AddPrimitive ( CEffect * * pEffect , int killTime ) ;
void FX_FeedTrail ( effectTrailArgStruct_t * a )
{
CTrail * fx = new CTrail ;
int i = 0 ;
while ( i < 4 )
{
VectorCopy ( a - > mVerts [ i ] . origin , fx - > mVerts [ i ] . origin ) ;
VectorCopy ( a - > mVerts [ i ] . rgb , fx - > mVerts [ i ] . rgb ) ;
VectorCopy ( a - > mVerts [ i ] . destrgb , fx - > mVerts [ i ] . destrgb ) ;
VectorCopy ( a - > mVerts [ i ] . curRGB , fx - > mVerts [ i ] . curRGB ) ;
fx - > mVerts [ i ] . alpha = a - > mVerts [ i ] . alpha ;
fx - > mVerts [ i ] . destAlpha = a - > mVerts [ i ] . destAlpha ;
fx - > mVerts [ i ] . curAlpha = a - > mVerts [ i ] . curAlpha ;
fx - > mVerts [ i ] . ST [ 0 ] = a - > mVerts [ i ] . ST [ 0 ] ;
fx - > mVerts [ i ] . ST [ 1 ] = a - > mVerts [ i ] . ST [ 1 ] ;
fx - > mVerts [ i ] . destST [ 0 ] = a - > mVerts [ i ] . destST [ 0 ] ;
fx - > mVerts [ i ] . destST [ 1 ] = a - > mVerts [ i ] . destST [ 1 ] ;
fx - > mVerts [ i ] . curST [ 0 ] = a - > mVerts [ i ] . curST [ 0 ] ;
fx - > mVerts [ i ] . curST [ 1 ] = a - > mVerts [ i ] . curST [ 1 ] ;
i + + ;
}
fx - > SetFlags ( a - > mSetFlags ) ;
fx - > mShader = a - > mShader ;
FX_AddPrimitive ( ( CEffect * * ) & fx , a - > mKillTime ) ;
}
// end