2013-04-04 14:52:42 +00:00
// this include must remain at the top of every CPP file
# include "common_headers.h"
# if !defined(FX_SCHEDULER_H_INC)
# include "FxScheduler.h"
# endif
# include "cg_media.h"
# pragma warning(disable: 4035)
static long myftol ( float f )
{
static int tmp ;
__asm fld f
__asm fistp tmp
__asm mov eax , tmp
}
# pragma warning(default: 4035)
extern int drawnFx ;
extern int mParticles ;
extern int mOParticles ;
extern int mLines ;
extern int mTails ;
// Helper function
//-------------------------
void ClampVec ( vec3_t dat , byte * res )
{
int r ;
// clamp all vec values, then multiply the normalized values by 255 to maximize the result
for ( int i = 0 ; i < 3 ; i + + )
{
r = myftol ( dat [ i ] * 255.0f ) ;
if ( r < 0 )
{
r = 0 ;
}
else if ( r > 255 )
{
r = 255 ;
}
res [ i ] = ( unsigned char ) r ;
}
}
void GetOrigin ( int clientID , vec3_t org )
{
if ( clientID > = 0 )
{
centity_t * cent = & cg_entities [ clientID ] ;
if ( cent & & cent - > gent & & cent - > gent - > client )
{
VectorCopy ( cent - > gent - > client - > renderInfo . muzzlePoint , org ) ;
}
}
}
void GetDir ( int clientID , vec3_t org )
{
if ( clientID > = 0 )
{
centity_t * cent = & cg_entities [ clientID ] ;
if ( cent & & cent - > gent & & cent - > gent - > client )
{
VectorCopy ( cent - > gent - > client - > renderInfo . muzzleDir , org ) ;
}
}
}
//--------------------------
//
// Base Effect Class
//
//--------------------------
//--------------------------
//
// Derived Particle Class
//
//--------------------------
void CParticle : : Die ( )
{
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 , crandom ( ) , crandom ( ) , crandom ( ) ) ;
VectorNormalize ( norm ) ;
theFxScheduler . PlayEffect ( mDeathFxID , mOrigin1 , norm ) ;
}
}
//----------------------------
bool CParticle : : Cull ( )
{
vec3_t dir ;
// Get the direction to the view
VectorSubtract ( mOrigin1 , cg . refdef . vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( cg . refdef . viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
float len = VectorLengthSquared ( dir ) ;
// Can't be too close
if ( len < 16 * 16 )
{
return true ;
}
return false ;
}
//----------------------------
void CParticle : : Draw ( )
{
if ( mFlags & FX_DEPTH_HACK )
{
// Not sure if first person needs to be set, but it can't hurt?
mRefEnt . renderfx | = RF_DEPTHHACK ;
}
// Add our refEntity to the scene
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
mParticles + + ;
}
//----------------------------
// Update
//----------------------------
bool CParticle : : Update ( )
{
// 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 ( mClientID < 0 | | mClientID > = ENTITYNUM_WORLD )
{
// we are somehow not bolted even though the flag is on?
return false ;
}
vec3_t dir , org ;
vec3_t realVel , realAccel ;
float time = ( theFxHelper . mTime - mTimeStart ) * 0.001f ;
// Get our current position and direction
GetOrigin ( mClientID , org ) ;
GetDir ( mClientID , dir ) ;
vec3_t ang , ax [ 3 ] ;
vectoangles ( dir , ang ) ;
AngleVectors ( ang , ax [ 0 ] , ax [ 1 ] , ax [ 2 ] ) ;
// VectorCopy( dir, ax[0] );
// CrossProduct( up, ax[0], ax[1] );
// VectorNormalize( ax[1] );
// CrossProduct( ax[0], ax[1], ax[2] );
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
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 ( ) )
{
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
UpdateRotation ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
// Update Origin
//----------------------------
bool CParticle : : UpdateOrigin ( )
{
vec3_t new_origin ;
// float ftime, time2;
UpdateVelocity ( ) ;
// Calc the time differences
// ftime = theFxHelper.mFrameTime * 0.001f;
//time2 = ftime * ftime * 0.5f;
// time2=0;
// Predict the new position
new_origin [ 0 ] = mOrigin1 [ 0 ] + theFxHelper . mFloatFrameTime * mVel [ 0 ] ; // + time2 * mVel[0];
new_origin [ 1 ] = mOrigin1 [ 1 ] + theFxHelper . mFloatFrameTime * mVel [ 1 ] ; // + time2 * mVel[1];
new_origin [ 2 ] = mOrigin1 [ 2 ] + theFxHelper . mFloatFrameTime * mVel [ 2 ] ; // + time2 * mVel[2];
// Only perform physics if this object is tagged to do so
if ( ( mFlags & FX_APPLY_PHYSICS ) )
{
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
2013-04-04 18:01:17 +00:00
solid = ! ! ( CG_PointContents ( new_origin , ENTITYNUM_WORLD ) & ( MASK_SHOT | CONTENTS_WATER ) ) ;
2013-04-04 14:52:42 +00:00
}
if ( solid )
{
trace_t trace ;
float dot ;
if ( mFlags & FX_USE_BBOX )
{
2013-04-04 18:01:17 +00:00
theFxHelper . Trace ( & trace , mOrigin1 , mMin , mMax , new_origin , - 1 , ( MASK_SHOT | CONTENTS_WATER ) ) ;
2013-04-04 14:52:42 +00:00
}
else
{
2013-04-04 18:01:17 +00:00
theFxHelper . Trace ( & trace , mOrigin1 , NULL , NULL , new_origin , - 1 , ( MASK_SHOT | CONTENTS_WATER ) ) ;
2013-04-04 14:52:42 +00:00
}
// Hit something
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 ) ;
}
if ( mFlags & FX_KILL_ON_IMPACT )
{
// time to die
return false ;
}
VectorMA ( mVel , theFxHelper . mFloatFrameTime * trace . fraction , mAccel , mVel ) ;
dot = DotProduct ( mVel , trace . plane . normal ) ;
VectorMA ( mVel , - 2 * dot , trace . plane . normal , mVel ) ;
VectorScale ( mVel , mElasticity , mVel ) ;
// 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 & & mVel [ 2 ] < 4 )
{
VectorClear ( mVel ) ;
VectorClear ( mAccel ) ;
mFlags & = ~ ( FX_APPLY_PHYSICS | FX_IMPACT_RUNS_FX ) ;
}
// Set the origin to the exact impact point
VectorCopy ( trace . endpos , mOrigin1 ) ;
return true ;
}
}
}
// No physics were done to this object, move it
VectorCopy ( new_origin , mOrigin1 ) ;
return true ;
}
//----------------------------
// Update Size
//----------------------------
void CParticle : : UpdateSize ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
mRefEnt . radius = ( mSizeStart * perc1 ) + ( mSizeEnd * ( 1.0f - perc1 ) ) ;
}
//----------------------------
// Update RGB
//----------------------------
void CParticle : : UpdateRGB ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
// Now get the correct color
VectorScale ( mRGBStart , perc1 , res ) ;
VectorMA ( res , ( 1.0f - perc1 ) , mRGBEnd , mRefEnt . angles ) ; // angles is a temp storage, will get clamped to a byte in the UpdateAlpha section
}
//----------------------------
// Update Alpha
//----------------------------
void CParticle : : UpdateAlpha ( )
{
// 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 * ( float ) cos ( ( 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
if ( perc1 < 0.0f )
{
perc1 = 0.0f ;
}
else if ( perc1 > 1.0f )
{
perc1 = 1.0f ;
}
// 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 = random ( ) * perc1 ;
}
if ( mFlags & FX_USE_ALPHA )
{
// should use this when using art that has an alpha channel
ClampVec ( mRefEnt . angles , ( byte * ) ( & mRefEnt . shaderRGBA ) ) ;
mRefEnt . shaderRGBA [ 3 ] = ( byte ) ( perc1 * 0xff ) ;
}
else
{
// Modulate the rgb fields by the alpha value to do the fade, works fine for additive blending
VectorScale ( mRefEnt . angles , perc1 , mRefEnt . angles ) ;
ClampVec ( mRefEnt . angles , ( byte * ) ( & mRefEnt . shaderRGBA ) ) ;
}
}
//--------------------------------
//
// Derived Oriented Particle Class
//
//--------------------------------
//----------------------------
bool COrientedParticle : : Cull ( )
{
vec3_t dir ;
// Get the direction to the view
VectorSubtract ( mOrigin1 , cg . refdef . vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( cg . refdef . viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
float len = VectorLengthSquared ( dir ) ;
// Can't be too close
if ( len < 24 * 24 )
{
return true ;
}
return false ;
}
//----------------------------
void COrientedParticle : : Draw ( )
{
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 ) ;
VectorCopy ( mNormal , mRefEnt . axis [ 0 ] ) ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
mOParticles + + ;
}
//----------------------------
// Update
//----------------------------
bool COrientedParticle : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
if ( ! Cull ( ) )
{
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
UpdateRotation ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
//
// Derived Line Class
//
//----------------------------
//----------------------------
void CLine : : Draw ( )
{
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 + + ;
mLines + + ;
}
//----------------------------
bool CLine : : Update ( )
{
// 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 ( mClientID < 0 | | mClientID > = ENTITYNUM_WORLD )
{
// we are somehow not bolted even though the flag is on?
return false ;
}
vec3_t dir , end ;
trace_t trace ;
// Get our current position and direction
GetOrigin ( mClientID , mOrigin1 ) ;
GetDir ( mClientID , dir ) ;
if ( mFlags & FX_APPLY_PHYSICS )
{
VectorMA ( mOrigin1 , 2048 , dir , end ) ;
theFxHelper . Trace ( & trace , mOrigin1 , NULL , NULL , end , mClientID , MASK_SHOT ) ;
VectorCopy ( trace . endpos , mOrigin2 ) ;
if ( mImpactFxID > 0 )
{
theFxScheduler . PlayEffect ( mImpactFxID , trace . endpos , trace . plane . normal ) ;
}
}
else
{
VectorMA ( mOrigin1 , mOrgOffset [ 0 ] , dir , mOrigin2 ) ;
}
}
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
//
// Derived Electricity Class
//
//----------------------------
void CElectricity : : Initialize ( )
{
mRefEnt . frame = random ( ) * 1265536 ;
mRefEnt . endTime = cg . time + ( mTimeEnd - mTimeStart ) ;
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 ( )
{
VectorCopy ( mOrigin1 , mRefEnt . origin ) ;
VectorCopy ( mOrigin2 , mRefEnt . oldorigin ) ;
mRefEnt . angles [ 0 ] = mChaos ;
mRefEnt . angles [ 1 ] = mTimeEnd - mTimeStart ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
mLines + + ; // NOT REALLY A LINE!
}
//----------------------------
bool CElectricity : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
//
// Derived Tail Class
//
//----------------------------
bool CTail : : Cull ( )
{
vec3_t dir ;
// Get the direction to the view
VectorSubtract ( mOrigin1 , cg . refdef . vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( cg . refdef . viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
return false ;
}
//----------------------------
void CTail : : Draw ( )
{
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 + + ;
mTails + + ;
}
//----------------------------
bool CTail : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
if ( ! fx_freeze . integer )
{
VectorCopy ( mOrigin1 , mOldOrigin ) ;
}
if ( mFlags & FX_RELATIVE )
{
if ( mClientID < 0 | | mClientID > = ENTITYNUM_WORLD )
{
// the thing we are bolted to is no longer valid, so we may as well just die.
return false ;
}
vec3_t dir , org ;
// vec3_t right, up;
vec3_t realVel , realAccel ;
// Get our current position and direction
GetOrigin ( mClientID , org ) ;
GetDir ( mClientID , dir ) ;
vec3_t ang , ax [ 3 ] ;
vectoangles ( dir , ang ) ;
AngleVectors ( ang , ax [ 0 ] , ax [ 1 ] , ax [ 2 ] ) ;
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 ) ;
// 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 , ( theFxHelper . mTime - mTimeStart ) * 0.001f , realAccel , realVel ) ;
// Now move us to where we should be at the given time
VectorMA ( org , ( theFxHelper . mTime - mTimeStart ) * 0.001f , realVel , mOrigin1 ) ;
// Just calc an old point some time in the past, doesn't really matter when
VectorMA ( org , ( ( theFxHelper . mTime - mTimeStart ) - 3 ) * 0.001f , realVel , mOldOrigin ) ;
}
else if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
if ( ! Cull ( ) )
{
UpdateSize ( ) ;
UpdateLength ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
CalcNewEndpoint ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
void CTail : : UpdateLength ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
mLength = ( mLengthStart * perc1 ) + ( mLengthEnd * ( 1.0f - perc1 ) ) ;
}
//----------------------------
void CTail : : CalcNewEndpoint ( )
{
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
//
//----------------------------
void CCylinder : : Draw ( )
{
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 ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
mRefEnt . backlerp = ( mSize2Start * perc1 ) + ( mSize2End * ( 1.0f - perc1 ) ) ;
}
//----------------------------
bool CCylinder : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
UpdateSize ( ) ;
UpdateSize2 ( ) ;
UpdateLength ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
//
// Derived Emitter Class
//
//----------------------------
//----------------------------
// Draw
//----------------------------
void CEmitter : : Draw ( )
{
// 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 ) ;
// ensure that we are sized
for ( int i = 0 ; i < 3 ; i + + )
{
VectorScale ( mRefEnt . axis [ i ] , mRefEnt . radius , mRefEnt . axis [ i ] ) ;
}
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 i , t , dif ;
# define TRAIL_RATE 8 // we "think" at about a 60hz rate
// Pick a target step distance and square it
step = mDensity + crandom ( ) * 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
for ( i = 0 ; i < 3 ; i + + )
{
org [ i ] = mOldOrigin [ i ] + ftime * v [ i ] + time2 * v [ i ] ;
}
// Only perform physics if this object is tagged to do so
if ( ( mFlags & FX_APPLY_PHYSICS ) )
{
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
solid = ! ! ( CG_PointContents ( org , ENTITYNUM_WORLD ) & MASK_SHOT ) ;
}
if ( solid )
{
trace_t trace ;
if ( mFlags & FX_USE_BBOX )
{
theFxHelper . Trace ( & trace , mOldOrigin , mMin , mMax , org , - 1 , MASK_SHOT ) ;
}
else
{
theFxHelper . Trace ( & trace , mOldOrigin , NULL , NULL , org , - 1 , MASK_SHOT ) ;
}
// Hit something
2013-04-04 18:01:17 +00:00
if ( trace . fraction < 1.0f | | trace . startsolid | | trace . allsolid )
2013-04-04 14:52:42 +00:00
{
return ;
}
}
}
// Is it time to draw an effect?
if ( DistanceSquared ( org , mOldOrigin ) > = step )
{
// Pick a new target step distance and square it
step = mDensity + crandom ( ) * 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 ( )
{
// 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 ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return 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 ) ;
}
UpdateAngles ( ) ;
UpdateSize ( ) ;
// UpdateRGB(); // had wanted to do something slick whereby an emitted effect could somehow inherit these
// UpdateAlpha(); // values, but it's not a priority right now.
Draw ( ) ;
return true ;
}
//----------------------------
void CEmitter : : UpdateAngles ( )
{
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
//
//--------------------------
//----------------------------
// Update
//----------------------------
bool CLight : : Update ( )
{
// Game pausing can cause dumb time things to happen, so kill the effect in this instance
if ( mTimeStart > theFxHelper . mTime )
{
return false ;
}
UpdateSize ( ) ;
UpdateRGB ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
// Update Size
//----------------------------
void CLight : : UpdateSize ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
mRefEnt . radius = ( mSizeStart * perc1 ) + ( mSizeEnd * ( 1.0f - perc1 ) ) ;
}
//----------------------------
// Update RGB
//----------------------------
void CLight : : UpdateRGB ( )
{
// 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 * ( float ) cos ( ( 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 = random ( ) * perc1 ;
}
// Now get the correct color
VectorScale ( mRGBStart , perc1 , res ) ;
mRefEnt . lightingOrigin [ 0 ] = res [ 0 ] + ( 1.0f - perc1 ) * mRGBEnd [ 0 ] ;
mRefEnt . lightingOrigin [ 1 ] = res [ 1 ] + ( 1.0f - perc1 ) * mRGBEnd [ 1 ] ;
mRefEnt . lightingOrigin [ 2 ] = res [ 2 ] + ( 1.0f - perc1 ) * mRGBEnd [ 2 ] ;
}
//--------------------------
//
// 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 ( )
{
vec3_t dir ;
// Get the direction to the view
VectorSubtract ( mOrigin1 , cg . refdef . vieworg , dir ) ;
// Check if it's behind the viewer
if ( ( DotProduct ( cg . refdef . viewaxis [ 0 ] , dir ) ) < 0 )
{
return true ;
}
float len = VectorLengthSquared ( dir ) ;
// Can't be too close
if ( len < 24 * 24 )
{
return true ;
}
return false ;
}
//----------------------------
void CPoly : : Draw ( )
{
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
verts [ i ] . modulate [ 0 ] = mRefEnt . shaderRGBA [ 0 ] ;
verts [ i ] . modulate [ 1 ] = mRefEnt . shaderRGBA [ 1 ] ;
verts [ i ] . modulate [ 2 ] = mRefEnt . shaderRGBA [ 2 ] ;
verts [ i ] . modulate [ 3 ] = mRefEnt . shaderRGBA [ 3 ] ;
// Copy the ST coords
Vector2Copy ( mST [ i ] , verts [ i ] . st ) ;
}
// Add this poly
theFxHelper . AddPolyToScene ( mRefEnt . customShader , mCount , verts ) ;
drawnFx + + ;
}
//----------------------------
void CPoly : : CalcRotateMatrix ( )
{
float cosX , cosZ ;
float sinX , sinZ ;
float rad ;
// rotate around Z
rad = DEG2RAD ( mRotDelta [ YAW ] * theFxHelper . mFrameTime * 0.01f ) ;
cosZ = cos ( rad ) ;
sinZ = sin ( rad ) ;
// rotate around X
rad = DEG2RAD ( mRotDelta [ PITCH ] * theFxHelper . mFrameTime * 0.01f ) ;
cosX = cos ( rad ) ;
sinX = sin ( 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 ( )
{
vec3_t temp [ MAX_CPOLY_VERTS ] ;
float dif = fabs ( mLastFrameTime - theFxHelper . mFrameTime ) ;
// Very generous check with frameTimes
if ( dif > 0.5f * 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 ( )
{
vec3_t mOldOrigin ;
// 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 )
{
VectorCopy ( mOrigin1 , mOldOrigin ) ;
if ( ( mTimeStart < theFxHelper . mTime ) & & UpdateOrigin ( ) = = false )
{
// we are marked for death
return false ;
}
}
if ( ! Cull ( ) )
{
// only rotate when our start timestamp has expired
if ( theFxHelper . mTime > mTimeStamp )
{
// Only rotate whilst moving
if ( ! VectorCompare ( mOldOrigin , mOrigin1 ) )
{
Rotate ( ) ;
}
}
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
}
return true ;
}
//----------------------------
void CPoly : : PolyInit ( )
{
if ( mCount < 3 )
{
return ;
}
int i ;
vec3_t org = { 0 , 0 , 0 } ;
// 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 : : Update ( void )
{
float ftime , time2 ;
ftime = cg . frametime * 0.001f ;
time2 = ftime * ftime * 0.5f ;
for ( int i = 0 ; i < 3 ; i + + )
{
mControl1 [ i ] = mControl1 [ i ] + ftime * mControl1Vel [ i ] + time2 * mControl1Vel [ i ] ;
mControl2 [ i ] = mControl2 [ i ] + ftime * mControl2Vel [ i ] + time2 * mControl2Vel [ i ] ;
}
UpdateSize ( ) ;
UpdateRGB ( ) ;
UpdateAlpha ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
inline void CBezier : : DrawSegment ( vec3_t start , vec3_t end , float texcoord1 , float texcoord2 )
{
vec3_t lineDir , cross , viewDir ;
static vec3_t lastEnd [ 2 ] ;
polyVert_t verts [ 4 ] ;
float scale ;
VectorSubtract ( end , start , lineDir ) ;
VectorSubtract ( end , cg . refdef . vieworg , viewDir ) ;
CrossProduct ( lineDir , viewDir , cross ) ;
VectorNormalize ( cross ) ;
scale = mRefEnt . radius * 0.5f ;
//Construct the oriented quad
if ( mInit )
{
VectorCopy ( lastEnd [ 0 ] , verts [ 0 ] . xyz ) ;
VectorCopy ( lastEnd [ 1 ] , verts [ 1 ] . xyz ) ;
}
else
{
VectorMA ( start , - scale , cross , verts [ 0 ] . xyz ) ;
VectorMA ( start , scale , 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 )
{
verts [ 0 ] . modulate [ 0 ] = 0 ;
verts [ 0 ] . modulate [ 1 ] = 0 ;
verts [ 0 ] . modulate [ 2 ] = 0 ;
verts [ 0 ] . modulate [ 3 ] = 0 ;
verts [ 1 ] . modulate [ 0 ] = 0 ;
verts [ 1 ] . modulate [ 1 ] = 0 ;
verts [ 1 ] . modulate [ 2 ] = 0 ;
verts [ 1 ] . modulate [ 3 ] = 0 ;
}
VectorMA ( end , scale , 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 , - scale , 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 ] ;
cgi_R_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 ;
VectorCopy ( mOrigin1 , old_pos ) ;
mInit = false ; //Signify a new batch for vert gluing
// Calculate the texture coords so the texture can stretch along the whole bezier
// if ( mFlags & FXF_WRAP )
// {
// tex = m_stScale / 1.0f;
// }
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 ] ;
}
// if ( m_flags & FXF_WRAP )
// {
tc2 = mu * tex ;
// }
// else
// {
// // Texture will get mapped onto each segement
// tc1 = 0.0f;
// tc2 = 1.0f;
// }
//Draw it
DrawSegment ( old_pos , pos , tc1 , tc2 ) ;
VectorCopy ( pos , old_pos ) ;
tc1 = tc2 ;
}
drawnFx + + ;
mLines + + ; // NOT REALLY A LINE
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - -
CFlash
Full screen flash
- - - - - - - - - - - - - - - - - - - - - - - - -
*/
//----------------------------
bool CFlash : : Update ( void )
{
UpdateRGB ( ) ;
Draw ( ) ;
return true ;
}
//----------------------------
void CFlash : : Init ( void )
{
vec3_t dif ;
float mod = 1.0f , dis ;
VectorSubtract ( mOrigin1 , cg . refdef . vieworg , dif ) ;
dis = VectorNormalize ( dif ) ;
mod = DotProduct ( dif , cg . refdef . viewaxis [ 0 ] ) ;
if ( dis > 600 | | ( mod < 0.5f & & dis > 100 ) )
{
mod = 0.0f ;
}
else if ( mod < 0.5f & & dis < = 100 )
{
mod + = 1.1f ;
}
mod * = ( 1.0f - ( ( dis * dis ) / ( 600.0f * 600.0f ) ) ) ;
VectorScale ( mRGBStart , mod , mRGBStart ) ;
VectorScale ( mRGBEnd , mod , mRGBEnd ) ;
}
//----------------------------
void CFlash : : Draw ( void )
{
mRefEnt . reType = RT_SPRITE ;
for ( int i = 0 ; i < 3 ; i + + )
{
if ( mRefEnt . lightingOrigin [ i ] > 1.0f )
{
mRefEnt . lightingOrigin [ i ] = 1.0f ;
}
else if ( mRefEnt . lightingOrigin [ i ] < 0.0f )
{
mRefEnt . lightingOrigin [ i ] = 0.0f ;
}
}
mRefEnt . shaderRGBA [ 0 ] = mRefEnt . lightingOrigin [ 0 ] * 255 ;
mRefEnt . shaderRGBA [ 1 ] = mRefEnt . lightingOrigin [ 1 ] * 255 ;
mRefEnt . shaderRGBA [ 2 ] = mRefEnt . lightingOrigin [ 2 ] * 255 ;
mRefEnt . shaderRGBA [ 3 ] = 255 ;
VectorCopy ( cg . refdef . vieworg , mRefEnt . origin ) ;
VectorMA ( mRefEnt . origin , 8 , cg . refdef . viewaxis [ 0 ] , mRefEnt . origin ) ;
mRefEnt . radius = 12.0f ;
theFxHelper . AddFxToScene ( & mRefEnt ) ;
drawnFx + + ;
}