2073 lines
43 KiB
C++
2073 lines
43 KiB
C++
//
|
|
// Client Effects Primitive Class
|
|
|
|
// jweier
|
|
|
|
#include "cg_local.h"
|
|
#include "FX_Public.h"
|
|
|
|
/*
|
|
-------------------------
|
|
FXPrimitive
|
|
|
|
Base class for all primitives
|
|
-------------------------
|
|
*/
|
|
|
|
FXPrimitive::FXPrimitive( void )
|
|
{
|
|
VectorClear( m_origin );
|
|
VectorClear( m_velocity );
|
|
VectorClear( m_acceleration );
|
|
m_flags = 0;
|
|
}
|
|
|
|
FXPrimitive::~FXPrimitive( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXPrimitive::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
float len;
|
|
|
|
//Get the direction to the view
|
|
VectorSubtract( m_origin, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's behind the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) < 0 )
|
|
return true;
|
|
|
|
len = VectorLengthSquared( dir );
|
|
|
|
//Can't be too close
|
|
if ( len < 16 * 16 )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Movestate utility functions
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateOrigin
|
|
-------------------------
|
|
*/
|
|
|
|
void FXPrimitive::UpdateOrigin( void )
|
|
{
|
|
vec3_t new_origin;//, clear = { 0, 0, 0 };
|
|
float ftime, time2;
|
|
int i;
|
|
|
|
//If the velocity is dead, kill the upward acceleration (Huh? I don't recall why this is here...)
|
|
// if ( VectorCompare( m_velocity, clear ) )
|
|
// m_acceleration[2] = 0;
|
|
|
|
//Moved
|
|
UpdateVelocity();
|
|
|
|
//Calc the time differences
|
|
ftime = cg.frametime * 0.001f;
|
|
time2 = ftime * ftime * 0.5f;
|
|
|
|
//Predict the new position
|
|
for ( i = 0 ; i < 3 ; i++ )
|
|
new_origin[i] = m_origin[i] + ftime * m_velocity[i] + time2 * m_velocity[i];
|
|
|
|
//Only perform physics if this object is tagged to do so
|
|
if ( ( m_flags & FXF_BOUNCE ) )
|
|
{
|
|
trace_t trace;
|
|
float dot;
|
|
|
|
CG_Trace( &trace, m_origin, NULL, NULL, new_origin, -1, CONTENTS_SOLID );
|
|
|
|
//Hit something
|
|
if ( trace.fraction < 1.0f && !trace.startsolid && !trace.allsolid )
|
|
{
|
|
//Check for a bounce flag
|
|
if ( m_flags & FXF_BOUNCE )
|
|
{
|
|
VectorMA( m_velocity, ftime*trace.fraction, m_acceleration, m_velocity );
|
|
dot = DotProduct( m_velocity, trace.plane.normal );
|
|
VectorMA( m_velocity, -2*dot, trace.plane.normal, m_velocity );
|
|
|
|
VectorScale( m_velocity, m_elasticity, m_velocity );
|
|
}
|
|
|
|
//If the velocity is too low, terminate it
|
|
if ( trace.plane.normal[2] > 0 && m_velocity[2] < 40 )
|
|
VectorClear( m_velocity );
|
|
|
|
//Done
|
|
return;
|
|
}
|
|
}
|
|
|
|
//No physics were done to this object, move it
|
|
VectorCopy( new_origin, m_origin );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXPrimitive::Draw( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateVelocity
|
|
-------------------------
|
|
*/
|
|
|
|
void FXPrimitive::UpdateVelocity( void )
|
|
{
|
|
VectorMA( m_velocity, cg.frametime * 0.001f, m_acceleration, m_velocity );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateScale
|
|
-------------------------
|
|
*/
|
|
|
|
void FXPrimitive::UpdateScale( void )
|
|
{
|
|
m_scale += md_scale * cg.frametime * 0.001f;
|
|
|
|
if (m_scale < 0.0f)
|
|
m_scale = 0.0f;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateAlpha
|
|
-------------------------
|
|
*/
|
|
|
|
#define FREQ_CONVERSION 0.00628f // ( 2 * pi ) / 1000 ms
|
|
#define FADE_PERCENT 0.75f
|
|
|
|
void FXPrimitive::UpdateAlpha( void )
|
|
{
|
|
float perc;
|
|
|
|
// Get percentage of completeness
|
|
perc = (float)(cg.time - m_start_time) / (float)(m_end_time - m_start_time);
|
|
|
|
if ( ( m_flags & FXF_NON_LINEAR_FADE ) )
|
|
{
|
|
if ( perc > FADE_PERCENT )
|
|
{
|
|
// Kill this flag, then set the fade to start now...this will cause an RGB to RGB fade to act weird
|
|
// because the start time is being changed...so, just don't do it!
|
|
m_flags ^= FXF_NON_LINEAR_FADE;
|
|
m_start_time = cg.time;
|
|
}
|
|
|
|
// Fade shouldn't begin yet
|
|
perc = 0;
|
|
}
|
|
|
|
m_alpha = m_startalpha * (1.0 - perc) + m_endalpha * perc;
|
|
|
|
if ( m_flags & FXF_PULSE_ALPHA )
|
|
// Use half of alpha as amplitude so it will end smoothly
|
|
m_alpha += ( sin( ( cg.time - m_start_time ) * FREQ_CONVERSION * m_alphafreq ) * m_alpha * 0.5 );
|
|
|
|
if (m_alpha < 0.0f)
|
|
m_alpha = 0.0f;
|
|
|
|
if (m_alpha > 1.0f)
|
|
m_alpha = 1.0f;
|
|
|
|
if ( m_flags & FXF_ALPHA_NOISE )
|
|
m_alpha = random() * m_alpha;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateRGB
|
|
-------------------------
|
|
*/
|
|
|
|
void FXPrimitive::UpdateRGB( void )
|
|
{
|
|
float perc;
|
|
|
|
// Get percentage of completeness
|
|
perc = (float)(cg.time - m_start_time) / (float)(m_end_time - m_start_time);
|
|
|
|
float invPerc = 1.0f - perc;
|
|
|
|
for (int i=0; i < 3; i++)
|
|
{
|
|
m_RGB[i] = ( m_startRGB[i] * invPerc + m_endRGB[i] * perc );
|
|
|
|
// Has been explicitely flagged to use the alpha channel
|
|
if ( !(m_flags & FXF_USE_ALPHA_CHAN) )
|
|
{
|
|
m_RGB[i] *= m_alpha;
|
|
}
|
|
|
|
if (m_RGB[i] < 0.0f)
|
|
m_RGB[i] = 0.0f;
|
|
|
|
if (m_RGB[i] > 1.0f)
|
|
m_RGB[i] = 1.0f;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXPrimitive::Update( void )
|
|
{
|
|
//Move the object
|
|
UpdateOrigin();
|
|
|
|
UpdateScale();
|
|
UpdateAlpha();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXQuad
|
|
|
|
Oriented quad with texture
|
|
-------------------------
|
|
*/
|
|
|
|
FXQuad::FXQuad( void )
|
|
{
|
|
}
|
|
|
|
FXQuad::~FXQuad( void )
|
|
{
|
|
}
|
|
|
|
const int NUM_QUADVERTS = 4;
|
|
|
|
const vec3_t quad_template[] =
|
|
{
|
|
{ -1.0f, -1.0f, 0.0f },
|
|
{ -1.0f, 1.0f, 0.0f },
|
|
{ 1.0f, 1.0f, 0.0f },
|
|
{ 1.0f, -1.0f, 0.0f }
|
|
};
|
|
|
|
const float quad_st_template[][2] =
|
|
{
|
|
{ 0.0f, 0.0f },
|
|
{ 0.0f, 1.0f },
|
|
{ 1.0f, 1.0f },
|
|
{ 1.0f, 0.0f }
|
|
};
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateRoll
|
|
-------------------------
|
|
*/
|
|
|
|
void FXQuad::UpdateRoll( void )
|
|
{
|
|
m_roll += md_roll * cg.frametime * 0.001f;
|
|
|
|
if (m_roll > 360)
|
|
m_roll = m_roll - 360;
|
|
|
|
if (m_roll < 0)
|
|
m_roll = m_roll + 360;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXQuad::Update( void )
|
|
{
|
|
UpdateRoll();
|
|
UpdateScale();
|
|
UpdateAlpha();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXQuad::Draw( void )
|
|
{
|
|
polyVert_t verts[NUM_QUADVERTS];
|
|
vec3_t vr, vu;
|
|
vec3_t axis[3];
|
|
float scale;
|
|
int i;
|
|
|
|
scale = m_scale * 0.5f;
|
|
|
|
MakeNormalVectors( m_normal, vr, vu );
|
|
VectorCopy( m_normal, axis[0] );
|
|
VectorCopy( vr, axis[1] );
|
|
VectorCopy( vu, axis[2] );
|
|
|
|
RotateAroundDirection( axis, m_roll );
|
|
|
|
//Construct the quad
|
|
for ( i = 0; i < NUM_QUADVERTS; i++ )
|
|
{
|
|
VectorMA( m_origin, quad_template[i][0] * ( scale ), axis[1], verts[i].xyz );
|
|
VectorMA( verts[i].xyz, quad_template[i][1] * ( scale ), axis[2], verts[i].xyz );
|
|
|
|
verts[i].modulate[0] = m_RGB[0] * 255;
|
|
verts[i].modulate[1] = m_RGB[1] * 255;
|
|
verts[i].modulate[2] = m_RGB[2] * 255;
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
verts[i].modulate[3] = (byte)(m_alpha * 255);
|
|
else
|
|
verts[i].modulate[3] = 255;
|
|
|
|
verts[i].st[0] = quad_st_template[i][0];
|
|
verts[i].st[1] = quad_st_template[i][1];
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, NUM_QUADVERTS, verts );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXSprite
|
|
|
|
Non-oriented sprite with texture
|
|
-------------------------
|
|
*/
|
|
|
|
FXSprite::FXSprite( void )
|
|
{
|
|
}
|
|
|
|
FXSprite::~FXSprite( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXSprite::Cull( void )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Sprite vertex template
|
|
const vec3_t sprite_template[4] =
|
|
{
|
|
{ -1, -1, 0, }, //Top left
|
|
{ -1, 1, 0, }, //Bottom left
|
|
{ 1, 1, 0, }, //Bottom right
|
|
{ 1, -1, 0, }, //Top right
|
|
};
|
|
|
|
|
|
//Sprite UV template
|
|
const float sprite_texture_template[][2] =
|
|
{
|
|
{ 0.0f, 0.0f }, //Top left
|
|
{ 0.0f, 1.0f }, //Bottom left
|
|
{ 1.0f, 1.0f }, //Bottom right
|
|
{ 1.0f, 0.0f }, //Top right
|
|
};
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateRoll
|
|
-------------------------
|
|
*/
|
|
|
|
void FXSprite::UpdateRoll( void )
|
|
{
|
|
m_roll += md_roll * cg.frametime * 0.001f;
|
|
|
|
if (m_roll > 360)
|
|
m_roll = m_roll - 360;
|
|
|
|
if (m_roll < 0)
|
|
m_roll = m_roll + 360;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXSprite::Update( void )
|
|
{
|
|
if (m_start_time > cg.time)
|
|
{//i was created in the future, right after un-pausing
|
|
return false;
|
|
}
|
|
//Move the object
|
|
UpdateOrigin();
|
|
|
|
UpdateRoll();
|
|
UpdateScale();
|
|
UpdateAlpha();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXSprite::Draw( void )
|
|
{
|
|
polyVert_t verts[4];
|
|
vec3_t axis[3];
|
|
float scale;
|
|
int i;
|
|
|
|
scale = m_scale * 0.5f;
|
|
|
|
for ( i = 0; i < 3; i++ )
|
|
VectorCopy( cg.refdef.viewaxis[i], axis[i] );
|
|
|
|
//This is done to spare non-rolling sprites the odd angle snapping <?>
|
|
if ( m_roll )
|
|
RotateAroundDirection( axis, m_roll );
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
VectorMA( m_origin, sprite_template[i][0] * scale, axis[1], verts[i].xyz );
|
|
VectorMA( verts[i].xyz, sprite_template[i][1] * scale, axis[2], verts[i].xyz );
|
|
|
|
//Setup the UVs
|
|
verts[i].st[0] = -sprite_texture_template[i][0];
|
|
verts[i].st[1] = -sprite_texture_template[i][1];
|
|
|
|
//Setup the vertex modulation
|
|
verts[i].modulate[0] = m_RGB[0] * 255;
|
|
verts[i].modulate[1] = m_RGB[1] * 255;
|
|
verts[i].modulate[2] = m_RGB[2] * 255;
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
verts[i].modulate[3] = (byte)(m_alpha * 255);
|
|
else
|
|
verts[i].modulate[3] = 255;
|
|
}
|
|
|
|
//Add it into the renderer
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXElectricity
|
|
|
|
Generates a bolt of electricity
|
|
-------------------------
|
|
*/
|
|
|
|
FXElectricity::FXElectricity( void )
|
|
{
|
|
m_init = false;
|
|
}
|
|
|
|
FXElectricity::~FXElectricity( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXElectricity::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( m_origin, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false; //dont' cull
|
|
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false; //dont' cull
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXElectricity::Bolt( vec3_t start, vec3_t dir, float length, int num )
|
|
{
|
|
vec3_t ofs, curPos;
|
|
float stepSize;
|
|
|
|
stepSize = (float)( length / (float) MAX_BOLT_SEGMENTS );
|
|
|
|
VectorCopy( start, curPos );
|
|
|
|
for ( int i = 0; i < MAX_BOLT_SEGMENTS; i++ )
|
|
{
|
|
//Move along the bolt
|
|
ofs[PITCH] = dir[PITCH]+ (crandom() * ( m_deviation * 0.25 ) );
|
|
ofs[YAW] = dir[YAW] + (crandom() * ( m_deviation * 0.25 ) );
|
|
ofs[ROLL] = dir[ROLL] + (crandom() * ( m_deviation * 0.75 ) );
|
|
|
|
VectorMA( curPos, stepSize, ofs, curPos );
|
|
|
|
//Save the current position
|
|
VectorCopy( curPos, m_boltVerts[i] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Build
|
|
-------------------------
|
|
*/
|
|
|
|
void FXElectricity::Build( void )
|
|
{
|
|
vec3_t dir, ofs, curPos;
|
|
float length, stepSize;
|
|
|
|
VectorSubtract( m_origin2, m_origin, dir );
|
|
length = VectorNormalize( dir );
|
|
|
|
stepSize = (float)( length / (float) MAX_BOLT_SEGMENTS );
|
|
|
|
VectorCopy( m_origin, curPos );
|
|
|
|
for ( int i = 0; i < MAX_BOLT_SEGMENTS; i++ )
|
|
{
|
|
//Save the current position
|
|
VectorCopy( curPos, m_boltVerts[i] );
|
|
|
|
//Move along the bolt
|
|
ofs[PITCH] = dir[PITCH]+ (crandom() * m_deviation );
|
|
ofs[YAW] = dir[YAW] + (crandom() * m_deviation );
|
|
ofs[ROLL] = dir[ROLL] + (crandom() * ( m_deviation * 0.5 ) );
|
|
|
|
VectorMA( curPos, stepSize, ofs, curPos );
|
|
}
|
|
|
|
VectorCopy( m_origin2, m_boltVerts[MAX_BOLT_SEGMENTS - 1] );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
DrawSegment
|
|
-------------------------
|
|
*/
|
|
|
|
inline void FXElectricity::DrawSegment( vec3_t start, vec3_t end, float scale, float tcStart, float tcEnd )
|
|
{
|
|
vec3_t lineDir, cross, viewDir;
|
|
polyVert_t verts[4];
|
|
|
|
VectorSubtract( end, start, lineDir );
|
|
VectorSubtract( end, cg.refdef.vieworg, viewDir );
|
|
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale *= 0.5;
|
|
|
|
//Construct the oriented quad
|
|
|
|
if ( m_init )
|
|
VectorCopy( m_lastEnd[0], verts[0].xyz );
|
|
else
|
|
VectorMA( start, -scale, cross, verts[0].xyz );
|
|
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = tcStart;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_init )
|
|
VectorCopy( m_lastEnd[1], verts[1].xyz );
|
|
else
|
|
VectorMA( start, scale, cross, verts[1].xyz );
|
|
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = tcStart;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( end, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = tcEnd;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( end, -scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = tcEnd;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
|
|
VectorCopy( verts[2].xyz, m_lastEnd[1] );
|
|
VectorCopy( verts[3].xyz, m_lastEnd[0] );
|
|
|
|
m_init = true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXElectricity::Draw( void )
|
|
{
|
|
float scale, incr = 0, detail = 0, tcStart = 0 , tcEnd = m_stScale;
|
|
|
|
//Check for tapering
|
|
if ( m_flags & FXF_TAPER )
|
|
{
|
|
// This overrides the default of zero
|
|
incr = m_scale / MAX_BOLT_SEGMENTS;
|
|
}
|
|
|
|
scale = m_scale;
|
|
m_init = false;
|
|
|
|
// Set up to calculate the texture coords so the texture can be mapped across the length of the bolt
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
detail = m_stScale / MAX_BOLT_SEGMENTS;
|
|
}
|
|
|
|
//Do all segments
|
|
for ( int i = 0; i < MAX_BOLT_SEGMENTS - 1 ; i++ )
|
|
{
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
// This will override the defaults if necessary
|
|
tcStart = detail * i;
|
|
tcEnd = detail * (i+ 1);
|
|
}
|
|
|
|
scale -= incr;
|
|
|
|
DrawSegment( m_boltVerts[i], m_boltVerts[i+1], scale, tcStart, tcEnd );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXParticle
|
|
|
|
Crazy particle stuff
|
|
-------------------------
|
|
*/
|
|
FXParticle::FXParticle( void )
|
|
{
|
|
Think = NULL;
|
|
}
|
|
|
|
|
|
FXParticle::~FXParticle( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXParticle::Cull( void )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXParticle::Draw( void )
|
|
{
|
|
polyVert_t verts[4];
|
|
vec3_t axis[3];
|
|
float scale;
|
|
int i;
|
|
|
|
if ( m_flags & FXF_NODRAW )
|
|
return;
|
|
|
|
scale = m_scale * 0.5f;
|
|
|
|
for ( i = 0; i < 3; i++ )
|
|
VectorCopy( cg.refdef.viewaxis[i], axis[i] );
|
|
|
|
//This is done to spare non-rolling particles the odd angle snapping <?>
|
|
if (m_roll)
|
|
RotateAroundDirection( axis, m_roll );
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
VectorMA( m_origin, sprite_template[i][0] * scale, axis[1], verts[i].xyz );
|
|
VectorMA( verts[i].xyz, sprite_template[i][1] * scale, axis[2], verts[i].xyz );
|
|
|
|
//Setup the UVs
|
|
verts[i].st[0] = sprite_texture_template[i][0];
|
|
verts[i].st[1] = sprite_texture_template[i][1];
|
|
|
|
//Setup the vertex modulation
|
|
verts[i].modulate[0] = (byte)(m_RGB[0] * 255);
|
|
verts[i].modulate[1] = (byte)(m_RGB[1] * 255);
|
|
verts[i].modulate[2] = (byte)(m_RGB[2] * 255);
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
verts[i].modulate[3] = (byte)(m_alpha * 255);
|
|
else
|
|
verts[i].modulate[3] = 255;
|
|
}
|
|
|
|
//Add it into the renderer
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateRoll
|
|
-------------------------
|
|
*/
|
|
|
|
void FXParticle::UpdateRoll( void )
|
|
{
|
|
m_roll += md_roll * cg.frametime * 0.001f;
|
|
|
|
if (m_roll > 360)
|
|
m_roll = m_roll - 360;
|
|
|
|
if (m_roll < 0)
|
|
m_roll = m_roll + 360;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXParticle::Update( void )
|
|
{
|
|
// There should be a think function, otherwise what's the point of using a particle?
|
|
if ( Think )
|
|
{
|
|
// All particle attributes need to be updated in the think function since
|
|
// nothing is auto-updated. This is done to ensure the most flexibility.
|
|
return Think( this, m_cowner );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXTri
|
|
|
|
Triangle primitive
|
|
-------------------------
|
|
*/
|
|
|
|
FXTri::FXTri( void )
|
|
{
|
|
}
|
|
|
|
FXTri::~FXTri( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXTri::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
vec3_t mid;
|
|
|
|
//Find the midpoint of the triangle
|
|
for ( int i = 0; i < 3; i++ )
|
|
{
|
|
mid[ i ] = ( m_origin[ i ] + m_origin2[ i ] + m_origin3[ i ] ) * 0.333f;
|
|
}
|
|
VectorSubtract( mid, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's behind the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) < 0 )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXTri::Draw( void )
|
|
{
|
|
polyVert_t verts[3];
|
|
|
|
//Construct the tri
|
|
VectorCopy( m_origin, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.0f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorCopy( m_origin2, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorCopy( m_origin3, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = 1.0f;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 3, verts );
|
|
}
|
|
|
|
|
|
/*
|
|
-------------------------
|
|
FXLine
|
|
|
|
Oriented line
|
|
-------------------------
|
|
*/
|
|
|
|
FXLine::FXLine( void )
|
|
{
|
|
}
|
|
|
|
FXLine::~FXLine( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXLine::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( m_origin, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false; //dont' cull
|
|
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false;
|
|
|
|
return true; //all points behind
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXLine::Draw( void )
|
|
{
|
|
vec3_t lineDir, cross, viewDir, neworg;
|
|
polyVert_t verts[4];
|
|
float scale;
|
|
|
|
VectorSubtract( m_origin2, m_origin, lineDir );
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, viewDir );
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale = m_scale * 0.5;
|
|
|
|
//Construct the oriented quad
|
|
VectorMA( m_origin, -scale, cross, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.0f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin, scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, -scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = m_stScale;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
|
|
//Cap the lines
|
|
if ( m_flags & FXF_DRAWCAPS )
|
|
{
|
|
//Construct an oriented quad for the endcap
|
|
VectorMA( m_origin, scale, cross, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.02f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin, -scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.1f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorNormalize( lineDir );
|
|
VectorMA( m_origin, -scale * 2, lineDir, neworg );
|
|
VectorMA( neworg, -scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = 0.9f;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( neworg, scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = 0.9f;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_endcap_shader, 4, verts );
|
|
|
|
//Construct an oriented quad for the endcap
|
|
VectorMA( m_origin2, -scale, cross, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.1f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.05f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale * 2, lineDir, neworg );
|
|
VectorMA( neworg, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = 0.9f;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( neworg, -scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = 0.9f;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_endcap_shader, 4, verts );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateOrigin
|
|
-------------------------
|
|
*/
|
|
|
|
void FXLine::UpdateOrigin( void )
|
|
{
|
|
if ( m_flags & FXF_SHRINK )
|
|
{
|
|
vec3_t dir;
|
|
float perc, len;
|
|
|
|
VectorSubtract( m_work_org, m_origin, dir );
|
|
len = VectorNormalize( dir );
|
|
|
|
// Get percentage of completeness
|
|
perc = (float)(cg.time - m_start_time) / (float)(m_end_time - m_start_time);
|
|
|
|
VectorMA( m_origin, len * ( 1.0 - perc ), dir, m_origin2 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXLine
|
|
|
|
Oriented line
|
|
-------------------------
|
|
*/
|
|
|
|
FXLine2::FXLine2( void )
|
|
{
|
|
}
|
|
|
|
FXLine2::~FXLine2( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXLine2::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( m_origin, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false; //dont' cull
|
|
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false;
|
|
|
|
return true; //all points behind
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXLine2::Draw( void )
|
|
{
|
|
#if 0
|
|
vec3_t lineDir, cross, viewDir;
|
|
polyVert_t verts[4];
|
|
float scale, scale2;
|
|
|
|
VectorSubtract( m_origin2, m_origin, lineDir );
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, viewDir );
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale = m_scale * 0.5f;
|
|
scale2 = m_scale2 * 0.5f;
|
|
|
|
//Construct the oriented quad
|
|
VectorMA( m_origin, -scale, cross, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.0f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin, scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale2, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, -scale2, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = m_stScale;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
#else
|
|
vec3_t lineDir, cross, viewDir;
|
|
polyVert_t verts[4];
|
|
float scale, scale2;
|
|
|
|
VectorSubtract( m_origin2, m_origin, lineDir );
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, viewDir );
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale = m_scale * 0.5f;
|
|
scale2 = m_scale2 * 0.5f;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
//Construct the tapered, oriented quad, we have to use 3 tris to do this though
|
|
VectorCopy( m_origin, verts[0].xyz );
|
|
verts[0].st[0] = 0.5f;
|
|
verts[0].st[1] = 0.0f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, -scale2, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = m_stScale;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale2, cross, verts[2].xyz );
|
|
verts[2].st[0] = 0.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 3, verts );
|
|
|
|
VectorCopy( m_origin, verts[0].xyz );
|
|
verts[0].st[0] = 0.5f;
|
|
verts[0].st[1] = 0.0f;
|
|
|
|
VectorMA( m_origin2, -scale2, cross, verts[1].xyz );
|
|
verts[1].st[0] = 0.0f;
|
|
verts[1].st[1] = m_stScale;
|
|
|
|
VectorMA( m_origin, -scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 0.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 3, verts );
|
|
|
|
VectorCopy( m_origin, verts[0].xyz );
|
|
verts[0].st[0] = 0.5f;
|
|
verts[0].st[1] = 0.0f;
|
|
|
|
VectorMA( m_origin2, scale2, cross, verts[1].xyz );
|
|
verts[1].st[0] = 0.0f;
|
|
verts[1].st[1] = m_stScale;
|
|
|
|
VectorMA( m_origin, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 0.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 3, verts );
|
|
/*
|
|
VectorMA( m_origin, scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, scale2, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = m_stScale;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin2, -scale2, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = m_stScale;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
*/
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXSpawner
|
|
|
|
Effect spawner
|
|
-------------------------
|
|
*/
|
|
|
|
FXSpawner::FXSpawner( void )
|
|
{
|
|
VectorClear( m_acceleration );
|
|
m_owner = NULL;
|
|
}
|
|
|
|
FXSpawner::~FXSpawner( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXSpawner::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( m_origin, 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 );
|
|
//Check to see if we're outside the valid radius
|
|
if ( len > m_radius*m_radius )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXSpawner::Draw( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXSpawner::Update( void )
|
|
{
|
|
UpdateOrigin();
|
|
UpdateVelocity();
|
|
UpdateScale();
|
|
UpdateAlpha();
|
|
|
|
//FIXME: This is being double called...
|
|
if ( Cull() == false )
|
|
{
|
|
if ( m_nextThink < cg.time )
|
|
{
|
|
if (Think != NULL)
|
|
Think( m_origin, m_angles, m_velocity, m_startRGB );
|
|
|
|
m_nextThink = cg.time + ( ( m_delay + ( m_variance * crandom() )) );
|
|
|
|
if ( m_flags & FXF_SPAWN_ONCE )
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateOrigin
|
|
-------------------------
|
|
*/
|
|
|
|
void FXSpawner::UpdateOrigin( void )
|
|
{
|
|
//If attached to an owner, move with it
|
|
if ( m_owner )
|
|
{
|
|
VectorCopy( m_owner->refEntity.origin, m_origin );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXBezier
|
|
|
|
Bezier curve line
|
|
-------------------------
|
|
*/
|
|
|
|
FXBezier::FXBezier( void )
|
|
{
|
|
m_init = false;
|
|
}
|
|
|
|
FXBezier::~FXBezier( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXBezier::Cull( void )
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( m_origin, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false; //don't cull
|
|
|
|
VectorSubtract( m_origin2, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false;
|
|
|
|
VectorSubtract( m_control1, cg.refdef.vieworg, dir );
|
|
|
|
//Check if it's in front of the viewer
|
|
if ( (DotProduct( cg.refdef.viewaxis[0], dir )) >= 0 )
|
|
return false;
|
|
|
|
return true; //all points behind viewer
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXBezier::Update( void )
|
|
{
|
|
vec3_t new_origin;
|
|
float ftime, time2;
|
|
|
|
VectorMA( m_control1_velocity, cg.frametime * 0.001f, m_control1_acceleration, m_control1_velocity );
|
|
VectorMA( m_control2_velocity, cg.frametime * 0.001f, m_control2_acceleration, m_control2_velocity );
|
|
|
|
ftime = cg.frametime * 0.001f;
|
|
time2 = ftime * ftime * 0.5f;
|
|
|
|
for ( int i = 0 ; i < 3 ; i++ )
|
|
{
|
|
new_origin[i] = m_control1[i] + ftime * m_control1_velocity[i] + time2 * m_control1_velocity[i];
|
|
}
|
|
|
|
VectorCopy( new_origin, m_control1 );
|
|
|
|
for ( i = 0 ; i < 3 ; i++ )
|
|
{
|
|
new_origin[i] = m_control2[i] + ftime * m_control2_velocity[i] + time2 * m_control2_velocity[i];
|
|
}
|
|
|
|
VectorCopy( new_origin, m_control2 );
|
|
|
|
UpdateAlpha();
|
|
UpdateScale();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
DrawSegment
|
|
-------------------------
|
|
*/
|
|
|
|
inline void FXBezier::DrawSegment( vec3_t start, vec3_t end, float texcoord1, float texcoord2 )
|
|
{
|
|
vec3_t lineDir, cross, viewDir;
|
|
polyVert_t verts[4];
|
|
float scale;
|
|
|
|
VectorSubtract( end, start, lineDir );
|
|
VectorSubtract( end, cg.refdef.vieworg, viewDir );
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale = m_scale * 0.5;
|
|
|
|
//Construct the oriented quad
|
|
if ( m_init )
|
|
VectorCopy( m_lastEnd[0], verts[0].xyz );
|
|
else
|
|
VectorMA( start, -scale, cross, verts[0].xyz );
|
|
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = texcoord1;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_init )
|
|
VectorCopy( m_lastEnd[1], verts[1].xyz );
|
|
else
|
|
VectorMA( start, scale, cross, verts[1].xyz );
|
|
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = texcoord1;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( end, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = texcoord2;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( end, -scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = texcoord2;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
|
|
VectorCopy( verts[2].xyz, m_lastEnd[1] );
|
|
VectorCopy( verts[3].xyz, m_lastEnd[0] );
|
|
|
|
m_init = true;
|
|
}
|
|
|
|
const float BEZIER_RESOLUTION = 16.0f;
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXBezier::Draw( void )
|
|
{
|
|
vec3_t pos, old_pos;
|
|
double mu, mum1;
|
|
float incr = 1.0f / BEZIER_RESOLUTION, tex = 1.0, tc1, tc2;
|
|
int i;
|
|
|
|
VectorCopy( m_origin, old_pos );
|
|
|
|
m_init = false; //Signify a new batch for vert gluing
|
|
|
|
// Calculate the texture coords so the texture can stretch along the whole bezier
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
tex = m_stScale / 1.0f;
|
|
}
|
|
|
|
for ( mu = 0.0; mu <= 1.0; mu += incr )
|
|
{
|
|
//Four point curve
|
|
#if 1
|
|
double mum13, mu3, group1, group2;
|
|
|
|
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 * m_origin[i] + group1 * m_control1[i] + group2 * m_control2[i] + mu3 * m_origin2[i];
|
|
|
|
#else
|
|
|
|
//Three point curve
|
|
|
|
double mum12, mu2;
|
|
mu2 = mu * mu;
|
|
mum1 = 1 - mu;
|
|
mum12 = mum1 * mum1;
|
|
|
|
for (i=0;i<3;i++)
|
|
pos[i] = m_origin[i] * mum12 + 2 * m_control1[i] * mum1 * mu + m_origin2[i] * mu2;
|
|
|
|
#endif
|
|
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
tc1 = mu * tex;
|
|
tc2 = ( mu + incr ) * 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 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXTrail
|
|
|
|
Leaves a trail behind it
|
|
-------------------------
|
|
*/
|
|
|
|
FXTrail::FXTrail( void )
|
|
{
|
|
}
|
|
|
|
FXTrail::~FXTrail( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXTrail::Cull( void )
|
|
{
|
|
return FXPrimitive::Cull();
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXTrail::Draw( void )
|
|
{
|
|
vec3_t lineDir, cross, viewDir;
|
|
polyVert_t verts[4];
|
|
float scale;
|
|
|
|
VectorSubtract( m_oldorigin, m_origin, lineDir );
|
|
VectorSubtract( m_oldorigin, cg.refdef.vieworg, viewDir );
|
|
CrossProduct( lineDir, viewDir, cross );
|
|
VectorNormalize( cross );
|
|
|
|
scale = m_scale * 0.5;
|
|
|
|
//Construct the oriented quad
|
|
VectorMA( m_origin, -scale, cross, verts[0].xyz );
|
|
verts[0].st[0] = 0.0f;
|
|
verts[0].st[1] = 0.0f;
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_origin, scale, cross, verts[1].xyz );
|
|
verts[1].st[0] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_oldorigin, scale, cross, verts[2].xyz );
|
|
verts[2].st[0] = 1.0f;
|
|
verts[2].st[1] = 1.0f;
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorMA( m_oldorigin, -scale, cross, verts[3].xyz );
|
|
verts[3].st[0] = 0.0f;
|
|
verts[3].st[1] = 1.0f;
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateTailLength
|
|
-------------------------
|
|
*/
|
|
|
|
void FXTrail::UpdateTailLength( void )
|
|
{
|
|
m_length += md_length * cg.frametime * 0.001f;
|
|
|
|
if (m_length < 0.0f)
|
|
m_length = 1.0f;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateTailPoint
|
|
-------------------------
|
|
*/
|
|
|
|
void FXTrail::UpdateTailPoint( void )
|
|
{
|
|
vec3_t dir;
|
|
float len;
|
|
|
|
UpdateTailLength();
|
|
|
|
VectorSubtract( m_oldorigin, m_origin, dir );
|
|
len = VectorNormalize( dir );
|
|
|
|
VectorMA( m_origin, m_length, dir, m_oldorigin);
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXTrail::Update( void )
|
|
{
|
|
//Move the object
|
|
UpdateOrigin();
|
|
|
|
UpdateTailPoint();
|
|
|
|
UpdateScale();
|
|
UpdateAlpha();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
FXCylinder
|
|
|
|
Cylinder
|
|
-------------------------
|
|
*/
|
|
|
|
const int NUM_CYLINDER_SEGMENTS = 32;
|
|
|
|
FXCylinder::FXCylinder( void )
|
|
{
|
|
}
|
|
|
|
FXCylinder::~FXCylinder( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Cull
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXCylinder::Cull( void )
|
|
{
|
|
return FXPrimitive::Cull();
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Draw
|
|
-------------------------
|
|
*/
|
|
|
|
void FXCylinder::Draw( void )
|
|
{
|
|
polyVert_t lower_points[NUM_CYLINDER_SEGMENTS], upper_points[NUM_CYLINDER_SEGMENTS], verts[4];
|
|
vec3_t vr, vu, vu2, midpoint, origin2;
|
|
float detail, length;
|
|
int i;
|
|
int segments;
|
|
|
|
// allow for overriding the LOD mechanism, not recommended, but hey, flexibility is often cool...
|
|
if ( m_flags & FXF_NO_LOD )
|
|
{
|
|
segments = NUM_CYLINDER_SEGMENTS;
|
|
}
|
|
else
|
|
{
|
|
//Work out the detail level of this cylinder
|
|
VectorMA( m_origin, m_height * 0.5, m_normal, midpoint );
|
|
VectorSubtract( midpoint, cg.refdef.vieworg, midpoint );
|
|
length = VectorLengthSquared( midpoint );
|
|
|
|
detail = 1 - (length / (1024.0*1024.0) );
|
|
|
|
// FIXME: the bias doesn't really work all that great
|
|
//Cylinder bias is simply implemented as a multiplier
|
|
segments = NUM_CYLINDER_SEGMENTS * detail * m_bias;
|
|
|
|
// 3 is the absolute minimum, but the pop between 3, 4 and 5 is too noticeable
|
|
if ( segments < 7 )
|
|
{
|
|
segments = 7;
|
|
}
|
|
|
|
if ( segments > NUM_CYLINDER_SEGMENTS )
|
|
{
|
|
segments = NUM_CYLINDER_SEGMENTS;
|
|
}
|
|
}
|
|
|
|
//Get the direction vector
|
|
MakeNormalVectors( m_normal, vr, vu );
|
|
|
|
VectorScale( vu, m_scale2 * 0.5, vu2 );
|
|
VectorScale( vu, m_scale * 0.5, vu );
|
|
|
|
VectorMA( m_origin, m_height, m_normal, origin2 );
|
|
|
|
// Calculate the step around the cylinder
|
|
detail = 360.0 / (float)segments;
|
|
|
|
for ( i = 0; i < segments ; i++ )
|
|
{
|
|
//Upper ring
|
|
RotatePointAroundVector( upper_points[i].xyz, m_normal, vu, detail * i );
|
|
VectorAdd( upper_points[i].xyz, m_origin, upper_points[i].xyz );
|
|
|
|
//Lower ring
|
|
RotatePointAroundVector( lower_points[i].xyz, m_normal, vu2, detail * i );
|
|
VectorAdd( lower_points[i].xyz, origin2, lower_points[i].xyz );
|
|
}
|
|
|
|
// Calculate the texture coords so the texture can wrap around the whole cylinder
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
if ( m_flags & FXF_STRETCH )
|
|
detail = 1.0f / (float)segments;
|
|
else
|
|
detail = m_stScale / (float)segments;
|
|
}
|
|
|
|
for ( i = 0; i < segments ; i++ )
|
|
{
|
|
int nextSegment = ( i + 1 == segments ) ? 0 : i + 1;
|
|
|
|
if ( m_flags & FXF_WRAP )
|
|
{
|
|
verts[0].st[0] = detail * i;
|
|
verts[1].st[0] = detail * i;
|
|
verts[2].st[0] = detail * ( i + 1 );
|
|
verts[3].st[0] = detail * ( i + 1 );
|
|
}
|
|
else
|
|
{
|
|
verts[0].st[0] = 0.0f;
|
|
verts[1].st[0] = 0.0f;
|
|
verts[2].st[0] = m_stScale;
|
|
verts[3].st[0] = m_stScale;
|
|
}
|
|
|
|
if( m_flags & FXF_STRETCH )
|
|
{
|
|
verts[0].st[1] = m_stScale;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[2].st[1] = 0.0f;
|
|
verts[3].st[1] = m_stScale;
|
|
}
|
|
else
|
|
{
|
|
verts[0].st[1] = 1.0f;
|
|
verts[1].st[1] = 0.0f;
|
|
verts[2].st[1] = 0.0f;
|
|
verts[3].st[1] = 1.0f;
|
|
}
|
|
|
|
VectorCopy( upper_points[i].xyz, verts[0].xyz );
|
|
|
|
verts[0].modulate[0] = m_RGB[0] * 255;
|
|
verts[0].modulate[1] = m_RGB[1] * 255;
|
|
verts[0].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorCopy( lower_points[i].xyz, verts[1].xyz );
|
|
|
|
verts[1].modulate[0] = m_RGB[0] * 255;
|
|
verts[1].modulate[1] = m_RGB[1] * 255;
|
|
verts[1].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorCopy( lower_points[nextSegment].xyz, verts[2].xyz );
|
|
|
|
verts[2].modulate[0] = m_RGB[0] * 255;
|
|
verts[2].modulate[1] = m_RGB[1] * 255;
|
|
verts[2].modulate[2] = m_RGB[2] * 255;
|
|
|
|
VectorCopy( upper_points[nextSegment].xyz, verts[3].xyz );
|
|
|
|
verts[3].modulate[0] = m_RGB[0] * 255;
|
|
verts[3].modulate[1] = m_RGB[1] * 255;
|
|
verts[3].modulate[2] = m_RGB[2] * 255;
|
|
|
|
if ( m_flags & FXF_USE_ALPHA_CHAN )
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = (byte)(m_alpha * 255);
|
|
}
|
|
else
|
|
{
|
|
verts[0].modulate[3] =
|
|
verts[1].modulate[3] =
|
|
verts[2].modulate[3] =
|
|
verts[3].modulate[3] = 255;
|
|
}
|
|
|
|
cgi_R_AddPolyToScene( m_shader, 4, verts );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateScale
|
|
-------------------------
|
|
*/
|
|
|
|
void FXCylinder::UpdateScale( void )
|
|
{
|
|
m_scale += md_scale * cg.frametime * 0.001f;
|
|
|
|
if (m_scale < 0.0f)
|
|
m_scale = 0.0f;
|
|
|
|
m_scale2 += md_scale2 * cg.frametime * 0.001f;
|
|
|
|
if (m_scale2 < 0.0f)
|
|
m_scale2 = 0.0f;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
UpdateHeight
|
|
-------------------------
|
|
*/
|
|
|
|
void FXCylinder::UpdateHeight( void )
|
|
{
|
|
m_height += md_height * cg.frametime * 0.001f;
|
|
|
|
if (m_height < 0.0f)
|
|
m_height = 0.0f;
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
Update
|
|
-------------------------
|
|
*/
|
|
|
|
bool FXCylinder::Update( void )
|
|
{
|
|
UpdateScale();
|
|
UpdateHeight();
|
|
UpdateAlpha();
|
|
UpdateRGB();
|
|
|
|
return true;
|
|
}
|