/* =============== CL_TracerEffect =============== */ void CL_TracerEffect( const vec3_t start, const vec3_t end ) { particle_t *p; byte *color; vec3_t dir; float life, dist; p = CL_AllocParticle( CL_BulletTracerDraw ); if( !p ) return; // get out shot direction and length VectorSubtract( end, start, dir ); VectorCopy( dir, p->vel ); dist = VectorNormalizeLength( dir ); // don't make small tracers if( dist <= traceroffset->value ) return; p->ramp = Com_RandomFloat( 200.0f, 256.0f ) * tracerlength->value; color = gTracerColors[4]; life = ( dist + p->ramp ) / ( max( 1.0f, tracerspeed->value )); p->color = CL_LookupColor( color[0], color[1], color[2] ); VectorCopy( start, p->org ); p->type = pt_tracer; p->die += life; }
/* =============== CL_TracerEffect =============== */ void CL_UserTracerParticle( float *org, float *vel, float life, int colorIndex, float length, byte deathcontext, void (*deathfunc)( particle_t *p )) { particle_t *p; byte *color; p = CL_AllocParticle( CL_BulletTracerDraw ); if( !p ) return; if( colorIndex > ( sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))) { p->color = bound( 0, colorIndex, 255 ); } else { color = gTracerColors[colorIndex]; p->color = CL_LookupColor( color[0], color[1], color[2] ); } VectorCopy( org, p->org ); VectorCopy( vel, p->vel ); p->ramp = length; // ramp used as length p->context = deathcontext; p->deathfunc = deathfunc; p->type = pt_tracer; p->die += life; }
/* ================ CL_ShowLine ================ */ void CL_ShowLine( const vec3_t start, const vec3_t end ) { int pcolor; pcolor = CL_LookupColor( 192, 0, 0 ); CL_DrawLine( start, end, pcolor, 30.0f, 5.0f ); }
void CL_ParticleLine( const vec3_t start, const vec3_t end, byte r, byte g, byte b, float life ) { int pcolor; pcolor = CL_LookupColor( r, g, b ); CL_DrawLine( start, end, pcolor, life, 2.0f ); }
/* =============== CL_DebugParticle just for debug purposes =============== */ void CL_DebugParticle( const vec3_t pos, byte r, byte g, byte b ) { particle_t *p; p = CL_AllocParticle( NULL ); if( !p ) return; VectorCopy( pos, p->org ); p->die += 10.0f; p->color = CL_LookupColor( r, g, b ); }
/* =============== CL_SparkleTracer =============== */ void CL_SparkleTracer( const vec3_t pos, const vec3_t dir, float vel ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_SparkTracerDraw ); if( !p ) return; color = gTracerColors[5]; // Yellow-Orange VectorCopy( pos, p->org ); p->die += Com_RandomFloat( 0.45f, 0.7f ); p->color = CL_LookupColor( color[0], color[1], color[2] ); p->ramp = Com_RandomFloat( 0.07f, 0.08f ); // ramp used as tracer length p->type = pt_tracer; VectorScale( dir, vel, p->vel ); }
/* =============== CL_TracerParticles allow more customization =============== */ particle_t *CL_TracerParticles( float *org, float *vel, float life ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_BulletTracerDraw ); if( !p ) return NULL; p->ramp = Com_RandomFloat( 200.0f, 256.0f ) * tracerlength->value; color = gTracerColors[4]; p->color = CL_LookupColor( color[0], color[1], color[2] ); VectorCopy( org, p->org ); VectorCopy( vel, p->vel ); p->type = pt_tracer; p->die += life; return p; }
/* ================ CL_ParticleBox ================ */ void CL_ParticleBox( const vec3_t mins, const vec3_t maxs, byte r, byte g, byte b, float life ) { vec3_t tmp, p[8]; int i, col; col = CL_LookupColor( r, g, b ); for( i = 0; i < 8; i++ ) { tmp[0] = (i & 1) ? mins[0] : maxs[0]; tmp[1] = (i & 2) ? mins[1] : maxs[1]; tmp[2] = (i & 4) ? mins[2] : maxs[2]; VectorCopy( tmp, p[i] ); } for( i = 0; i < 6; i++ ) { CL_DrawRectangle( p[boxpnt[i][1]], p[boxpnt[i][0]], p[boxpnt[i][2]], p[boxpnt[i][3]], col, life ); } }
/* =============== CL_Implosion =============== */ void CL_Implosion( const vec3_t end, float radius, int count, float life ) { particle_t *p; float vel, radius2; vec3_t dir, m_vecPos; int i, colorIndex; colorIndex = CL_LookupColor( gTracerColors[5][0], gTracerColors[5][1], gTracerColors[5][2] ); for( i = 0; i < count; i++ ) { p = CL_AllocParticle( CL_TracerImplosion ); if( !p ) return; dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); radius2 = Com_RandomFloat( radius * 0.9f, radius * 1.1f ); VectorNormalize( dir ); VectorMA( end, -radius2, dir, m_vecPos ); // velocity based on how far particle has to travel away from org if( life ) vel = (radius2 / life); else vel = Com_RandomFloat( radius2 * 0.5f, radius2 * 1.5f ); VectorCopy( m_vecPos, p->org ); p->color = colorIndex; p->ramp = (vel / radius2) * 0.1f; // length based on velocity p->ramp = bound( 0.1f, p->ramp, 1.0f ); p->type = pt_tracer; VectorScale( dir, vel, p->vel ); // die right when you get there p->die += ( life != 0.0f ) ? life : ( radius2 / vel ); } }
/* =============== CL_StreakTracer =============== */ void CL_StreakTracer( const vec3_t pos, const vec3_t velocity, int colorIndex ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_SparkTracerDraw ); if( !p ) return; if( colorIndex > ( sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))) { p->color = bound( 0, colorIndex, 255 ); } else { color = gTracerColors[colorIndex]; p->color = CL_LookupColor( color[0], color[1], color[2] ); } p->die += Com_RandomFloat( 0.5f, 1.0f ); VectorCopy( velocity, p->vel ); VectorCopy( pos, p->org ); p->ramp = Com_RandomFloat( 0.05f, 0.08f ); p->type = pt_tracer; }
/* ================ CL_UpdateParticle update particle color, position etc ================ */ void CL_UpdateParticle( particle_t *p, float ft ) { float time3 = 15.0 * ft; float time2 = 10.0 * ft; float time1 = 5.0 * ft; float dvel = 4 * ft; float grav = ft * clgame.movevars.gravity * 0.05f; float size = 1.5f; int i, iRamp, alpha = 255; vec3_t right, up; rgb_t color; r_stats.c_particle_count++; switch( p->type ) { case pt_static: break; case pt_tracer: case pt_clientcustom: if( p->callback ) { p->callback( p, ft ); } if( p->type == pt_tracer ) return; // already drawed break; case pt_fire: p->ramp += time1; if( p->ramp >= 6 ) p->die = -1; else p->color = ramp3[(int)p->ramp]; p->vel[2] += grav; break; case pt_explode: p->ramp += time2; if( p->ramp >= 8 ) p->die = -1; else p->color = ramp1[(int)p->ramp]; for( i = 0; i < 3; i++ ) p->vel[i] += p->vel[i] * dvel; p->vel[2] -= grav; break; case pt_explode2: p->ramp += time3; if( p->ramp >= 8 ) p->die = -1; else p->color = ramp2[(int)p->ramp]; for( i = 0; i < 3; i++ ) p->vel[i] -= p->vel[i] * ft; p->vel[2] -= grav; break; case pt_blob: case pt_blob2: p->ramp += time2; iRamp = (int)p->ramp >> SIMSHIFT; if( iRamp >= SPARK_COLORCOUNT ) { p->ramp = 0.0f; iRamp = 0; } p->color = CL_LookupColor( gSparkRamp[iRamp][0], gSparkRamp[iRamp][1], gSparkRamp[iRamp][2] ); for( i = 0; i < 2; i++ ) p->vel[i] -= p->vel[i] * 0.5f * ft; p->vel[2] -= grav * 5.0f; if( Com_RandomLong( 0, 3 )) { p->type = pt_blob; alpha = 0; } else { p->type = pt_blob2; alpha = 255; } break; case pt_grav: p->vel[2] -= grav * 20; break; case pt_slowgrav: p->vel[2] -= grav; break; case pt_vox_grav: p->vel[2] -= grav * 8; break; case pt_vox_slowgrav: p->vel[2] -= grav * 4; break; } #if 0 // HACKHACK a scale up to keep particles from disappearing size += (p->org[0] - RI.vieworg[0]) * RI.vforward[0]; size += (p->org[1] - RI.vieworg[1]) * RI.vforward[1]; size += (p->org[2] - RI.vieworg[2]) * RI.vforward[2]; if( size < 20.0f ) size = 1.0f; else size = 1.0f + size * 0.004f; #endif // scale the axes by radius VectorScale( RI.vright, size, right ); VectorScale( RI.vup, size, up ); p->color = bound( 0, p->color, 255 ); VectorSet( color, clgame.palette[p->color][0], clgame.palette[p->color][1], clgame.palette[p->color][2] ); GL_SetRenderMode( kRenderTransTexture ); pglColor4ub( color[0], color[1], color[2], alpha ); GL_Bind( GL_TEXTURE0, cls.particleImage ); // add the 4 corner vertices. pglBegin( GL_QUADS ); pglTexCoord2f( 0.0f, 1.0f ); pglVertex3f( p->org[0] - right[0] + up[0], p->org[1] - right[1] + up[1], p->org[2] - right[2] + up[2] ); pglTexCoord2f( 0.0f, 0.0f ); pglVertex3f( p->org[0] + right[0] + up[0], p->org[1] + right[1] + up[1], p->org[2] + right[2] + up[2] ); pglTexCoord2f( 1.0f, 0.0f ); pglVertex3f( p->org[0] + right[0] - up[0], p->org[1] + right[1] - up[1], p->org[2] + right[2] - up[2] ); pglTexCoord2f( 1.0f, 1.0f ); pglVertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] ); pglEnd(); if( p->type != pt_clientcustom ) { // update position. VectorMA( p->org, ft, p->vel, p->org ); } }
/* =============== CL_BulletImpactParticles =============== */ void CL_BulletImpactParticles( const vec3_t org ) { particle_t *p; vec3_t pos, dir; float vel; int i, j; // do sparks // randomize position pos[0] = org[0] + Com_RandomFloat( -2.0f, 2.0f ); pos[1] = org[1] + Com_RandomFloat( -2.0f, 2.0f ); pos[2] = org[2] + Com_RandomFloat( -2.0f, 2.0f ); // create a 8 random spakle tracers for( i = 0; i < 8; i++ ) { dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); vel = Com_RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED ); CL_SparkleTracer( pos, dir, vel ); } if (r_oldparticles->integer == 1) { for (i = 0; i < 12; i++) { int greyColors; p = CL_AllocParticle(NULL); if (!p) return; p->die += 1.0f; // Randomly make each particle one of three colors: dark grey, medium grey or light grey. greyColors = (rand() % 3 + 1) * 32; p->color = CL_LookupColor(greyColors, greyColors, greyColors); p->type = pt_grav; for (j = 0; j < 3; j++) { p->org[j] = org[j] + Com_RandomFloat(-2.0f, 3.0f); p->vel[j] = Com_RandomFloat(-70.0f, 70.0f); } } } else { for (i = 0; i < 12; i++) { p = CL_AllocParticle(NULL); if (!p) return; p->die += 1.0f; p->color = 0; // black p->type = pt_grav; for (j = 0; j < 3; j++) { p->org[j] = org[j] + Com_RandomFloat(-2.0f, 3.0f); p->vel[j] = Com_RandomFloat(-70.0f, 70.0f); } } } }