1566 lines
37 KiB
C
1566 lines
37 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
/*******************************************************
|
|
QMB: new particle engine
|
|
|
|
almost ready for release!!
|
|
done: just need to make all the old functions call the new ones
|
|
|
|
maybe add some more documentation
|
|
|
|
work out what needs to be done to add to other quake engine
|
|
|
|
needs 32bit texture loading (from www.quakesrc.org)
|
|
*******************************************************
|
|
Shove this in to glquake insted of whats there at the moment for particles
|
|
|
|
//QMB: particles
|
|
//types of particles
|
|
typedef enum {
|
|
p_sparks, p_smoke, p_fire, p_blood, p_chunks, p_smoke_fade, p_custom
|
|
} p_type_t;
|
|
|
|
//QMB: particles
|
|
//custom movement effects
|
|
typedef enum {
|
|
pt_static, pt_grav, pt_slowgrav, pt_rise, pt_slowrise, pt_explode, pt_explode2, pt_blob, pt_blob2, pt_fire
|
|
} part_move_t;
|
|
|
|
//QMB: particles
|
|
//particle struct
|
|
typedef struct particle_s
|
|
{
|
|
// driver-usable fields
|
|
vec3_t org;
|
|
vec3_t colour; //float color (stops the need for looking up the 8bit to 24bit everytime
|
|
// drivers never touch the following fields
|
|
struct particle_s *next;
|
|
vec3_t vel;
|
|
float ramp; //sort of diffrent purpose
|
|
float die;
|
|
float start;
|
|
int hit;
|
|
float size;
|
|
float delay;
|
|
part_move_t type;
|
|
} particle_t;
|
|
|
|
//new particles
|
|
//add a trail of any particle type
|
|
void AddTrail(vec3_t start, vec3_t end, int type, float time);
|
|
void AddTrailColor(vec3_t start, vec3_t end, int type, float time, vec3_t colour);
|
|
//QMB: end
|
|
//add a particle or two
|
|
//Times: smoke=3, spark=2, blood=3, chunk=4
|
|
void AddParticle(vec3_t org, int count, float size, float time, int type);
|
|
void AddParticleColor(vec3_t org, int count, float size, float time, int type, vec3_t colour);
|
|
|
|
|
|
*******************************************************/
|
|
|
|
#include "quakedef.h"
|
|
//#include "r_local.h"
|
|
|
|
//default max # of particles at one time
|
|
//#define MAX_PARTICLES 2048
|
|
#define MAX_PARTICLES 4096
|
|
//no fewer than this no matter what's on the command line
|
|
#define ABSOLUTE_MIN_PARTICLES 512
|
|
|
|
//colour ramps: need to be changed to 24-bit colour
|
|
int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
|
|
int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
|
|
int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
|
|
|
|
//sin and cos tables for the particle triangle fans
|
|
float sint[7], cost[7];
|
|
|
|
//linked lists pointers for the first of the active, free and the a spare list
|
|
particle_t *active_particles, *free_particles, *particles;
|
|
particle_t *smoke, *fire, *blood, *sparks, *chunks, *env, *trails;
|
|
//Holder of the particle texture
|
|
int part_tex, smoke_tex, trail_tex;
|
|
//number of particles in total
|
|
int r_numparticles;
|
|
int r_numdelayadds;
|
|
int numParticles;
|
|
//vec3_t r_pright, r_pup, r_ppn;
|
|
cvar_t gl_texpart = {"gl_texpart","1"};
|
|
cvar_t gl_trail = {"gl_trail","1"};
|
|
cvar_t r_particle_dist = {"r_particle_dist","20"};
|
|
|
|
//internal functions
|
|
void R_UpdateParticles(void);
|
|
void TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal);
|
|
void R_UpdateAll(void);
|
|
void MakeParticleTexure(void);
|
|
void DrawTriFans(void);
|
|
void DrawTexQuad(void);
|
|
void AddFadeSmoke(vec3_t org, int count);
|
|
void DelayAddChunk(vec3_t org, int count, vec3_t colour, float time);
|
|
/*
|
|
===============
|
|
R_InitParticles
|
|
===============
|
|
*/
|
|
void R_InitParticles (void)
|
|
{
|
|
int i, a;
|
|
|
|
i = COM_CheckParm ("-particles");
|
|
if (i){
|
|
r_numparticles = (int)(Q_atoi(com_argv[i+1]));
|
|
if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
|
|
r_numparticles = ABSOLUTE_MIN_PARTICLES;
|
|
}
|
|
else{
|
|
r_numparticles = MAX_PARTICLES;
|
|
}
|
|
|
|
particles = (particle_t *)Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
|
|
|
|
//calculate sin/cos tables
|
|
for (i=0;i<7;i++)
|
|
{
|
|
a = i/7.0 * M_PI*2;
|
|
sint[i]=sin(a);
|
|
cost[i]=cos(a);
|
|
}
|
|
|
|
R_ClearParticles();
|
|
|
|
MakeParticleTexure();
|
|
Cvar_RegisterVariable (&gl_texpart);
|
|
Cvar_RegisterVariable (&gl_trail);
|
|
Cvar_RegisterVariable (&r_particle_dist);
|
|
}
|
|
|
|
#ifdef QUAKE2
|
|
void R_DarkFieldParticles (entity_t *ent)
|
|
{
|
|
int i, j, k;
|
|
particle_t *p;
|
|
float vel;
|
|
vec3_t dir;
|
|
vec3_t org;
|
|
byte *colourByte;
|
|
|
|
org[0] = ent->origin[0];
|
|
org[1] = ent->origin[1];
|
|
org[2] = ent->origin[2];
|
|
for (i=-16 ; i<16 ; i+=8)
|
|
for (j=-16 ; j<16 ; j+=8)
|
|
for (k=0 ; k<32 ; k+=8)
|
|
{
|
|
if (!free_particles)
|
|
return;
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = active_particles;
|
|
active_particles = p;
|
|
|
|
p->die = 0.2 + (rand()&7) * 0.02;
|
|
p->color = 150 + rand()%6;
|
|
p->type = pt_slowgrav;
|
|
|
|
dir[0] = j*8;
|
|
dir[1] = i*8;
|
|
dir[2] = k*8;
|
|
|
|
p->org[0] = org[0] + i + (rand()&3);
|
|
p->org[1] = org[1] + j + (rand()&3);
|
|
p->org[2] = org[2] + k + (rand()&3);
|
|
|
|
VectorNormalize (dir);
|
|
vel = 50 + (rand()&63);
|
|
VectorScale (dir, vel, p->vel);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
===============
|
|
R_EntityParticles
|
|
===============
|
|
*/
|
|
|
|
#define NUMVERTEXNORMALS 162
|
|
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
|
|
vec3_t avelocities[NUMVERTEXNORMALS];
|
|
float beamlength = 16;
|
|
vec3_t avelocity = {23, 7, 3};
|
|
float partstep = 0.01f;
|
|
float timescale = 0.01f;
|
|
|
|
//What the hell is all this stuff for????
|
|
void R_EntityParticles (entity_t *ent)
|
|
{
|
|
int count;
|
|
int i;
|
|
particle_t *p;
|
|
float angle;
|
|
float sr, sp, sy, cr, cp, cy;
|
|
vec3_t forward;
|
|
float dist;
|
|
byte *colourByte;
|
|
|
|
dist = 64;
|
|
count = 50;
|
|
|
|
if (!avelocities[0][0])
|
|
{
|
|
for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
|
|
avelocities[0][i] = (rand()&255) * 0.01;
|
|
}
|
|
|
|
|
|
for (i=0 ; i<NUMVERTEXNORMALS ; i++)
|
|
{
|
|
angle = cl.time * avelocities[i][0];
|
|
sy = sin(angle);
|
|
cy = cos(angle);
|
|
angle = cl.time * avelocities[i][1];
|
|
sp = sin(angle);
|
|
cp = cos(angle);
|
|
angle = cl.time * avelocities[i][2];
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
forward[0] = cp*cy;
|
|
forward[1] = cp*sy;
|
|
forward[2] = -sp;
|
|
|
|
if (!free_particles)
|
|
return;
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = active_particles;
|
|
active_particles = p;
|
|
|
|
p->hit = 0;
|
|
p->die = cl.time + 0.01;
|
|
|
|
colourByte = (byte *)&d_8to24table[0x6f];
|
|
p->colour[0] = colourByte[0]/255.0;
|
|
p->colour[1] = colourByte[1]/255.0;
|
|
p->colour[2] = colourByte[2]/255.0;
|
|
|
|
p->type = pt_explode;
|
|
|
|
p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
|
|
p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
|
|
p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
|
|
}
|
|
Con_Printf ("EntityParticles");
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_ClearParticles
|
|
===============
|
|
*/
|
|
void R_ClearParticles (void)
|
|
{
|
|
int i;
|
|
|
|
free_particles = &particles[0];
|
|
active_particles = smoke = chunks = fire = blood = sparks = env = trails = NULL;
|
|
|
|
for (i=0 ;i<r_numparticles ; i++)
|
|
particles[i].next = &particles[i+1];
|
|
particles[r_numparticles-1].next = NULL;
|
|
numParticles = 0;
|
|
}
|
|
|
|
//Reads a point file of particles
|
|
//Does this ever get used?
|
|
void R_ReadPointFile_f (void)
|
|
{
|
|
FILE *f;
|
|
vec3_t org;
|
|
int r;
|
|
int c;
|
|
particle_t *p;
|
|
char name[MAX_OSPATH];
|
|
byte *colourByte;
|
|
|
|
sprintf (name,"maps/%s.pts", sv.name);
|
|
|
|
COM_FOpenFile (name, &f);
|
|
if (!f)
|
|
{
|
|
Con_Printf ("couldn't open %s\n", name);
|
|
return;
|
|
}
|
|
|
|
Con_Printf ("Reading %s...\n", name);
|
|
c = 0;
|
|
for ( ;; )
|
|
{
|
|
r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
|
|
if (r != 3)
|
|
break;
|
|
c++;
|
|
|
|
if (!free_particles)
|
|
{
|
|
Con_Printf ("Not enough free particles\n");
|
|
break;
|
|
}
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = active_particles;
|
|
active_particles = p;
|
|
|
|
p->hit = 0;
|
|
p->die = cl.time + 99999;
|
|
|
|
colourByte = (byte *)&d_8to24table[(-c)&15];
|
|
p->colour[0] = colourByte[0]/255.0;
|
|
p->colour[1] = colourByte[1]/255.0;
|
|
p->colour[2] = colourByte[2]/255.0;
|
|
|
|
p->type = pt_static;
|
|
VectorCopy (vec3_origin, p->vel);
|
|
VectorCopy (org, p->org);
|
|
}
|
|
|
|
fclose (f);
|
|
Con_Printf ("%i points read\n", c);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_ParseParticleEffect
|
|
|
|
Parse an effect out of the server message
|
|
===============
|
|
*/
|
|
void R_ParseParticleEffect (void)
|
|
{
|
|
vec3_t org, dir;
|
|
int i, count, msgcount, color;
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
org[i] = MSG_ReadCoord ();
|
|
for (i=0 ; i<3 ; i++)
|
|
dir[i] = MSG_ReadChar () * (1.0/16);
|
|
msgcount = MSG_ReadByte ();
|
|
color = MSG_ReadByte ();
|
|
|
|
if (msgcount == 255)
|
|
count = 1024;
|
|
else
|
|
count = msgcount;
|
|
|
|
R_RunParticleEffect (org, dir, color, count);
|
|
}
|
|
|
|
/*===============
|
|
R_ParticleExplosion
|
|
===============*/
|
|
void R_ParticleExplosion (vec3_t org)
|
|
{
|
|
AddParticle(org, 64, 300, 1.5f, p_sparks);
|
|
AddParticle(org, 32, 200, 1.5f, p_sparks);
|
|
AddParticle(org, 20, 25, 2.0f, p_fire);
|
|
}
|
|
|
|
/*===============
|
|
R_ParticleExplosion2
|
|
===============*/
|
|
//Needs to be made to call new functions so that old ones can be removed
|
|
void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
|
|
{
|
|
vec3_t colour;
|
|
byte *colourByte;
|
|
|
|
colourByte = (byte *)&d_8to24table[colorStart];
|
|
colour[0] = (float)colourByte[0]/255.0;
|
|
colour[1] = (float)colourByte[1]/255.0;
|
|
colour[2] = (float)colourByte[2]/255.0;
|
|
|
|
AddParticleColor(org, 64, 200, 1.5f, p_sparks, colour);
|
|
AddParticle(org, 64, 1, 3, p_smoke);
|
|
}
|
|
|
|
/*===============
|
|
R_BlobExplosion
|
|
===============*/
|
|
//also do colored fires
|
|
void R_BlobExplosion (vec3_t org)
|
|
{
|
|
vec3_t colour;
|
|
|
|
colour[0]=0;
|
|
colour[1]=0;
|
|
colour[2]=1;
|
|
|
|
AddParticleColor(org, 64, 200, 1, p_sparks, colour);
|
|
}
|
|
|
|
/*===============
|
|
R_RunParticleEffect
|
|
===============*/
|
|
void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
|
|
{
|
|
byte *colourByte;
|
|
vec3_t colour;
|
|
|
|
colourByte = (byte *)&d_8to24table[color];
|
|
colour[0] = colourByte[0]/255.0;
|
|
colour[1] = colourByte[1]/255.0;
|
|
colour[2] = colourByte[2]/255.0;
|
|
|
|
if (count == 15)
|
|
{
|
|
AddParticleColor(org, 10, 1, 4, p_chunks, colour);
|
|
AddParticle(org, 1, 100, 1.0f, p_sparks);
|
|
}else if (count == 10)
|
|
{
|
|
AddParticleColor(org, 10, 1, 4, p_chunks, colour);
|
|
AddParticle(org, 3, 100, 1.0f, p_sparks);
|
|
}else if (count == 20)
|
|
{
|
|
AddParticleColor(org, 10, 1, 4, p_chunks, colour);
|
|
AddParticle(org, 10, 100, 1.0f, p_sparks);
|
|
}else if (count == 30)
|
|
{
|
|
AddParticleColor(org, 10, 1, 4, p_chunks, colour);
|
|
AddParticle(org, 5, 100, 1.0f, p_sparks);
|
|
}else if (count == 1024)
|
|
R_ParticleExplosion(org);
|
|
else
|
|
{
|
|
AddParticleColor(org, count, 1, 3, p_blood, colour);
|
|
}
|
|
}
|
|
|
|
|
|
/*===============
|
|
R_LavaSplash
|
|
===============*/
|
|
//Need to find out when this is called
|
|
void R_LavaSplash (vec3_t org)
|
|
{
|
|
AddParticle(org, 1500, 1000, 10, p_sparks);
|
|
AddParticle(org, 35, 55, 5, p_fire);
|
|
}
|
|
|
|
/*===============
|
|
R_TeleportSplash
|
|
===============*/
|
|
//Need to be changed so that they spin down into the ground
|
|
//whould look very cool
|
|
//maybe coloured blood (new type?)
|
|
void R_TeleportSplash (vec3_t org)
|
|
{
|
|
vec3_t colour;
|
|
|
|
colour[0]=0.9f;
|
|
colour[1]=0.9f;
|
|
colour[2]=0.9f;
|
|
|
|
AddParticleColor(org, 256, 200, 0.1f, p_sparks, colour);
|
|
}
|
|
|
|
//Should be made to call the new functions to keep compatablity
|
|
void R_RocketTrail (vec3_t start, vec3_t end, int type)
|
|
{
|
|
vec3_t colour;
|
|
|
|
switch (type)
|
|
{
|
|
case 0: // rocket trail
|
|
AddTrail(start, end, p_fire, 0.1f);
|
|
AddTrail(start, end, p_smoke, 1);
|
|
break;
|
|
|
|
case 1: // smoke smoke
|
|
AddTrail(start, end, p_smoke, 1);
|
|
break;
|
|
|
|
case 2: // blood
|
|
AddTrail(start, end, p_blood, 2);
|
|
break;
|
|
|
|
case 3: //tracer 1
|
|
colour[0]=0; colour[1]=1; colour[2]=0;
|
|
AddTrailColor (start, end, p_blood, 2, colour);
|
|
break;
|
|
|
|
case 5: // tracer 2
|
|
colour[0]=1; colour[1]=0.85f; colour[2]=0;
|
|
AddTrailColor (start, end, p_blood, 2, colour);
|
|
break;
|
|
|
|
case 4: // slight blood
|
|
AddParticle(end, 20, 1, 2, p_blood);
|
|
break;
|
|
|
|
case 6: // voor trail
|
|
colour[0]=1; colour[1]=0; colour[2]=0.75f;
|
|
AddTrailColor (start, end, p_blood, 2, colour);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_DrawParticles
|
|
===============
|
|
*/
|
|
extern cvar_t sv_gravity;
|
|
|
|
void R_DrawParticles (void)
|
|
{
|
|
//See if they can be compressed or made neater
|
|
if (cl.time != cl.oldtime)
|
|
R_UpdateAll();
|
|
|
|
glDepthMask(0);
|
|
// glEnable (GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glShadeModel (GL_SMOOTH);
|
|
|
|
DrawTexQuad();
|
|
|
|
glDepthMask(1);
|
|
// glDisable (GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
}
|
|
|
|
void DrawTexQuad(void)
|
|
{
|
|
particle_t *p;
|
|
|
|
vec3_t v;
|
|
int i;
|
|
float alphaF;
|
|
int size;
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
//Draw sparks particles
|
|
for (p=sparks ; p ; p=p->next)
|
|
{
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
alphaF = (1-(cl.time-p->start)/(p->die-p->start));
|
|
glColor4f (p->colour[0],p->colour[1],p->colour[2],alphaF);
|
|
glVertex3fv (p->org);
|
|
glColor4f (p->colour[0]/2,p->colour[1]/2,p->colour[2]/2,0);
|
|
for (i=7 ; i>=0 ; i--)
|
|
{
|
|
v[0] = p->org[0] - p->vel[0]/8 + vright[0]*cost[i%7]*p->size + vup[0]*sint[i%7]*p->size;
|
|
v[1] = p->org[1] - p->vel[1]/8 + vright[1]*cost[i%7]*p->size + vup[1]*sint[i%7]*p->size;
|
|
v[2] = p->org[2] - p->vel[2]/8 + vright[2]*cost[i%7]*p->size + vup[2]*sint[i%7]*p->size;
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
GL_Bind(part_tex);
|
|
glBegin (GL_QUADS);
|
|
|
|
/*
|
|
//Draw other particles
|
|
for (p=active_particles ; p ; p=p->next)
|
|
{
|
|
colour = (byte *)&d_8to24table[(int)p->color];
|
|
glColor4ub (colour[0],colour[1],colour[2],(byte)(p->ramp*255));
|
|
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, -size, vup, v);
|
|
VectorMA (v, -size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
VectorMA (p->org, size, vup, v);
|
|
VectorMA (v, -size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
VectorMA (p->org, size, vup, v);
|
|
VectorMA (v, size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org, -size, vup, v);
|
|
VectorMA (v, size, vright, v);
|
|
glVertex3fv (v);
|
|
}*/
|
|
|
|
//Draw blood particles
|
|
size = 1.2;
|
|
for (p=blood ; p ; p=p->next)
|
|
{
|
|
glColor4f (p->colour[0]*p->ramp,p->colour[1]*p->ramp,p->colour[2]*p->ramp,p->ramp);
|
|
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, -p->size*p->ramp, vup, v);
|
|
VectorMA (v, -p->size*p->ramp, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
VectorMA (p->org, p->size*p->ramp, vup, v);
|
|
VectorMA (v, -p->size*p->ramp, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
VectorMA (p->org, p->size*p->ramp, vup, v);
|
|
VectorMA (v, p->size*p->ramp, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org, -p->size*p->ramp, vup, v);
|
|
VectorMA (v, p->size*p->ramp, vright, v);
|
|
glVertex3fv (v);
|
|
}
|
|
|
|
//Draw fire particles
|
|
//size = 25;
|
|
for (p=fire ; p ; p=p->next)
|
|
{
|
|
VectorSubtract (p->org, r_origin, v);
|
|
if (Length (v) > r_particle_dist.value*3)
|
|
{
|
|
glColor4f (p->colour[0]*p->ramp,p->colour[1]*p->ramp,p->colour[2]*p->ramp,p->ramp);
|
|
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, -p->size, vup, v);
|
|
VectorMA (v, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (v, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (v, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org, -p->size, vup, v);
|
|
VectorMA (v, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
}
|
|
}
|
|
|
|
//Draw chunks particles
|
|
size=1;
|
|
for (p=chunks ; p ; p=p->next)
|
|
{
|
|
glColor4f (p->colour[0]*p->ramp,p->colour[1]*p->ramp,p->colour[2]*p->ramp,p->ramp);
|
|
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, -size, vup, v);
|
|
VectorMA (v, -size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
VectorMA (p->org, size, vup, v);
|
|
VectorMA (v, -size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
VectorMA (p->org, size, vup, v);
|
|
VectorMA (v, size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org, -size, vup, v);
|
|
VectorMA (v, size, vright, v);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
|
|
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
GL_Bind(smoke_tex);
|
|
glBegin (GL_QUADS);
|
|
//Draw smoke particles
|
|
for (p=smoke ; p ; p=p->next)
|
|
{
|
|
VectorSubtract (p->org, r_origin, v);
|
|
if (Length (v) > r_particle_dist.value)
|
|
{
|
|
glColor4f (p->colour[0],p->colour[1],p->colour[2],p->ramp/4);
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, -p->size*(2-p->ramp), vup, v);
|
|
VectorMA (v, -p->size*(2-p->ramp), vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
VectorMA (p->org, p->size*(2-p->ramp), vup, v);
|
|
VectorMA (v, -p->size*(2-p->ramp), vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
VectorMA (p->org, p->size*(2-p->ramp), vup, v);
|
|
VectorMA (v, p->size*(2-p->ramp), vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org, -p->size*(2-p->ramp), vup, v);
|
|
VectorMA (v, p->size*(2-p->ramp), vright, v);
|
|
glVertex3fv (v);
|
|
}
|
|
}
|
|
glEnd ();
|
|
|
|
GL_Bind(trail_tex);
|
|
glBegin (GL_QUADS);
|
|
//Draw trails
|
|
for (p=trails ; p ; p=p->next)
|
|
{
|
|
glColor4f (p->colour[0],p->colour[1],p->colour[2],p->ramp);
|
|
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (p->org, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
//VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (p->org, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
//VectorMA (p->org2, -p->size, vup, v);
|
|
VectorMA (p->org2, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org2, p->size, vup, v);
|
|
VectorMA (p->org2, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
// reverse texture - for upside down trails, backwards textures are culled neway.
|
|
glTexCoord2f (0, 1);
|
|
VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (p->org2, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (0, 0);
|
|
//VectorMA (p->org, p->size, vup, v);
|
|
VectorMA (p->org2, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 0);
|
|
//VectorMA (p->org2, -p->size, vup, v);
|
|
VectorMA (p->org, -p->size, vright, v);
|
|
glVertex3fv (v);
|
|
|
|
glTexCoord2f (1, 1);
|
|
VectorMA (p->org2, p->size, vup, v);
|
|
VectorMA (p->org, p->size, vright, v);
|
|
glVertex3fv (v);
|
|
}
|
|
|
|
glEnd();
|
|
}
|
|
|
|
//p_sparks, p_smoke, p_smoke_fade, p_fire, p_blood, p_chunks
|
|
void R_UpdateAll(void)
|
|
{
|
|
particle_t *p, *kill;
|
|
float grav, frametime, dist;
|
|
int j;
|
|
|
|
vec3_t oldOrg, stop, normal;
|
|
|
|
//Work out gravity and time
|
|
frametime = (cl.time - cl.oldtime)*1.5;
|
|
grav = frametime * 9.8*(sv_gravity.value/800);
|
|
|
|
for (j=p_sparks;j<=p_chunks;j++)
|
|
{
|
|
if (j==p_smoke_fade)
|
|
j++;
|
|
|
|
switch (j)
|
|
{
|
|
case(p_smoke):
|
|
p=smoke;
|
|
break;
|
|
case(p_sparks):
|
|
p=sparks;
|
|
break;
|
|
case(p_fire):
|
|
p=fire;
|
|
break;
|
|
case(p_blood):
|
|
p=blood;
|
|
break;
|
|
case(p_chunks):
|
|
p=chunks;
|
|
break;
|
|
}
|
|
|
|
for (; p; p=p->next){
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time) // || CONTENTS_SOLID == SV_PointContents (kill->org)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
if (j==p_fire)
|
|
AddParticle(kill->org,1,4,1,p_smoke);
|
|
numParticles--;
|
|
//AddFadeSmoke(kill->org, 1);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (p=smoke; p; p=p->next){
|
|
//Update smoke movement
|
|
VectorCopy(p->org, oldOrg);
|
|
|
|
p->org[0] += p->vel[0]*frametime + (rand()%4-1.5)/16*frametime;
|
|
p->org[1] += p->vel[1]*frametime + (rand()%4-1.5)/16*frametime;
|
|
p->org[2] += p->vel[2]*frametime + (rand()%4-1.5)/16*frametime;
|
|
p->vel[2] += grav;
|
|
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
p->die = 0;
|
|
|
|
if (p->type)
|
|
{
|
|
if (cl.time > p->start)
|
|
p->type=0;
|
|
p->ramp = 1+(1-(cl.time-p->delay)/(p->start-p->delay));
|
|
}else{
|
|
p->ramp = (1-(cl.time-p->start)/(p->die-p->start));
|
|
p->size += p->ramp/16;
|
|
}
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
numParticles--;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (p=fire; p; p=p->next){
|
|
//Update fire movement
|
|
VectorCopy(p->org, oldOrg);
|
|
|
|
p->org[0] += p->vel[0]*frametime;
|
|
p->org[1] += p->vel[1]*frametime;
|
|
p->org[2] += p->vel[2]*frametime;
|
|
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -2;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org);
|
|
}
|
|
|
|
p->ramp = (1-((cl.time-p->start)/(p->die-p->start))*0.8);
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
AddParticle(kill->org,1,4,1,p_smoke);
|
|
numParticles--;
|
|
//AddFadeSmoke(kill->org, 1);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (p=chunks; p; p=p->next){
|
|
//Update chunk movement
|
|
VectorCopy(p->org, oldOrg);
|
|
p->org[0] += p->vel[0]*frametime;
|
|
p->org[1] += p->vel[1]*frametime;
|
|
p->org[2] += p->vel[2]*frametime;
|
|
p->vel[2] -= grav*8;
|
|
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -1.3;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org);
|
|
}
|
|
|
|
p->ramp = (1-(cl.time-p->start)/(p->die-p->start));
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next;kill;kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
numParticles--;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (p=sparks; p; p=p->next){
|
|
//Update spark movement
|
|
VectorCopy(p->org, oldOrg);
|
|
p->org[0] += p->vel[0]*frametime;
|
|
p->org[1] += p->vel[1]*frametime;
|
|
p->org[2] += p->vel[2]*frametime;
|
|
p->vel[2] -= grav*32;
|
|
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -1.5;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org);
|
|
if (rand()%100-90>0)
|
|
p->die = cl.time-1;
|
|
}
|
|
|
|
p->ramp = (1-(cl.time-p->start)/(p->die-p->start));
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
numParticles--;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (p=blood; p; p=p->next){
|
|
//Update blood movement
|
|
if (p->hit == 0){
|
|
VectorCopy(p->org, oldOrg);
|
|
p->org[0] += p->vel[0]*frametime;
|
|
p->org[1] += p->vel[1]*frametime;
|
|
p->org[2] += p->vel[2]*frametime;
|
|
p->vel[2] -= grav*8;
|
|
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -0.1;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org);
|
|
if (Length(p->vel)<0.2)
|
|
p->hit=1;
|
|
}
|
|
}
|
|
|
|
p->ramp = (1-(cl.time-p->start)/(p->die-p->start));
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
numParticles--;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (p=trails; p; p=p->next){
|
|
if (p->type == pt_grav){
|
|
p->vel[2] -= grav*10;
|
|
}
|
|
VectorCopy(p->org, oldOrg);
|
|
p->org[0] += p->vel[0]*frametime;
|
|
p->org[1] += p->vel[1]*frametime;
|
|
p->org[2] += p->vel[2]*frametime;
|
|
TraceLineN(oldOrg, p->org, stop, normal);
|
|
if ((stop != p->org)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -0.1;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org);
|
|
if (Length(p->vel)<0.2)
|
|
p->hit=1;
|
|
}
|
|
|
|
VectorCopy(p->org2, oldOrg);
|
|
p->org2[0] += p->vel[0]*frametime;
|
|
p->org2[1] += p->vel[1]*frametime;
|
|
p->org2[2] += p->vel[2]*frametime;
|
|
TraceLineN(oldOrg, p->org2, stop, normal);
|
|
if ((stop != p->org2)&&(Length(stop)!=0))
|
|
{
|
|
dist = DotProduct(p->vel, normal) * -0.1;
|
|
|
|
VectorMA(p->vel, dist, normal, p->vel);
|
|
VectorCopy(stop, p->org2);
|
|
if (Length(p->vel)<0.2)
|
|
p->hit=1;
|
|
}
|
|
p->ramp = (1-(cl.time-p->start)/(p->die-p->start));
|
|
|
|
//Kill off dead particles
|
|
for (kill = p->next ;kill; kill = p->next)
|
|
{
|
|
if (kill->die <= cl.time)
|
|
{
|
|
p->next = kill->next;
|
|
kill->next = free_particles;
|
|
free_particles = kill;
|
|
numParticles--;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** TraceLineN
|
|
* same as the TraceLine but returns the normal as well
|
|
* which is needed for bouncing particles
|
|
*/
|
|
void TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
|
|
{
|
|
trace_t trace;
|
|
|
|
memset (&trace, 0, sizeof(trace));
|
|
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
|
|
|
|
VectorCopy (trace.endpos, impact);
|
|
VectorCopy (trace.plane.normal, normal);
|
|
}
|
|
|
|
/*
|
|
Fire: Explosion, Rocket, Flame
|
|
Smoke: Rocket, Gren trail, Explosion smoke
|
|
Sparks: Explosion, Gunshot
|
|
Chunks: Gunshot
|
|
Blood: Gunshot, trail
|
|
Enviromental: Snow, Rain
|
|
Trails: Rail trail, Lightning(?)
|
|
*/
|
|
|
|
|
|
/** AddParticle
|
|
* Just calls AddParticleColor with the default color variable for that particle
|
|
*/
|
|
void AddParticle(vec3_t org, int count, float size, float time, int type)
|
|
{
|
|
//Times: smoke=3, spark=2, blood=3, chunk=4
|
|
vec3_t colour;
|
|
|
|
switch (type)
|
|
{
|
|
case (p_smoke):
|
|
colour[0] = colour[1] = colour[2] = (rand()%255)/255.0;
|
|
break;
|
|
case (p_sparks):
|
|
colour[0] = 1;
|
|
colour[1] = 0.5;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_fire):
|
|
colour[0] = 1;
|
|
colour[1] = 0.55f;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_blood):
|
|
colour[0] = (rand()%128)/256.0+0.5;;
|
|
colour[1] = 0;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_chunks):
|
|
colour[0] = colour[1] = colour[2] = (rand()%182)/255.0;
|
|
}
|
|
|
|
AddParticleColor(org, count, size, time, type, colour);
|
|
}
|
|
|
|
//same as addparticle with a colour var
|
|
|
|
/** AddParticleColor
|
|
* This is where it all happends, well not really this is where
|
|
* most of the particles (and soon all) are added execpt for trails
|
|
*/
|
|
void AddParticleColor(vec3_t org, int count, float size, float time, int type, vec3_t colour)
|
|
{
|
|
particle_t *p;
|
|
vec3_t stop, normal;
|
|
int i;
|
|
float tempSize;
|
|
|
|
for (i=0 ; (i<count)&&(free_particles) ; i++)
|
|
{
|
|
//get the next free particle off the list
|
|
p = free_particles;
|
|
//reset the next free particle to the next on the list
|
|
free_particles = p->next;
|
|
//add the particle to the correct one
|
|
p->size = size;
|
|
switch (type)
|
|
{
|
|
case (p_fire):
|
|
p->next = fire;
|
|
fire = p;
|
|
|
|
//pos
|
|
p->org[0] = org[0] + ((rand()%80)-40)*(size/25);
|
|
p->org[1] = org[1] + ((rand()%80)-40)*(size/25);
|
|
p->org[2] = org[2] + ((rand()%80)-40)*(size/25);
|
|
TraceLineN(org, p->org, stop, normal);
|
|
if (Length(stop) != 0)
|
|
VectorCopy(stop, p->org);
|
|
|
|
//velocity
|
|
p->vel[0] = ((rand()%40)-20)*(size/25);
|
|
p->vel[1] = ((rand()%40)-20)*(size/25);
|
|
p->vel[2] = ((rand()%40)-20)*(size/25);
|
|
break;
|
|
|
|
case (p_sparks):
|
|
p->next = sparks;
|
|
sparks = p;
|
|
|
|
p->size = 1;
|
|
//pos
|
|
VectorCopy(org, p->org);
|
|
//velocity
|
|
tempSize = size * 2;
|
|
p->vel[0] = (rand()%(int)tempSize)-((int)tempSize/2);
|
|
p->vel[1] = (rand()%(int)tempSize)-((int)tempSize/2);
|
|
p->vel[2] = (rand()%(int)tempSize); //-((int)size/2);
|
|
break;
|
|
|
|
case (p_smoke):
|
|
p->next = smoke;
|
|
smoke = p;
|
|
|
|
//pos
|
|
p->org[0] = org[0] + ((rand()%30)-15)/2;
|
|
p->org[1] = org[1] + ((rand()%30)-15)/2;
|
|
p->org[2] = org[2] + ((rand()%30)-15)/2;
|
|
TraceLineN(org, p->org, stop, normal);
|
|
if (Length(stop) != 0)
|
|
VectorCopy(stop, p->org);
|
|
|
|
//velocity
|
|
p->vel[0] = ((rand()%10)-5)/20;
|
|
p->vel[1] = ((rand()%10)-5)/20;
|
|
p->vel[2] = ((rand()%10)-5)/20;
|
|
break;
|
|
|
|
case (p_blood):
|
|
p->next = blood;
|
|
blood = p;
|
|
|
|
p->size = size * (rand()%20)/5;
|
|
//pos
|
|
VectorCopy(org, p->org);
|
|
//p->org[0] = org[0] + ((rand()%30)-15)/2;
|
|
//p->org[1] = org[1] + ((rand()%30)-15)/2;
|
|
//p->org[2] = org[2] + ((rand()%30)-15)/2;
|
|
TraceLineN(org, p->org, stop, normal);
|
|
if (Length(stop) != 0)
|
|
VectorCopy(stop, p->org);
|
|
|
|
//velocity
|
|
p->vel[0] = (rand()%40)-20;
|
|
p->vel[1] = (rand()%40)-20;
|
|
p->vel[2] = (rand()%40)-20;
|
|
break;
|
|
|
|
case (p_chunks):
|
|
p->next = chunks;
|
|
chunks = p;
|
|
//pos
|
|
VectorCopy(org, p->org);
|
|
//velocity
|
|
p->vel[0] = (rand()%40)-20;
|
|
p->vel[1] = (rand()%40)-20;
|
|
p->vel[2] = (rand()%40)-5;
|
|
break;
|
|
}
|
|
|
|
p->hit = 0;
|
|
p->start = cl.time;
|
|
p->die = cl.time + time;
|
|
p->type = 0;
|
|
VectorCopy(colour, p->colour);
|
|
|
|
numParticles++;
|
|
}
|
|
}
|
|
|
|
/** DelayAddChunk
|
|
* This is to do effects like max payne where the chunks from
|
|
* a bullet hole are created from there for a few seconds
|
|
* basicly it will slowly add chunks over a period of time
|
|
*/
|
|
void DelayAddChunk(vec3_t org, int count, vec3_t colour, float time)
|
|
{
|
|
//as you can see its not here yet
|
|
//i hope to get it in by the next version
|
|
}
|
|
|
|
/** AddFadeSmoke
|
|
* Specal type of smoke which is added when a fire
|
|
* particle dies this is how the rocket trail is made
|
|
* the somke has a quick fade in before acting normaly.
|
|
* This should also work for particle fires if i implement them
|
|
*/
|
|
void AddFadeSmoke(vec3_t org, int count)
|
|
{
|
|
particle_t *p;
|
|
int i;
|
|
|
|
for (i=0 ; (i<count)&&(free_particles) ; i++)
|
|
{
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = smoke;
|
|
smoke = p;
|
|
|
|
p->hit = 0;
|
|
p->delay = cl.time;
|
|
p->start = cl.time + 0.1;
|
|
p->die = cl.time + 1.1;
|
|
p->type = 1;
|
|
p->size = 4;
|
|
|
|
p->ramp = 2;
|
|
|
|
p->colour[0] = p->colour[1] = p->colour[2] = (rand()%255)/255.0;
|
|
|
|
p->org[0] = org[0];
|
|
p->org[1] = org[1];
|
|
p->org[2] = org[2];
|
|
p->vel[0] = ((rand()%10)-5)/20;
|
|
p->vel[1] = ((rand()%10)-5)/20;
|
|
p->vel[2] = ((rand()%10)-5)/20;
|
|
}
|
|
}
|
|
|
|
/** AddEnv
|
|
* This is ment to add enviroment effects when its
|
|
* finished but currently its not working ill add it soon
|
|
* -note there is the psudo code of how it will work there
|
|
* if you do implemnt it send me the code
|
|
*/
|
|
void AddEnv(vec3_t org, vec3_t org2, int count)
|
|
{
|
|
//From top corner (org) to bottom corner (org2)
|
|
//(org2 - org)*(1,0,0)->A
|
|
//(org2 - org)*(0,1,0)->B
|
|
//for i=0 to count
|
|
//add effeect at: org + rand()*A + rand()*B
|
|
//set take away effect when it gets below org2[3]
|
|
|
|
}
|
|
|
|
/** AddTrail
|
|
* Calls AddTrailColor with the default colours
|
|
*/
|
|
void AddTrail(vec3_t start, vec3_t end, int type, float time)
|
|
{
|
|
vec3_t colour;
|
|
|
|
//colour set when first update called (check if needs to be fixed)
|
|
switch (type)
|
|
{
|
|
case (p_smoke):
|
|
colour[0] = colour[1] = colour[2] = (rand()%128)/128.0+128;
|
|
break;
|
|
case (p_sparks):
|
|
colour[0] = 1;
|
|
colour[1] = 0.5;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_fire):
|
|
colour[0] = 1;
|
|
colour[1] = 0.55f;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_blood):
|
|
colour[0] = 0.8f;
|
|
colour[1] = 0;
|
|
colour[2] = 0;
|
|
break;
|
|
case (p_chunks):
|
|
colour[0] = colour[1] = colour[2] = (rand()%182)/255.0;
|
|
}
|
|
AddTrailColor(start, end, type, time, colour);
|
|
}
|
|
|
|
/** AddTrailColor
|
|
* This will add a trail of particles of the specified type.
|
|
* The particles may need thining but ill get some feed back
|
|
* on it first
|
|
*/
|
|
void AddTrailColor(vec3_t start, vec3_t end, int type, float time, vec3_t color)
|
|
{
|
|
particle_t *p;
|
|
int i;
|
|
float count;
|
|
vec3_t point;
|
|
|
|
//work out vector for trail
|
|
VectorSubtract(start, end, point);
|
|
//work out the length and therefore the amount of particles
|
|
count = Length(point);
|
|
//make sure its at least 1 long
|
|
//quater the amount of particles (speeds it up a bit)
|
|
if (count == 0)
|
|
return;
|
|
else
|
|
count = count/4;
|
|
|
|
if (((type == p_blood)||(type == p_smoke))&&(free_particles)){
|
|
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = trails;
|
|
trails = p;
|
|
|
|
VectorCopy(start, p->org);
|
|
VectorCopy(end, p->org2);
|
|
|
|
p->die = cl.time + time +2;
|
|
p->size = 2;
|
|
|
|
VectorCopy(color, p->colour);
|
|
p->hit = 0;
|
|
p->start = cl.time;
|
|
p->vel[0] = 0;
|
|
p->vel[1] = 0;
|
|
p->vel[2] = 0;
|
|
|
|
numParticles++;
|
|
count /= 2;
|
|
if (type == p_blood){
|
|
p->type = pt_grav;
|
|
return;
|
|
} else
|
|
p->type = pt_static;
|
|
}
|
|
|
|
//the vector from the current pos to the next particle
|
|
VectorScale(point, 1.0/count, point);
|
|
|
|
for (i=0 ; (i<count)&&(free_particles) ; i++)
|
|
{
|
|
//set the current particle to the next free particle
|
|
p = free_particles;
|
|
//reset the free particle pointer to the now first free particle
|
|
free_particles = p->next;
|
|
|
|
//small starting velocity
|
|
p->vel[0]=((rand()%16)-8)/2;
|
|
p->vel[1]=((rand()%16)-8)/2;
|
|
p->vel[2]=((rand()%16)-8)/2;
|
|
|
|
//add the particle to the correct one
|
|
switch (type)
|
|
{
|
|
case (p_fire):
|
|
p->next = fire;
|
|
fire = p;
|
|
p->size = 8;
|
|
break;
|
|
case (p_sparks):
|
|
//need bigger starting velocity (affected by grav)
|
|
p->vel[0]=((rand()%32)-16)*2;
|
|
p->vel[1]=((rand()%32)-16)*2;
|
|
p->vel[2]=((rand()%32))*2;
|
|
|
|
p->next = sparks;
|
|
sparks = p;
|
|
p->size = 1;
|
|
break;
|
|
case (p_smoke):
|
|
p->next = smoke;
|
|
smoke = p;
|
|
p->size = 4;
|
|
break;
|
|
case (p_blood):
|
|
p->next = blood;
|
|
blood = p;
|
|
p->size = 1.5 * (rand()%20)/10;
|
|
break;
|
|
case (p_chunks):
|
|
p->next = chunks;
|
|
chunks = p;
|
|
p->size = 1;
|
|
break;
|
|
}
|
|
|
|
//reset the particle vars
|
|
p->hit = 0;
|
|
p->start = cl.time;
|
|
p->die = cl.time + time;
|
|
|
|
|
|
VectorCopy(color, p->colour);
|
|
|
|
//work out the pos
|
|
VectorMA (start, i, point, p->org);
|
|
|
|
//make it a bit more random
|
|
p->org[0] += ((rand()%16)-8)/8;
|
|
p->org[1] += ((rand()%16)-8)/8;
|
|
p->org[2] += ((rand()%16)-8)/8;
|
|
|
|
numParticles++;
|
|
}
|
|
}
|
|
|
|
/** MakeParticleTexture
|
|
* Makes the particle textures only 2 the
|
|
* smoke texture (which could do with some work and
|
|
* the others which is just a round circle.
|
|
*
|
|
* I should really make it an alpha texture which would save 32*32*3
|
|
* bytes of space but *shrug* it works so i wont stuff with it
|
|
*/
|
|
void MakeParticleTexure(void)
|
|
{
|
|
int i, j, k, centreX, centreY, separation, max;
|
|
byte data[128][128][4];
|
|
|
|
//Normal texture (0->256 in a circle)
|
|
//If you change this texture you will change the textures of
|
|
//all particles except for smoke (other texture) and the
|
|
//sparks which dont use textures
|
|
for(j=0;j<128;j++){
|
|
for(i=0;i<128;i++){
|
|
data[i][j][0] = 255;
|
|
data[i][j][1] = 255;
|
|
data[i][j][2] = 255;
|
|
separation = (int) sqrt((64-i)*(64-i) + (64-j)*(64-j));
|
|
if(separation<63)
|
|
data[i][j][3] = 255 - separation * 256/63;
|
|
else data[i][j][3] =0;
|
|
}
|
|
}
|
|
//Load the texture into vid mem and save the number for later use
|
|
part_tex = GL_LoadTexture ("particle", 128, 128, &data[0][0][0], true, true, 4);
|
|
|
|
//Smoke texture (32 * 4 unit circles)
|
|
//This needs a bit of work its still a bit square but it will do for now
|
|
|
|
//Clear the data
|
|
max=(int)(sqrt((64-0)*(64-0) + (64-0)*(64-0)));
|
|
for(j=0;j<128;j++){
|
|
for(i=0;i<128;i++){
|
|
data[i][j][0] = 255;
|
|
data[i][j][1] = 255;
|
|
data[i][j][2] = 255;
|
|
separation = (int) sqrt((64-i)*(64-i) + (64-j)*(64-j));
|
|
data[i][j][3] = (max - separation)*2;
|
|
}
|
|
}
|
|
|
|
//Add 128 random 4 unit circles
|
|
for(k=0;k<128;k++){
|
|
centreX = rand()%122+3;
|
|
centreY = rand()%122+3;
|
|
for(j=-3;j<3;j++){
|
|
for(i=-3;i<3;i++){
|
|
separation = (int) sqrt((i*i) + (j*j));
|
|
if (separation <= 5)
|
|
data[i+centreX][j+centreY][3] += (5-separation);
|
|
}
|
|
}
|
|
}
|
|
smoke_tex = GL_LoadTexture ("smoke_part", 128, 128, &data[0][0][0], false, true, 4);
|
|
|
|
//Load the texture and save the number for later use
|
|
|
|
//Clear the data
|
|
max=64;
|
|
for(j=0;j<128;j++){
|
|
for(i=0;i<128;i++){
|
|
data[i][j][0] = 255;
|
|
data[i][j][1] = 255;
|
|
data[i][j][2] = 255;
|
|
separation = (int) sqrt((i - 64)*(i - 64));
|
|
data[i][j][3] = (max - separation)*2;
|
|
}
|
|
}
|
|
|
|
//Add 128 random 4 unit circles
|
|
for(k=0;k<128;k++){
|
|
centreX = rand()%122+3;
|
|
centreY = rand()%122+3;
|
|
for(j=-3;j<3;j++){
|
|
for(i=-3;i<3;i++){
|
|
separation = (int) sqrt((i*i) + (j*j));
|
|
if (separation <= 5)
|
|
data[i+centreX][j+centreY][3] += (5-separation);
|
|
}
|
|
}
|
|
}
|
|
trail_tex = GL_LoadTexture ("trail_part", 128, 128, &data[0][0][0], false, true, 4);
|
|
|
|
free(data);
|
|
}
|
|
//Yep thats all only 1472 lines of code
|