ew-engine/mq engine src/gl_part.c
2006-10-08 00:00:00 +00:00

1884 lines
No EOL
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.
*/
//
// particle engine
//
#include "quakedef.h"
typedef enum ptype_s ptype_t;
typedef struct particle_s particle_t;
typedef struct texcoords_s texcoords_t;
enum ptype_s
{
pt_static = 1 << 0,
pt_smoke = 1 << 1,
pt_bubble = 1 << 2,
pt_explode = 1 << 3,
pt_blood = 1 << 4,
pt_bulletpuff = 1 << 5,
pt_fade = 1 << 6,
pt_grav = 1 << 7,
pt_rail = 1 << 8,
pt_blob = 1 << 9,
pt_blob2 = 1 << 10,
pt_smokeexp = 1 << 11,
pt_fire = 1 << 12,
pt_fire2 = 1 << 13
};
struct particle_s
{
float *texcoords;
int contents;
int fade;
int growth;
float die;
float time;
float alpha;
float scale;
float bounce;
float gravity;
byte colorred;
byte colorgreen;
byte colorblue;
vec3_t origin;
vec3_t velocity;
ptype_t type;
qboolean glow;
particle_t *next;
particle_t *prev;
};
void AssignPartStuff ( particle_t *p,
float *texcoords,
float die,
float time,
float alpha,
float scale,
float bounce,
float gravity,
int fade,
int growth,
int contents,
byte colorred,
byte colorgreen,
byte colorblue,
vec3_t origin,
vec3_t velocity,
ptype_t type,
qboolean glow)
{
p->texcoords = texcoords;
p->die = die;
p->time = time;
p->alpha = alpha;
p->scale = scale;
p->bounce = bounce;
p->gravity = gravity;
p->fade = fade;
p->growth = growth;
p->contents = contents;
p->colorred = colorred;
p->colorgreen = colorgreen;
p->colorblue = colorblue;
p->origin[0] = origin[0];
p->origin[1] = origin[1];
p->origin[2] = origin[2];
p->velocity[0] = velocity[0];
p->velocity[1] = velocity[1];
p->velocity[2] = velocity[2];
p->type = type;
p->glow = glow;
}
int part_font;
byte data[64][64][4];
float smoke_coords[4];
float blood_coords[4];
float bubble_coords[4];
float particle_coords[4];
particle_t *active_particles, *free_particles, *particles;
int r_numparticles;
vec3_t r_pright, r_pup, r_ppn;
extern byte particle[32][32];
extern byte smoke[32][32];
extern byte blood[32][32];
extern byte bubble[32][32];
void R_MakeParticleTexture (int xx, int yy, byte texture[32][32])
{
int x, y;
for (x=xx ; x<xx+32 ; x++)
{
for (y=yy ; y<yy+32 ; y++)
{
data[x][y][0] = 255;
data[x][y][1] = 255;
data[x][y][2] = 255;
data[x][y][3] = texture[x-xx][y-yy];
}
}
}
void R_InitParticleTexture (void)
{
memset (data, 0, sizeof(data));
R_MakeParticleTexture (0, 0, smoke);
R_MakeParticleTexture (0, 32, blood);
R_MakeParticleTexture (32, 0, bubble);
R_MakeParticleTexture (32, 32, particle);
part_font = GL_LoadTexture ("particle", 64, 64, &data[0][0][0], true, true, 4);
// 0 = left, 1 = right, 2 = down, 3 = up
smoke_coords[0] = 0.0;
smoke_coords[1] = 0.5;
smoke_coords[2] = 0.0;
smoke_coords[3] = 0.5;
blood_coords[0] = 0.5;
blood_coords[1] = 1.0;
blood_coords[2] = 0.0;
blood_coords[3] = 0.5;
bubble_coords[0] = 0.0;
bubble_coords[1] = 0.5;
bubble_coords[2] = 0.5;
bubble_coords[3] = 1.0;
particle_coords[0] = 0.5;
particle_coords[1] = 1.0;
particle_coords[2] = 0.5;
particle_coords[3] = 1.0;
// 0 = left, 1 = right, 2 = down, 3 = up
}
/*
===============
R_InitParticles
===============
*/
void R_InitParticles (void)
{
int i = COM_CheckParm ("-particles");
r_numparticles = 4096;
if (i)
r_numparticles = (int)(atoi(com_argv[i+1]));
particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
memset(particles, 0, r_numparticles * sizeof(particle_t));
for( i = 0 ; i < r_numparticles ; ++i )
{
particles[i].prev = &particles[i - 1];
particles[i].next = &particles[i + 1];
}
particles[0].prev = NULL;
particles[r_numparticles - 1].next = NULL;
free_particles = &particles[0];
active_particles = NULL;
R_InitParticleTexture ();
}
/*
===============
R_ClearParticles
===============
*/
void R_ClearParticles (void)
{
int i;
free_particles = &particles[0];
active_particles = NULL;
memset(particles, 0, r_numparticles * sizeof(particle_t));
for( i = 0 ; i < r_numparticles ; ++i )
{
particles[i].prev = &particles[i - 1];
particles[i].next = &particles[i + 1];
}
particles[0].prev = NULL;
particles[r_numparticles - 1].next = NULL;
}
particle_t* addParticle()
{
particle_t* p = free_particles;
if(!p)
return NULL;
free_particles = p->next;
if(free_particles)
free_particles->prev = NULL;
p->next = active_particles;
if(active_particles)
active_particles->prev = p;
active_particles = p;
return p;
}
particle_t* remParticle(particle_t* p)
{
particle_t* next;
if(!p)
return NULL;
if(p == active_particles)
active_particles = p->next;
if(p->next)
p->next->prev = p->prev;
if(p->prev)
p->prev->next = p->next;
if(free_particles)
free_particles->prev = p;
next = p->next;
p->next = free_particles;
free_particles = p;
p->prev = NULL;
return next;
}
/*
===============
R_ReadPointFile
===============
*/
void R_ReadPointFile_f (void)
{
FILE *f;
vec3_t origin;
int r;
int c;
particle_t *p;
char name[MAX_OSPATH];
byte *color;
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", &origin[0], &origin[1], &origin[2]);
if (r != 3)
break;
c++;
p = addParticle();
if(!p)
{
Con_Printf ("Not enough free particles\n");
break;
}
color = (byte *) &d_8to24table[(int)(-c)&15];
p->fade = 0;
p->growth = 0;
p->texcoords = particle_coords;
p->contents = 0;
p->die = 99;
p->time = 0;
p->alpha = 200;
p->scale = 2;
p->bounce = 0;
p->gravity = 0;
p->colorred = color[0];
p->colorgreen = color[1];
p->colorblue = color[2];
p->origin[0] = origin[0];
p->origin[1] = origin[1];
p->origin[2] = origin[2];
p->velocity[0] = vec3_origin[0];
p->velocity[1] = vec3_origin[1];
p->velocity[2] = vec3_origin[2];
p->type = pt_static;
p->glow = true;
}
fclose (f);
Con_Printf ("%i points read\n", c);
}
/*
===============
R_EntityParticles
===============
*/
float r_avertexnormals[162][3] =
{
#include "anorms.h"
};
vec3_t avelocities[128];
void R_EntityParticles (entity_t *ent)
{
int i;
float sp, sy, cp, cy, angle;
vec3_t forward;
particle_t *p;
if (!avelocities[0][0])
{
for (i=0 ; i<384 ; i++)
{
avelocities[0][i] = (rand() & 255) * 0.01;
}
}
for (i=0 ; i<128 ; 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);
forward[0] = cp*cy;
forward[1] = cp*sy;
forward[2] = -sp;
p = addParticle();
if(!p)
{
return;
}
p->fade = 0;
p->growth = 0;
p->texcoords = particle_coords;
p->contents = 0;
p->die = cl.time + 0.01;
p->time = 0;
p->alpha = 200;
p->scale = 2;
p->bounce = 0;
p->gravity = 0;
p->colorred = 255;//255;
p->colorgreen = 255;//243;
p->colorblue = 255;//27;
p->origin[0] = ent->origin[0] + r_avertexnormals[i][0]*64 + forward[0]*16;
p->origin[1] = ent->origin[1] + r_avertexnormals[i][1]*64 + forward[1]*16;
p->origin[2] = ent->origin[2] + r_avertexnormals[i][2]*64 + forward[2]*16;
p->velocity[0] = 0;
p->velocity[1] = 0;
p->velocity[2] = 0;
p->type = pt_static;
p->glow = true;
}
}
/*
===============
R_ParseParticleEffect
Parse an effect out of the server message
===============
*/
void R_ParseParticleEffect (void)
{
vec3_t origin, direction;
int count, color;
origin[0] = MSG_ReadCoord ();
origin[1] = MSG_ReadCoord ();
origin[2] = MSG_ReadCoord ();
direction[0] = MSG_ReadChar () * 0.0625;
direction[1] = MSG_ReadChar () * 0.0625;
direction[2] = MSG_ReadChar () * 0.0625;
count = MSG_ReadByte ();
color = MSG_ReadByte ();
R_RunParticleEffect (origin, direction, color, count);
}
/*
===================
R_ParticleExplosion
===================
*/
extern cvar_t sv_gravity;
void R_ParticleExplosion (vec3_t origin)
{
int i, contents;
particle_t *p;
contents = Mod_PointInLeaf(origin, cl.worldmodel)->contents;
for (i=0; i<64; i++)
{
p = addParticle();
if(!p)
{
return;
}
p->fade = -196;
p->growth = 16;
p->texcoords = smoke_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = 2;
p->bounce = 0;
p->gravity = 0;
p->colorred = 255;
p->colorgreen = rand() &255;
p->colorblue = 0;
p->origin[0] = origin[0] + (rand() &31) - 16;
p->origin[1] = origin[1] + (rand() &31) - 16;
p->origin[2] = origin[2] + (rand() &31) - 16;
p->velocity[0] = (rand() & 31) - 16;
p->velocity[1] = (rand() & 31) - 16;
p->velocity[2] = (rand() & 31) - 16;
p->type = pt_smokeexp;
p->glow = true;
}
for (i=0 ; i<256 ; i++)
{
p = addParticle();
if(!p)
{
return;
}
if ((contents == CONTENTS_EMPTY) || (contents == CONTENTS_SOLID))
{
p->fade = -128;
p->growth = -2;
p->texcoords = particle_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 1.5;
p->gravity = -0.5f * sv_gravity.value;
p->colorred = 255;
p->colorgreen = rand() &255;
p->colorblue = 0;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_explode;
p->glow = true;
}
else
{
p->fade = 0;
p->growth = 0;
p->texcoords = bubble_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = 0;
p->colorred = 127;
p->colorgreen = 127;
p->colorblue = 255;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_bubble;
p->glow = false;
}
}
}
/*
===================
R_ColoredExplosion
===================
*/
//Xsniper - Added RGB Colored Explosions
void R_ColoredExplosion (vec3_t origin, vec3_t colour)
{
int i, contents;
particle_t *p;
contents = Mod_PointInLeaf(origin, cl.worldmodel)->contents;
for (i=0; i<64; i++)
{
p = addParticle();
if(!p)
{
return;
}
p->fade = -196;
p->growth = 16;
p->texcoords = smoke_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = 2;
p->bounce = 0;
p->gravity = 0;
p->colorred = colour[0] * 255.0; //255;
p->colorgreen = colour[1] * 255.0; //rand() &255;
p->colorblue = colour[2] * 255.0; //0;
p->origin[0] = origin[0] + (rand() &31) - 16;
p->origin[1] = origin[1] + (rand() &31) - 16;
p->origin[2] = origin[2] + (rand() &31) - 16;
p->velocity[0] = (rand() & 31) - 16;
p->velocity[1] = (rand() & 31) - 16;
p->velocity[2] = (rand() & 31) - 16;
p->type = pt_smokeexp;
p->glow = true;
}
for (i=0 ; i<256 ; i++)
{
p = addParticle();
if(!p)
{
return;
}
if ((contents == CONTENTS_EMPTY) || (contents == CONTENTS_SOLID))
{
p->fade = -128;
p->growth = -2;
p->texcoords = particle_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 1.5;
p->gravity = -0.5f * sv_gravity.value;
p->colorred = colour[0] * 255.0; //255;
p->colorgreen = colour[1] * 255.0; //rand() &255;
p->colorblue = colour[2] * 255.0; //0;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_explode;
p->glow = true;
}
else
{
p->fade = 0;
p->growth = 0;
p->texcoords = bubble_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = 0;
p->colorred = colour[0] * 255.0; //127;
p->colorgreen = colour[1] * 255.0; //127;
p->colorblue = colour[2] * 255.0; //255;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_bubble;
p->glow = false;
}
}
}
//Xsniper - End
/*
====================
R_ColoredExplosion2
====================
*/
//Xsniper - Added RGB Color Support
void R_ColoredExplosion2 (vec3_t origin, vec3_t colour)
{
int i,contents;
particle_t *p;
contents = Mod_PointInLeaf(origin, cl.worldmodel)->contents;
for (i=0; i<384; i++)
{
p = addParticle();
if(!p)
{
return;
}
if ((contents == CONTENTS_EMPTY) ||
(contents == CONTENTS_SOLID))
{
p->fade = -128;
p->growth = -2;
p->texcoords = particle_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = -0.5f * sv_gravity.value;
p->colorred = colour[0] * 255.0;
p->colorgreen = colour[1] * 255.0;
p->colorblue = colour[2] * 255.0;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_explode;
p->glow = true;
}
else
{
p->fade = 0;
p->growth = 0;
p->texcoords = bubble_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = 0;
p->colorred = colour[0] * 255.0; //127;
p->colorgreen = colour[1] * 255.0; //127;
p->colorblue = colour[2] * 255.0; //255;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_bubble;
p->glow = false;
}
}
}
//Xsniper - End
/*
====================
R_ParticleExplosion2
====================
*/
void R_ParticleExplosion2 (vec3_t origin, int colorStart, int colorLength)
{
int i,contents;
particle_t *p;
int colorMod = 0;
byte *color;
contents = Mod_PointInLeaf(origin, cl.worldmodel)->contents;
for (i=0; i<384; i++)
{
p = addParticle();
if(!p)
{
return;
}
if ((contents == CONTENTS_EMPTY) ||
(contents == CONTENTS_SOLID))
{
color = (byte *) &d_8to24table[(int)colorStart + (colorMod % colorLength)];
colorMod++;
p->fade = -128;
p->growth = -2;
p->texcoords = particle_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = -0.5f * sv_gravity.value;
p->colorred = color[0];
p->colorgreen = color[1];
p->colorblue = color[2];
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_explode;
p->glow = true;
}
else
{
p->fade = 0;
p->growth = 0;
p->texcoords = bubble_coords;
p->contents = contents;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = 0;
p->colorred = 127;
p->colorgreen = 127;
p->colorblue = 255;
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_bubble;
p->glow = false;
}
}
}
/*
===============
R_BlobExplosion
===============
*/
void R_BlobExplosion (vec3_t origin)
{
int i;
particle_t *p;
byte *color;
for (i=0 ; i<384 ; i++)
{
p = addParticle();
if(!p)
{
return;
}
color = (byte *) &d_8to24table[(int)(rand() & 7) + 66];
p->fade = -128;
p->growth = -2;
p->texcoords = particle_coords;
p->contents = 0;
p->die = cl.time + 5;
p->time = 0;
p->alpha = 200;
p->scale = (rand() & 3) +1;
p->bounce = 0;
p->gravity = -0.5f * sv_gravity.value;
p->colorred = color[0];
p->colorgreen = color[1];
p->colorblue = color[2];
p->origin[0] = origin[0] + (rand() & 31) - 16;
p->origin[1] = origin[1] + (rand() & 31) - 16;
p->origin[2] = origin[2] + (rand() & 31) - 16;
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
p->type = pt_blob;
p->glow = true;
if (i & 1)
{
color = (byte *) &d_8to24table[(int)(rand() & 7) + 150];
p->colorred = color[0];
p->colorgreen = color[1];
p->colorblue = color[2];
p->type = pt_blob2;
}
}
}
/*
===============
R_RunParticleEffect
===============
*/
void R_RunParticleEffect (vec3_t origin, vec3_t direction, int color, int count)
{
int i, contents;
particle_t *p;
byte *color24;
if (count == 128)
{
for (i=0 ; i<count ; i++)
{ // rocket explosion
p = addParticle();
if(!p)
{
return;
}
contents = Mod_PointInLeaf(p->origin, cl.worldmodel)->contents;
p->scale = 2;
p->alpha = 200;
p->die = cl.time + 5;
if ((contents == CONTENTS_EMPTY) ||
(contents == CONTENTS_SOLID))
{
p->texcoords = particle_coords;
p->bounce = 0;
p->colorred = 255;
p->colorgreen = 243;
p->colorblue = 147;
p->fade = -128;
p->growth = -2;
p->gravity = -0.5f * sv_gravity.value;
p->type = pt_explode;
p->glow = true;
}
else
{
p->texcoords = bubble_coords;
p->bounce = 0;
p->colorred = 127;
p->colorgreen = 127;
p->colorblue = 255;
p->fade = 0;
p->growth = 0;
p->gravity = 0;
p->type = pt_bubble;
p->glow = false;
}
p->origin[0] = origin[0] + ((rand() & 31) - 16);
p->origin[1] = origin[1] + ((rand() & 31) - 16);
p->origin[2] = origin[2] + ((rand() & 31) - 16);
p->velocity[0] = (rand() & 511) - 256;
p->velocity[1] = (rand() & 511) - 256;
p->velocity[2] = (rand() & 511) - 256;
}
return;
}
for (i=0 ; i<count ; i++)
{
p = addParticle();
if(!p)
{
return;
}
p->texcoords = blood_coords;
p->bounce = 0;
p->scale = 2;
p->alpha = 200;
p->die = cl.time + 5;
color24 = (byte *) &d_8to24table[(int)(rand() & 3) + color];
p->colorred = color24[0];
p->colorgreen = color24[1];
p->colorblue = color24[2];
p->growth = 0;
p->fade = -64;
p->gravity = -0.5f * sv_gravity.value;
p->type = pt_blood;
p->glow = false;
p->origin[0] = origin[0] + ((rand() & 15) - 8);
p->origin[1] = origin[1] + ((rand() & 15) - 8);
p->origin[2] = origin[2] + ((rand() & 15) - 8);
p->velocity[0] = direction[0] * 15;
p->velocity[1] = direction[1] * 15;
p->velocity[2] = direction[2] * 15;
}
}
/*
===============
R_SparkShower
===============
*/
void R_SparkShower (vec3_t origin, vec3_t direction)
{
int i, contents;
particle_t *p;
p = addParticle();
if (!free_particles)
{
return;
}
contents = Mod_PointInLeaf(p->origin, cl.worldmodel)->contents;
if ((contents == CONTENTS_EMPTY) ||
(contents == CONTENTS_SOLID))
{
p->scale = 2;
p->alpha = 200;
p->texcoords = smoke_coords;
p->bounce = 0;
p->type = pt_bulletpuff;
p->glow = false;
p->colorred = 187;
p->colorgreen = 187;
p->colorblue = 187;
p->fade = -255;
p->growth = 16;
p->gravity = 0;
p->die = cl.time + 5;
p->origin[0] = origin[0];
p->origin[1] = origin[1];
p->origin[2] = origin[2];
p->velocity[0] = (rand() & 7) - 4;
p->velocity[1] = (rand() & 7) - 4;
p->velocity[2] = (rand() & 7) - 4;
}
for (i=0 ; i<10 ; i++)
{
p = addParticle();
if(!p)
{
return;
}
contents = Mod_PointInLeaf(p->origin, cl.worldmodel)->contents;
p->scale = (rand() & 3) +1;
p->alpha = 200;
p->die = cl.time + 5;
if ((contents == CONTENTS_EMPTY) ||
(contents == CONTENTS_SOLID))
{
p->texcoords = particle_coords;
p->bounce = 1.5;
p->colorred = 255;
p->colorgreen = 243;
p->colorblue = 147;
p->fade = -128;
p->growth = -2;
p->gravity = -0.5f * sv_gravity.value;
p->type = pt_explode;
p->glow = true;
}
else
{
p->texcoords = bubble_coords;
p->bounce = 0;
p->colorred = 127;
p->colorgreen = 127;
p->colorblue = 255;
p->fade = 0;
p->growth = 0;
p->gravity = 0;
p->type = pt_bubble;
p->glow = false;
}
p->origin[0] = origin[0] + ((rand() & 7) - 4);
p->origin[1] = origin[1] + ((rand() & 7) - 4);
p->origin[2] = origin[2] + ((rand() & 7) - 4);
p->velocity[0] = direction[0] + (rand() & 127) - 64;
p->velocity[1] = direction[1] + (rand() & 127) - 64;
p->velocity[2] = direction[2] + (rand() & 127) - 64;
}
}
/*
===============
R_LavaSplash
===============
*/
void R_LavaSplash (vec3_t origin)
{
int i, j;
particle_t *p;
for (i=-16 ; i<16 ; i++)
{
for (j=-16 ; j<16 ; j++)
{
p = addParticle();
if(!p)
{
return;
}
p->texcoords = particle_coords;
p->bounce = 0;
p->scale = 5;
p->alpha = 255;
p->die = cl.time + 10;
p->fade = -64;
p->growth = 0;
p->gravity = -0.1f * sv_gravity.value;
p->colorred = 163;
p->colorgreen = 39;
p->colorblue = 11;
p->type = pt_grav;
p->glow = true;
p->velocity[0] = (rand() & 7) + (j * 8);
p->velocity[1] = (rand() & 7) + (i * 8);
p->velocity[2] = 256;
p->origin[0] = origin[0] + (rand() & 7) + (j * 8);
p->origin[1] = origin[1] + (rand() & 7) + (i * 8);
p->origin[2] = origin[2] + (rand() & 63);
}
}
}
/*
===============
R_TeleportSplash
===============
*/
void R_TeleportSplash (vec3_t origin)
{
int i, j, k;
particle_t *p;
for (i=-16 ; i<16 ; i+=4)
{
for (j=-16 ; j<16 ; j+=4)
{
for (k=-24 ; k<32 ; k+=4)
{
p = addParticle();
if(!p)
{
return;
}
p->texcoords = particle_coords;
p->bounce = 0;
p->scale = 2;
p->alpha = 200;
p->die = cl.time + 1;
p->gravity = -0.05f * sv_gravity.value;
p->colorred = 255;
p->colorgreen = 255;
p->colorblue = 255;
p->fade = -255;
p->type = pt_fade;
p->glow = true;
p->origin[0] = origin[0] + i + (rand() & 7);
p->origin[1] = origin[1] + j + (rand() & 7);
p->origin[2] = origin[2] + k + (rand() & 7);
p->velocity[0] = i*2 + (rand() & 31) - 16;
p->velocity[1] = j*2 + (rand() & 31) - 16;
p->velocity[2] = k*2 + (rand() & 31) + 24;
}
}
}
}
void R_LightningTrail (vec3_t start, vec3_t end)
{
vec3_t vec;
float len;
particle_t *p;
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
VectorScale (vec, 2, vec);
while (len > 0)
{
p = addParticle();
if(!p)
{
return;
}
p->alpha = 255;
p->scale = 3;
p->die = cl.time + 1;
p->glow = true;
p->colorred = 0;
p->colorgreen = 0;
p->colorblue = 255;
p->fade = -512;
p->growth = 0;
p->gravity = 0;
p->type = pt_rail;
p->texcoords = particle_coords;
p->bounce = 0;
p->origin[0] = start[0];
p->origin[1] = start[1];
p->origin[2] = start[2];
p->velocity[0] = 0;
p->velocity[1] = 0;
p->velocity[2] = 0;
len--;
VectorAdd (start, vec, start);
}
}
void R_RocketTrail (vec3_t start, vec3_t end, entity_t *ent)
{
particle_t *p;
vec3_t velocity;
int contents;
contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
return;
if (cl.time > ent->time_left)
{
p = addParticle();
if(!p)
return;
if (contents == CONTENTS_EMPTY || contents == CONTENTS_SOLID)
{
velocity[0] = (rand() & 15) - 8;
velocity[1] = (rand() & 15) - 8;
velocity[2] = (rand() & 31) + 15;
AssignPartStuff (p, smoke_coords, cl.time + 10, 0, 255, 2, 0, 0,
-255, 16, contents, 187, 187, 187, start, velocity, pt_smoke, false);
}
else
{
velocity[0] = 0;
velocity[1] = 0;
velocity[2] = 20;
AssignPartStuff (p, bubble_coords, cl.time + 10, 0, 200, (rand() & 3) +1, 0, 0,
0, 0, contents, 127, 127, 255, start, velocity, pt_bubble, false);
}
ent->time_left = cl.time + 0.01;
}
}
void R_BloodTrail (vec3_t start, vec3_t end, entity_t *ent)
{
particle_t *p;
byte *color;
if (cl.time > ent->time_left)
{
p = addParticle();
if(!p)
{
return;
}
p->die = cl.time + 10;
color = (byte *) &d_8to24table[(int)(rand() & 3) + 68];
p->colorred = color[0];
p->colorgreen = color[1];
p->colorblue = color[2];
p->fade = -128;
p->gravity = -0.5f * sv_gravity.value;
p->alpha = 200;
p->scale = 4;
p->texcoords = blood_coords;
p->bounce = 0;
p->type = pt_blood;
p->glow = false;
p->velocity[0] = (rand() & 15) - 8;
p->velocity[1] = (rand() & 15) - 8;
p->velocity[2] = (rand() & 15) - 8;
p->origin[0] = start[0] + ((rand() & 3) - 2);
p->origin[1] = start[1] + ((rand() & 3) - 2);
p->origin[2] = start[2] + ((rand() & 3) - 2);
ent->time_left = cl.time + 0.05;
}
}
void R_TracerTrail (vec3_t start, vec3_t end, entity_t *ent, byte color)
{
vec3_t vec;
static int tracercount;
particle_t *p;
byte *color24;
float len;
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
VectorScale (vec, 2, vec);
while (len > 0)
{
p = addParticle();
if(!p)
return;
VectorCopy (start, p->origin);
if (color == 77)
{
p->fade = -1024;
p->growth = 2;
}
else
{
p->fade = -512;
p->growth = 0;
}
p->time = 0;
p->gravity = 0;
p->die = cl.time + 5;
if (color == 63)
{
p->colorred = 0;
p->colorgreen = 255;
p->colorblue = 0;
p->scale = 5;
}
else if (color == 77)
{
p->colorred = 79;
p->colorgreen = 151;
p->colorblue = 227;
p->scale = 7;
}
else
{
color24 = (byte *) &d_8to24table[(int)color];
p->colorred = color24[0];
p->colorgreen = color24[1];
p->colorblue = color24[2];
p->scale = 5;
}
p->alpha = 255;
p->texcoords = particle_coords;
p->bounce = 0;
p->type = pt_static;
p->glow = true;
p->velocity[0] = 0;
p->velocity[1] = 0;
p->velocity[2] = 0;
len--;
VectorAdd (start, vec, start);
}
}
void R_VoorTrail (vec3_t start, vec3_t end, entity_t *ent)
{
particle_t *p;
if (cl.time > ent->time_left)
{
p = addParticle();
if(!p)
return;
p->die = cl.time + 5;
p->colorred = 187;
p->colorgreen = 115;
p->colorblue = 159;
p->fade = -128;
p->gravity = -0.05f * sv_gravity.value;
p->alpha = 200;
p->scale = 5;
p->texcoords = particle_coords;
p->bounce = 0;
p->type = pt_fade;
p->glow = true;
p->velocity[0] = (rand() & 15) - 8;
p->velocity[1] = (rand() & 15) - 8;
p->velocity[2] = (rand() & 15) - 8;
p->origin[0] = start[0] + ((rand() & 3) - 2);
p->origin[1] = start[1] + ((rand() & 3) - 2);
p->origin[2] = start[2] + ((rand() & 3) - 2);
ent->time_left = cl.time + 0.05;
}
}
/*
======
R_Fire
======
*/
void R_Fire (entity_t *ent, qboolean fire2)
{
particle_t *p;
if( cl.time + 2 < ent->time_left )
{
ent->time_left = 0;
}
if (cl.time > ent->time_left)
{
p = addParticle();
if(!p)
{
return;
}
p->die = cl.time + 5;
p->colorred = 227;
p->colorgreen = 151;
p->colorblue = 79;
p->fade = -128;
p->growth = -2;
p->gravity = 0.05f * sv_gravity.value;
p->alpha = 128;
p->scale = 10;
p->texcoords = particle_coords;
p->bounce = 0;
p->type = pt_fire;
p->glow = true;
p->velocity[0] = (rand() & 3) - 2;
p->velocity[1] = (rand() & 3) - 2;
p->velocity[2] = 0;
p->origin[0] = ent->origin[0];
p->origin[1] = ent->origin[1];
p->origin[2] = ent->origin[2] + 4;
if (fire2)
{
p->origin[2] = ent->origin[2] - 2;
if (ent->frame)
{
p->scale = 30;
p->velocity[0] = (rand() & 7) - 4;
p->velocity[1] = (rand() & 7) - 4;
p->velocity[2] = 0;
p->fade = -128;
p->growth = -4;
p->gravity = 0.1f * sv_gravity.value;
p->type = pt_fire2;
}
}
ent->time_left = cl.time + 0.05;
}
}
// New Fire Begin - Xsniper
/*
======
R_BlueFire
======
*/
void R_BlueFire (entity_t *ent, qboolean fire2)
{
particle_t *p;
if( cl.time + 2 < ent->time_left )
{
ent->time_left = 0;
}
if (cl.time > ent->time_left)
{
p = addParticle();
if(!p)
{
return;
}
p->die = cl.time + 5;
p->colorred = 79;
p->colorgreen = 151;
p->colorblue = 227;
p->fade = -128;
p->growth = -2;
p->gravity = 0.05f * sv_gravity.value;
p->alpha = 128;
p->scale = 10;
p->texcoords = particle_coords;
p->bounce = 0;
p->type = pt_fire;
p->glow = true;
p->velocity[0] = (rand() & 3) - 2;
p->velocity[1] = (rand() & 3) - 2;
p->velocity[2] = 0;
p->origin[0] = ent->origin[0];
p->origin[1] = ent->origin[1];
p->origin[2] = ent->origin[2] + 4;
if (fire2)
{
p->origin[2] = ent->origin[2] - 2;
if (ent->frame)
{
p->scale = 30;
p->velocity[0] = (rand() & 7) - 4;
p->velocity[1] = (rand() & 7) - 4;
p->velocity[2] = 0;
p->fade = -128;
p->growth = -4;
p->gravity = 0.1f * sv_gravity.value;
p->type = pt_fire2;
}
}
ent->time_left = cl.time + 0.05;
}
}
// New Fire End - Xsniper
#define DIST_EPSILON (0.03125)
int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
qboolean detectCollision( int num, vec3_t start, vec3_t end, vec3_t impact, vec3_t normal )
{
dclipnode_t *node, *nodes = cl.worldmodel->hulls->clipnodes;
mplane_t *plane, *planes = cl.worldmodel->hulls->planes;
float t1, t2;
float frac;
vec3_t mid;
int side;
qboolean t1neg, t2neg;
while( num >= 0 )
{
t1neg = false;
t2neg = false;
node = nodes + num;
plane = planes + node->planenum;
t1 = PlaneDiff(start, plane);
t2 = PlaneDiff(end, plane);
if( t1 < 0 )
{
t1neg = true;
}
if( t2 < 0 )
{
t2neg = true;
}
if( !t1neg && !t2neg )
{
num = node->children[0];
continue;
}
if( t1neg && t2neg )
{
num = node->children[1];
continue;
}
if( t1neg )
{
frac = (t1 + DIST_EPSILON)/(t1-t2);
}
else
{
frac = (t1 - DIST_EPSILON)/(t1-t2);
}
if(frac < 0)
{
frac = 0;
}
if(frac > 1)
{
frac = 1;
}
mid[0] = start[0] + frac*(end[0] - start[0]);
mid[1] = start[1] + frac*(end[1] - start[1]);
mid[2] = start[2] + frac*(end[2] - start[2]);
side = ( t1 < 0 );
if( detectCollision( node->children[side], start, mid, impact, normal ) )
{
return true;
}
if( SV_HullPointContents( cl.worldmodel->hulls, node->children[side^1], mid ) != CONTENTS_SOLID )
{
num = node->children[ side^1 ];
VectorCopy (mid, start);
continue;
}
if( !side )
{
VectorCopy (plane->normal, normal);
}
else
{
VectorNegate (plane->normal, normal);
}
VectorCopy (mid, impact);
return true;
}
return false;
}
void R_MoveParticles( void )
{
particle_t *p = active_particles;
float frametime = cl.time - cl.oldtime;
float dist;
vec3_t impact, normal, oldorigin;
while (p)
{
if ((p->die < cl.time) || (!gl_particles.value))
{
p = remParticle (p);
continue;
}
VectorCopy (p->origin, oldorigin);
p->origin[0] += p->velocity[0] * frametime;
p->origin[1] += p->velocity[1] * frametime;
p->origin[2] += p->velocity[2] * frametime;
p->alpha += frametime * p->fade;
p->scale += frametime * p->growth;
if (p->alpha <= 0.0f || p->scale <= 0.0f)
{
p = remParticle (p);
continue;
}
p->contents = Mod_PointInLeaf(p->origin, cl.worldmodel)->contents;
if ((p->contents == CONTENTS_SKY) ||
((p->contents == CONTENTS_SOLID && !p->bounce)) ||
((p->contents == CONTENTS_EMPTY) && (p->type & pt_bubble)) ||
((p->contents != CONTENTS_EMPTY) && (p->contents != CONTENTS_SOLID) && (p->type & (pt_explode | pt_bulletpuff | pt_smokeexp))))
{
p = remParticle (p);
continue;
}
p->velocity[2] += frametime * p->gravity;
if (p->type == pt_bubble)
{
p->velocity[0] = (rand() & 15) - 8;
p->velocity[1] = (rand() & 15) - 8;
p->velocity[2] = (rand() & 31) + 64;
}
if (p->bounce)
{
if (detectCollision (0, oldorigin, p->origin, impact, normal))
{
VectorCopy (impact, p->origin);
dist = DotProduct (p->velocity, normal) * -p->bounce;
VectorMA (p->velocity, dist, normal, p->velocity);
if( DotProduct (p->velocity, p->velocity) < 0.03 )
{
VectorClear (p->velocity);
p = remParticle (p);
}
}
}
p = p->next;
}
}
void R_DrawParticles (void)
{
byte alpha;
vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f};
vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f};
vec3_t coord[4];
particle_t *p = active_particles;
if( !p )
return;
VectorAdd (up, right, coord[0]);
VectorSubtract (right, up, coord[1]);
VectorNegate (coord[0], coord[2]);
VectorNegate (coord[1], coord[3]);
glBindTexture (GL_TEXTURE_2D, part_font);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDepthMask (false);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
while (p)
{
alpha = p->alpha;
glColor4ub (p->colorred, p->colorgreen, p->colorblue, alpha);
glPushMatrix ();
{
glTranslatef (p->origin[0], p->origin[1], p->origin[2]);
glScalef (p->scale, p->scale, p->scale);
glBegin (GL_QUADS);
{
glTexCoord2f (p->texcoords[1], p->texcoords[2]); glVertex3fv (coord[0]);
glTexCoord2f (p->texcoords[1], p->texcoords[3]); glVertex3fv (coord[1]);
glTexCoord2f (p->texcoords[0], p->texcoords[3]); glVertex3fv (coord[2]);
glTexCoord2f (p->texcoords[0], p->texcoords[2]); glVertex3fv (coord[3]);
}
glEnd ();
}
glPopMatrix ();
p = p->next;
}
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDepthMask (true);
glColor4f (1,1,1,1);
}