Files
illusion-arena-engine/code/renderer_oa/tr_particles.c
leilei- 245fea051e Renderer-based particle system (#25)
* A WIP particle system

* - Some more particle refactoring
- an attempt to fix things that went wrong
- trying to integrate fog onto particles (which is currently wrong)
- qpal.h committed (oops)
- Attempt to separate particle rendering from particle moving for future optimization/refactor
2016-11-01 03:30:15 -04:00

3172 lines
84 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "qpal.h"
#include "../qcommon/cm_local.h"
#include "../qcommon/cm_public.h"
//
// LEILEI'S PARTICLES!
//
// partially ported out of cg_marks.c
// and heavily improved upon
#define BLOODRED 2
#define EMISIVEFADE 3
#define GREY75 4
#define BLOODRED 2
#define EMISIVEFADE 3
#define LFXSTUFF 1
#define LFXSHOCK 2
#define LFXSMOKE 3
#define LFXSPARK 4
#define LFXBURST 5
#define LFXLIQUID 6
#define LFXSTRAND 7
#define LFXTRAIL 8
#define LFXBUBBLE 9
#define LFXQUAKE 10
// color types
#define P_LFX 1 // ramp
#define P_LFXSIMPLE 2 // solid color
#define P_INDEXED 3 // indexed color from qpal
#define MAX_TRAIL_POINTS 8
#define TRAIL_LENGTH_SPLIT 64
typedef struct particle_s
{
struct particle_s *next;
float time;
float endtime;
vec3_t org;
vec3_t vel;
vec3_t accel;
int color;
float colorvel;
float alpha;
float alphavel;
int type;
shader_t *pshader;
float height;
float width;
float endheight;
float endwidth;
float start;
float end;
float startfade;
qboolean rotate;
int snum;
qboolean link;
// Ridah
int shaderAnim;
int roll;
int accumroll;
// leilei
float stretch;
vec3_t angle;
vec3_t avelocity;
vec3_t src;
vec3_t dest;
float airfriction;
float rollfriction;
int qolor; // quake palette color translation
int ramp; // quake color ramping (rocket trails, explosion)
float cols[4][5]; // fading color cycle
vec3_t dir; // angle, direction
float rollvel; // velocity of roll
float bounce; // how much elasticity does it have
vec3_t torg[MAX_TRAIL_POINTS]; // extra origins to use for trails and bursts
int active_trail; // how many trail points are active on this trail
int bubbleit; // turn into a bubble when crossing into water.
int material; // kind of material it is?
float die; // quake translation
int rendertype; // particle type (spark, oriented, etc)
int colortype; // color type (ramp, palette, singular)
int fogNum;
} particle_t;
void R_AddParticleToScene (particle_t *p, vec3_t org, float alpha);
void R_LetsBounce ( particle_t *p);
// Shaders
static shader_t *addshock;
static shader_t *subshock;
static shader_t *modshock;
static shader_t *alfshock;
static shader_t *addball;
static shader_t *subball;
static shader_t *modball;
static shader_t *alfball;
static shader_t *blood1;
static shader_t *blood2;
static shader_t *watsplash;
static shader_t *watburst;
static shader_t *watbubble;
static shader_t *fireball;
static shader_t *addsmoke;
static shader_t *subsmoke;
static shader_t *modsmoke;
static shader_t *alfsmoke;
#define MAX_ENTITIES 500
// more quake stuff
static int ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 };
static int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 };
static int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 };
typedef enum
{
P_NONE,
P_WEATHER,
P_FLAT,
P_SMOKE,
P_ROTATE,
P_WEATHER_TURBULENT,
P_ANIM, // Ridah
P_BAT,
P_BLEED,
P_FLAT_SCALEUP,
P_FLAT_SCALEUP_FADE,
P_WEATHER_FLURRY,
P_SMOKE_IMPACT,
P_BUBBLE,
P_BUBBLE_TURBULENT,
P_SPRITE,
P_BEAM, // leilei - angle not calculated
P_SPARK, // leilei - angle and length recalculated from velocity
P_QUAKESTATIC,
P_QUAKEGRAV,
P_QUAKESLOWGRAV,
P_QUAKEFIRE,
P_QUAKEEXPLODE,
P_QUAKEEXPLODE2,
P_QUAKEBLOB,
P_QUAKEBLOB2,
P_QUAKE
} particle_type_t;
#define MAX_SHADER_ANIMS 32
#define MAX_SHADER_ANIM_FRAMES 64
static int numShaderAnims;
// done.
#define PARTICLE_GRAVITY 40
#define MAX_PARTICLES 2048 // 1000000 // we can do CRAZY amounts of particles. but let's be sensible
particle_t *active_particles, *free_particles;
particle_t particles[MAX_PARTICLES];
int cl_numparticles = MAX_PARTICLES;
qboolean initparticles = qfalse;
static vec3_t pvforward, pvright, pvup;
static vec3_t rforward, rright, rup;
static float oldTime;
static float THEtime;
// lazy struct hack to make quake code backporting quicker and painless
typedef struct
{
double time;
} imlazy_t;
static imlazy_t cl;
#define pt_grav P_QUAKEGRAV
#define pt_slowgrav P_QUAKESLOWGRAV
#define pt_static P_QUAKESTATIC
#define pt_explode P_QUAKEEXPLODE
#define pt_explode2 P_QUAKEEXPLODE2
#define pt_blob P_QUAKEBLOB
#define pt_blob2 P_QUAKEBLOB2
#define pt_fire P_QUAKEFIRE
void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs,
clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere );
static void P_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
int skipNumber, int mask ) {
CM_Trace(result, start, end, NULL, NULL, 0, start, mask, 0, NULL);
}
/*
===============
R_ClearParticles
===============
*/
void R_ClearParticles (void)
{
int i;
memset( particles, 0, sizeof(particles) );
free_particles = &particles[0];
active_particles = NULL;
for (i=0 ;i<cl_numparticles ; i++)
{
particles[i].next = &particles[i+1];
particles[i].type = 0;
}
particles[cl_numparticles-1].next = NULL;
oldTime = THEtime;
numShaderAnims = i;
initparticles = qtrue;
}
/*
=====================
R_AddParticleToScene
=====================
*/
void R_AddParticleToScene (particle_t *p, vec3_t org, float alpha)
{
vec3_t point;
float width;
float height;
float time, time2;
float ratio;
int fogNum;
float invratio;
vec3_t color;
time = 0; invratio = 0; // shut up gcc
VectorSet (color, p->cols[0][0], p->cols[1][0], p->cols[2][0]);
THEtime = backEnd.refdef.time;
// qarticle transitions
cl.time = THEtime / 10; // quarticles
time = THEtime- p->time;
time2 = p->endtime - p->time;
ratio = time / time2;
// Do us some fogging fogger
{
byte fogFactors[3] = {255, 255, 255};
if(tr.world && p->fogNum > 0 && p->fogNum < tr.world->numfogs)
{
tess.numVertexes = 1;
VectorCopy(org, tess.xyz[0]);
tess.fogNum = p->fogNum;
RB_CalcModulateColorsByFog(fogFactors);
}
}
{// create a front rotating facing polygon
// that can change colors
// and........ something.
vec3_t rr, ru;
vec3_t rotate_ang;
if (p->colortype == P_LFX){ // Ramp
// hack to prevent that one long particle from going crazy in the world.
if (p->startfade > THEtime){
p->bounce = 0; p->bubbleit = 0; //no cpu expensive checks
return;
}
if (THEtime> p->startfade)
{
float inv1,inv2,inv3,inv4;
invratio = 1 - ( (THEtime- p->startfade) / (p->endtime - p->startfade) );
inv1 = invratio * 4.0;
inv2 = invratio * 4.0 - 1;
inv3 = invratio * 4.0 - 2;
inv4 = invratio * 4.0 - 3;
if (inv1 > 1.0f) inv1 = 1.0f;
if (inv2 > 1.0f) inv2 = 1.0f;
if (inv3 > 1.0f) inv3 = 1.0f;
if (inv4 > 1.0f) inv4 = 1.0f;
{
int et;
vec4_t fcol;
for(et=0;et<4;et++)
{
if (invratio < 0.25f)
fcol[et] = (p->cols[et][3] * inv1) + (p->cols[et][4] * (1 - inv1));
else if (invratio < 0.50f)
fcol[et] = (p->cols[et][2] * inv2) + (p->cols[et][3] * (1 - inv2));
else if (invratio < 0.75f)
fcol[et] = (p->cols[et][1] * inv3) + (p->cols[et][2] * (1 - inv3));
else
fcol[et] = (p->cols[et][0] * inv4) + (p->cols[et][1] * (1 - inv4));
}
for(et=0;et<4;et++){
if (fcol[et]>1)fcol[et]=1.0f;
if (fcol[et]<0)fcol[et]=0.0f;
}
color[0] = fcol[0];
color[1] = fcol[1];
color[2] = fcol[2];
color[3] = fcol[3];
}
}
if (invratio > 4)
invratio = 4;
}
else if (p->colortype = P_INDEXED)
{
VectorSet(color, qpalette[p->qolor][0], qpalette[p->qolor][1], qpalette[p->qolor][2]);
color[3] = 1.0f;
}
else // simple
{
invratio = 1;
color[0] = p->cols[0][0];
color[1] = p->cols[1][0];
color[2] = p->cols[2][0];
color[3] = p->alpha;
}
if (p->rendertype == LFXSHOCK)
{ // ORIENTED sprite - used for shockwaves, water waves, waves, etc.
vec3_t argles;
vec3_t right, up;
int ind=0;
vectoangles( p->dir, argles );
AngleVectors ( argles, NULL, right, up);
width = p->width + ( ratio * ( p->endwidth - p->width) );
height = p->height + ( ratio * ( p->endheight - p->height) );
if (p->roll) {
vectoangles( p->dir, rotate_ang );
rotate_ang[ROLL] += p->roll;
AngleVectors ( rotate_ang, NULL, right, up);
}
RB_BeginSurface( p->pshader, fogNum );
VectorMA (org, -height, right, point);
VectorMA (point, -width, up, point);
VectorCopy (point, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( point, 2*height, up, point);
VectorCopy (point, tess.xyz[tess.numVertexes]);
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( point, 2*width, right, point );
VectorCopy (point, tess.xyz[tess.numVertexes]);
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( point, -2*height, up, point );
VectorCopy (point, tess.xyz[tess.numVertexes]);
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
ind+=4;
RB_EndSurface();
}
else if (p->rendertype == LFXSPARK)
{ // STRETCHY SPARK sprite - used for sparks etc
vec3_t argles;
vec3_t right, up, fwd;
vec3_t line;
float len, begin, end;
vec3_t start, finish;
int ind=0;
vec3_t oldorgstretch;
vectoangles( p->dir, argles );
AngleVectors ( argles, NULL, right, up);
// Set up the 'beam'
oldorgstretch[0] = org[0] + ((p->vel[0] ) * 0.005);
oldorgstretch[1] = org[1] + ((p->vel[1]) * 0.005);
oldorgstretch[2] = org[2] + ((p->vel[2] ) * 0.005);
VectorSubtract( org, oldorgstretch, fwd );
len = VectorNormalize( fwd );
//len = DotProduct(p->vel);// * (5 / (THEtime- oldTime)) ;
len *= p->height + p->width;
len *= 7; // doesn't look good in low framerates :/
begin = -len / 2;
end = len / 2;
// Set up the particle
width = p->width + ( ratio * ( p->endwidth - p->width) );
height = p->height + ( ratio * ( p->endheight - p->height) );
VectorMA( org, begin, fwd, start );
VectorMA( org, end, fwd, finish );
line[0] = DotProduct( fwd, backEnd.refdef.viewaxis[1] );
line[1] = DotProduct( fwd, backEnd.refdef.viewaxis[2] );
VectorScale( backEnd.refdef.viewaxis[1], line[1], right );
VectorMA( right, -line[0], backEnd.refdef.viewaxis[2], right );
VectorNormalize( right );
RB_BeginSurface( p->pshader, fogNum );
VectorMA( finish, width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( finish, -width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( start, -width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( start, width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
ind+=4;
RB_EndSurface();
// center glow of softness? Enable for 2002 particleset?
}
else if (p->rendertype == LFXBURST)
{ // STRETCHY BURST sprite - used for explosions
// like spark but origin doesnt change. it just keeps stretching
// from where it was spawned.
vec3_t argles;
vec3_t right, up, fwd;
vec3_t line;
float len, begin, end;
vec3_t start, finish;
int ind=0;
vec3_t oldorgstretch;
vectoangles( p->dir, argles );
AngleVectors ( argles, NULL, right, up);
// Set up the 'beam'
oldorgstretch[0] = p->torg[0][0];
oldorgstretch[1] = p->torg[0][1];
oldorgstretch[2] = p->torg[0][2];
VectorSubtract( org, oldorgstretch, fwd );
len = VectorNormalize( fwd );
//len = DotProduct(p->vel);// * (5 / (THEtime- oldTime)) ;
len *= p->height + p->width;
len *= 1; // doesn't look good in low framerates :/
begin = 0;
end = len;
// Set up the particle
width = p->width + ( ratio * ( p->endwidth - p->width) );
height = p->height + ( ratio * ( p->endheight - p->height) );
VectorMA( org, begin, fwd, start );
VectorMA( org, end, fwd, finish );
line[0] = DotProduct( fwd, backEnd.refdef.viewaxis[1] );
line[1] = DotProduct( fwd, backEnd.refdef.viewaxis[2] );
VectorScale( backEnd.refdef.viewaxis[1], line[1], right );
VectorMA( right, -line[0], backEnd.refdef.viewaxis[2], right );
VectorNormalize( right );
RB_BeginSurface( p->pshader, fogNum );
VectorMA( finish, width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( finish, -width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( start, -width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
VectorMA( start, width, right, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
ind+=4;
RB_EndSurface();
}
else if (p->rendertype == LFXTRAIL)
{ // STRETCHY TRAIL sprite - used for..... i dunno
// like burst but splits into more trails when the certain length is achieved
// TO RETURN
}
else
// VP PARALLEL sprite
{
// trace_t pt1, pt2, pt3, pt4;
// float avgfrac;
int ind=0;
width = p->width + ( ratio * ( p->endwidth - p->width) );
height = p->height + ( ratio * ( p->endheight - p->height) );
if (p->roll) {
vectoangles( backEnd.refdef.viewaxis[0], rotate_ang );
rotate_ang[ROLL] += p->roll;
AngleVectors ( rotate_ang, NULL, rr, ru);
}
if (p->roll) {
VectorMA (org, -height, ru, point);
VectorMA (point, -width, rr, point);
} else {
VectorMA (org, -height, pvup, point);
VectorMA (point, -width, pvright, point);
}
// Faded clipping test. we don't need dx10 after all :)
RB_BeginSurface( p->pshader, fogNum );
VectorCopy (point, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
if (p->roll) {
VectorMA (point, 2*height, ru, point);
} else {
VectorMA (point, 2*height, pvup, point);
}
VectorCopy (point, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
if (p->roll) {
VectorMA (point, 2*width, rr, point);
} else {
VectorMA (point, 2*width, pvright, point);
}
VectorCopy (point, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
if (p->roll) {
VectorMA (point, -2*height, ru, point);
} else {
VectorMA (point, -2*height, pvup, point);
}
VectorCopy (point, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255 * color[0];
tess.vertexColors[tess.numVertexes][1] = 255 * color[1];
tess.vertexColors[tess.numVertexes][2] = 255 * color[2];
tess.vertexColors[tess.numVertexes][3] = 255 * invratio;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
ind+=4;
RB_EndSurface();
}
}
if (!p->pshader) {
// force a shader.
p->pshader = alfball;
return;
}
}
static float roll = 0.0;
#define MINe(p,q) ((p <= q) ? p : q)
int reallyactive;
void R_AddParticles (void)
{
particle_t *p, *next;
float alpha;
float time, time2;
vec3_t oldorg; // leilei
particle_t *active, *tail;
vec3_t rotate_ang;
float frametime;
float time3;
float time1;
float dvel;
float grav;
float f;
int intheworld = 0;
if (!initparticles)
R_ClearParticles ();
// This is supposed to prevent excessive calculations, but it's buggy and not working properly and conflicts
// with the hud, of all things
// leilei - quake time stuf
frametime = THEtime- oldTime;
frametime *= 0.001;
time3 = frametime * 15;
time2 = frametime * 10; // 15;
time1 = frametime * 5;
//grav = frametime * -800;
grav = PARTICLE_GRAVITY;
dvel = 4*frametime;
time = frametime;
VectorCopy( backEnd.refdef.viewaxis[0], pvforward );
VectorCopy( backEnd.refdef.viewaxis[1], pvright );
VectorCopy( backEnd.refdef.viewaxis[2], pvup );
vectoangles( backEnd.refdef.viewaxis[0], rotate_ang );
roll += ((THEtime- oldTime) * 0.1) ;
rotate_ang[ROLL] += (roll*0.9);
AngleVectors ( rotate_ang, rforward, rright, rup);
oldTime = THEtime;
active = NULL;
tail = NULL;
// Intended to keep physics calculations under control, but it doens't work properly. :(
//if ((!backEnd.doneParticles) && !(tr.refdef.rdflags & RDF_NOWORLDMODEL))
for (p=active_particles ; p ; p=next)
{
next = p->next;
//time = (THEtime- p->time)*0.001;
VectorCopy(p->org, oldorg);
// if we're told to die, it's most likely a quake particle.
if (p->die)
{
int scal = 2.6f;
p->endtime = THEtime + (p->die);
p->die = 0;
p->height= scal;
p->width= scal;
p->endheight= scal;
p->endwidth= scal;
p->bounce = 0;
p->bubbleit = 0;
// ri.Printf( PRINT_ALL, "boung!");
p->colortype = P_INDEXED;
p->alpha = 1;
p->qolor = p->color;
p->time = THEtime;
p->startfade = THEtime;
p->rendertype = LFXQUAKE;
p->accel[0] = p->accel[1] = p->accel[2] = 0;
p->pshader = alfball;
//p->qarticle = 1;
}
if (p->rendertype != LFXQUAKE){
p->vel[0] += p->accel[0]*frametime;
p->vel[1] += p->accel[1]*frametime;
p->vel[2] += p->accel[2]*frametime;
}
else
{
p->vel[0] += frametime;
p->vel[1] += frametime;
p->vel[2] += frametime;
int i;
switch (p->type)
{
case pt_static:
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]*frametime;
p->vel[2] -= grav;
break;
case pt_blob:
for (i=0 ; i<3 ; i++)
p->vel[i] += p->vel[i]*dvel;
p->vel[2] -= grav;
break;
case pt_blob2:
for (i=0 ; i<2 ; i++)
p->vel[i] -= p->vel[i]*dvel;
p->vel[2] -= grav;
break;
case pt_grav:
p->vel[2] -= grav * 20;
break;
case pt_slowgrav:
p->accel[2] -= grav;
break;
}
if (THEtime> p->endtime)
{
p->next = free_particles;
free_particles = p;
p->type = 0;
p->color = 0;
p->alpha = 0;
p->qolor = 0;
p->accel[0] = 0;
p->accel[1] = 0;
p->accel[2] = 0;
p->rollvel = 0;
p->rollfriction = 0;
//p->qarticle = 0;
p->cols[0][0] = 0;
p->cols[1][0] = 0;
p->cols[2][0] = 0;
p->cols[3][0] = 0;
p->cols[0][1] = 0;
p->cols[1][1] = 0;
p->cols[2][1] = 0;
p->cols[3][1] = 0;
p->cols[0][2] = 0;
p->cols[1][2] = 0;
p->cols[2][2] = 0;
p->cols[3][2] = 0;
p->cols[0][3] = 0;
p->cols[1][3] = 0;
p->cols[2][3] = 0;
p->cols[3][3] = 0;
p->cols[0][4] = 0;
p->cols[1][4] = 0;
p->cols[2][4] = 0;
p->cols[3][4] = 0;
p->airfriction = 0;
p->bounce = 0;
p->bubbleit = 0;
p->material = 0;
p->active_trail = 0;
continue;
}
}
oldorg[0] = p->org[0];
oldorg[1] = p->org[1];
oldorg[2] = p->org[2];
p->org[0] += p->vel[0]*frametime;
p->org[1] += p->vel[1]*frametime;
p->org[2] += p->vel[2]*frametime;
if (p->rendertype != LFXQUAKE)
{
if (alpha > 1.0)
alpha = 1;
if (p->rollfriction){
f = 1.0f - MINe(p->rollfriction * frametime, 1);
p->rollvel *= f;
}
if (p->airfriction){
f = 1.0f - MINe(p->airfriction * frametime, 1);
VectorScale(p->vel, f, p->vel);
}
p->roll += (p->rollvel*frametime);
alpha = p->alpha + time*p->alphavel;
// hack to prevent that one long particle from going crazy in the world.
if (p->startfade > THEtime){
p->alpha = -1; // kill it
}
if (alpha <= 0)
{ // faded out
p->next = free_particles;
free_particles = p;
p->type = 0;
p->airfriction = 0;
p->color = 0;
p->alpha = 0;
p->endtime = THEtime- 0.1;
p->active_trail = 0;
continue;
}
if (THEtime> p->endtime || p->alpha < 0.0f)
{
p->next = free_particles;
free_particles = p;
p->type = 0;
p->color = 0;
p->alpha = 0;
p->qolor = 0;
p->accel[0] = 0;
p->accel[1] = 0;
p->accel[2] = 0;
p->rollvel = 0;
p->rollfriction = 0;
//p->qarticle = 0;
p->cols[0][0] = 0;
p->cols[1][0] = 0;
p->cols[2][0] = 0;
p->cols[3][0] = 0;
p->cols[0][1] = 0;
p->cols[1][1] = 0;
p->cols[2][1] = 0;
p->cols[3][1] = 0;
p->cols[0][2] = 0;
p->cols[1][2] = 0;
p->cols[2][2] = 0;
p->cols[3][2] = 0;
p->cols[0][3] = 0;
p->cols[1][3] = 0;
p->cols[2][3] = 0;
p->cols[3][3] = 0;
p->cols[0][4] = 0;
p->cols[1][4] = 0;
p->cols[2][4] = 0;
p->cols[3][4] = 0;
p->airfriction = 0;
p->bounce = 0;
p->bubbleit = 0;
p->material = 0;
p->active_trail = 0;
continue;
}
}
p->next = NULL;
if (!tail)
active = tail = p;
else
{
tail->next = p;
tail = p;
}
// leilei - trail stuffs
vectoangles( p->vel, p->angle );
p->stretch = 34;
p->src[0] = p->org[0];
p->src[1] = p->org[1];
p->src[2] = p->org[2];
p->dest[0] = p->org[0] + p->vel[0] + p->accel[0];
p->dest[1] = p->org[1] + p->vel[1] + p->accel[1];
p->dest[2] = p->org[2] + p->vel[2] + p->accel[2];
// leilei - bubble conversion
if(p->bubbleit && p->type != LFXBUBBLE)
{
int contents = CM_PointContents( p->org, 0 );
if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME ) ) {
p->type = LFXBUBBLE;
p->pshader = watbubble;
p->airfriction = 2.0f;
p->accel[0] = 0;
p->accel[1] = 0;
p->accel[2] = 66;
p->cols[0][0] = 1; p->cols[0][1] = 1; p->cols[0][2] = 1;
p->cols[1][0] = 1; p->cols[1][1] = 1; p->cols[1][2] = 1;
p->cols[2][0] = 1; p->cols[2][1] = 1; p->cols[2][2] = 1;
p->cols[3][0] = 1; p->cols[3][1] = 1; p->cols[3][2] = 1;
p->endtime += 1000; // last it a wile
}
}
if(p->type == LFXBUBBLE)
{
int contents = CM_PointContents( p->org, 0 );
if ( contents | ( CONTENTS_WATER | CONTENTS_SLIME ) ) {
p->endtime = THEtime;
}
else
{
p->accel[0] = (crandom() * 4 - 2);
p->accel[1] = (crandom() * 4 - 2);
p->accel[2] = 66;
}
}
// leilei - bounce physics
if(p->bounce > 0)
{
trace_t trace;
float dist;
// Do the trace of truth
P_Trace (&trace, oldorg, NULL, NULL, p->org, -1, CONTENTS_SOLID);
{
if (trace.fraction < 1){
VectorCopy(trace.endpos, p->org); // particle where we've hit from
if (p->bounce < 0)
{
// bounce -1 means remove on impact
p->endtime = THEtime;
}
// anything else - bounce off solid
dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce;
VectorMA(p->vel, dist, trace.plane.normal, p->vel);
// lets roll
//p->vel[2] = 7;
if(p->bounce < 0.2f)
p->alpha = -5; // kill!
}
}
}
//R_AddParticleToScene (p, p->org, alpha);
}
active_particles = active;
reallyactive = active;
backEnd.doneParticles = qtrue; // we did it!
}
void R_RenderParticles (void)
{
particle_t *p, *next;
float alpha;
float time, time2;
vec3_t oldorg; // leilei
particle_t *active, *tail;
vec3_t rotate_ang;
float frametime;
float time3;
float time1;
float dvel;
float grav;
float f;
if (!initparticles)
return;
if (!backEnd.doneParticles)
R_AddParticles();
active_particles = reallyactive;
for (p=active_particles ; p ; p=next)
{
next = p->next;
R_AddParticleToScene (p, p->org, p->alpha);
}
}
//
// leilei's LFX particle system effects
//
void R_LFX_Blood (vec3_t org, vec3_t dir, float pressure)
{
int i, j;
int count = pressure * 4;
particle_t *p;
for (i = 0; i < count; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->bubbleit = 2; // dissolve
p->endtime = THEtime+ (1200 * (crandom() * 22));
//p->startfade = p->endtime;
//p->color = GREY75;
p->rendertype = LFXSMOKE;
p->alpha = 1.0f;
p->alphavel = 2.0f;
p->height = 1.5;
p->width = 1.5;
p->endheight = 1.5;
p->endwidth = 1.5;
p->cols[0][0] = p->cols[0][1] = p->cols[0][2] = p->cols[0][3] = p->cols[0][4] = 1.0;
p->cols[1][0] = p->cols[1][1] = p->cols[1][2] = p->cols[1][3] = p->cols[1][4] = 0.0;
p->cols[2][0] = p->cols[2][1] = p->cols[2][2] = p->cols[2][3] = p->cols[2][4] = 0.0;
// Manage blending Functions
p->pshader = addsmoke;
p->colortype = P_LFX;
VectorCopy(org, p->org);
p->bounce = 1.1f;
for (j = 0; j < 3; j++) {
//p->org[j] = org[j] + ((rand() & (count/8)) - (count/16));
p->org[j] = org[j] + ((crandom() * (count/16)) - (count/32));
p->vel[j] = dir[j] * (i * 2.6);
p->vel[j] *= 0.01;
}
p->accel[0] = p->accel[1] = p->accel[2] = 0;
p->accel[2] = -(PARTICLE_GRAVITY*8);
p->airfriction = 0;
// p->org[j] = org[j] + (rand()&((count))-(count));
// p->vel[j] = dir[j]*(rand()*(count*0.5))-(count) * 0.7;
// p->vel[2] += (i / 5);
// }
}
}
void R_LFX_Smoke (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc)
{
int i, j;
int cont = 50;
particle_t *p;
cont = (44 / (count / 2 + 1)) + 1;
for (i = 0; i < cont; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->rendertype = LFXSMOKE;
p->alpha = 0.1f;
p->alphavel = 0.0f;
p->height = p->width = 1.0 * (count / 3);
p->bubbleit = 0;
p->endheight = p->height + scaleup;
p->endwidth = p->width + scaleup;
// Manage random roll and
p->rotate = qtrue;
p->roll = crandom()*179;
p->cols[0][0] = color1[0];
p->cols[1][0] = color1[1];
p->cols[2][0] = color1[2];
p->cols[3][0] = color1[3];
p->cols[0][1] = color2[0];
p->cols[1][1] = color2[1];
p->cols[2][1] = color2[2];
p->cols[3][1] = color2[3];
p->cols[0][2] = color3[0];
p->cols[1][2] = color3[1];
p->cols[2][2] = color3[2];
p->cols[3][2] = color3[3];
p->cols[0][3] = color4[0];
p->cols[1][3] = color4[1];
p->cols[2][3] = color4[2];
p->cols[3][3] = color4[3];
p->cols[0][4] = color5[0];
p->cols[1][4] = color5[1];
p->cols[2][4] = color5[2];
p->cols[3][4] = color5[3];
// Manage blending Functions
if (blendfunc == 1)
p->pshader = addsmoke;
else if (blendfunc == 2)
p->pshader = modsmoke;
else if (blendfunc == 3)
p->pshader = subsmoke;
else if (blendfunc == 8)
p->pshader = fireball;
else
p->pshader = alfsmoke;
p->colortype = P_LFX;
VectorCopy(org, p->org);
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
//p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16));
p->org[j] = org[j];
p->vel[j] = (crandom() * dir[j]) * speed;
p->vel[j] += ((crandom() * (spread)) - (spread/2));
}
p->airfriction = 1.6f;
p->bounce = 1.7f;
p->rollvel = crandom() * 40 - 20;
p->rollfriction = 0.7;
}
}
void R_LFX_Smoke2 (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scale, float scaleup, int blendfunc)
{
int i, j;
int cont = 50;
particle_t *p;
cont = count;
p = 0; // die warnings
for (i = 0; i < cont; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->bubbleit = 1;
p->rendertype = LFXSMOKE;
p->alpha = 0.1f;
p->alphavel = 0.0f;
p->height = p->width = (1.0 * scale);
p->endheight = p->height + scaleup;
p->endwidth = p->width + scaleup;
// Manage random roll and
p->rotate = qtrue;
p->roll = crandom()*179;
p->cols[0][0] = color1[0];
p->cols[1][0] = color1[1];
p->cols[2][0] = color1[2];
p->cols[3][0] = color1[3];
p->cols[0][1] = color2[0];
p->cols[1][1] = color2[1];
p->cols[2][1] = color2[2];
p->cols[3][1] = color2[3];
p->cols[0][2] = color3[0];
p->cols[1][2] = color3[1];
p->cols[2][2] = color3[2];
p->cols[3][2] = color3[3];
p->cols[0][3] = color4[0];
p->cols[1][3] = color4[1];
p->cols[2][3] = color4[2];
p->cols[3][3] = color4[3];
p->cols[0][4] = color5[0];
p->cols[1][4] = color5[1];
p->cols[2][4] = color5[2];
p->cols[3][4] = color5[3];
if (blendfunc == 1)
p->pshader = addsmoke;
else if (blendfunc == 2)
p->pshader = modsmoke;
else if (blendfunc == 3)
p->pshader = subsmoke;
else if (blendfunc == 8)
p->pshader = fireball;
else
p->pshader = alfsmoke;
p->colortype = P_LFX;
VectorCopy(org, p->org);
/*
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
//p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16));
p->org[j] = org[j];
p->vel[j] = (crandom() * dir[j]) * speed;
p->vel[j] += ((crandom() * (spread)) - (spread/2));
}
}
*/
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
p->org[j] = org[j];
p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f);
p->vel[j] += dir[j];
p->vel[j] += (dir[j] * (rand() & (int)speed));
}
//p->rollvel = crandom() * (50 - 100)*DotProduct(p->vel);
p->rollvel = crandom() * ((p->vel[0]+p->vel[1]+p->vel[2])/6) - ((p->vel[0]+p->vel[1]+p->vel[2])/3);
p->rollfriction = 2;
p->airfriction = 3.7f;
p->accel[2] = (PARTICLE_GRAVITY*1.3);
p->bounce = 3.5f;
p->bounce = 0.0f; // bounce is slow...
}
}
void R_LFX_Shock (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc)
{
int i, j;
particle_t *p;
for (i = 0; i < count; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->bubbleit = 0;
p->rendertype = LFXSHOCK;
// p->rendertype = BLOODRED; // note - not actually bloodred.
p->alpha = 0.1f;
p->alphavel = 0.0f;
//p->qolor = (color & ~7) + (rand() & 7);
p->height = p->width = 1.0 * (count / 3);
p->endheight = p->height + scaleup;
p->endwidth = p->width + scaleup;
// Manage random roll and
p->rotate = qtrue;
//p->rotate = qtrue;
p->roll = crandom()*179;
//p->roll = rand()%179;
p->dir[0] = dir[0];
p->dir[1] = dir[1];
p->dir[2] = dir[2];
p->cols[0][0] = color1[0];
p->cols[1][0] = color1[1];
p->cols[2][0] = color1[2];
p->cols[3][0] = color1[3];
p->cols[0][1] = color2[0];
p->cols[1][1] = color2[1];
p->cols[2][1] = color2[2];
p->cols[3][1] = color2[3];
p->cols[0][2] = color3[0];
p->cols[1][2] = color3[1];
p->cols[2][2] = color3[2];
p->cols[3][2] = color3[3];
p->cols[0][3] = color4[0];
p->cols[1][3] = color4[1];
p->cols[2][3] = color4[2];
p->cols[3][3] = color4[3];
p->cols[0][4] = color5[0];
p->cols[1][4] = color5[1];
p->cols[2][4] = color5[2];
p->cols[3][4] = color5[3];
// Manage blending Functions
if (blendfunc == 1)
p->pshader = addshock;
else if (blendfunc == 2)
p->pshader = modshock;
else if (blendfunc == 14)
p->pshader = watsplash;
else if (blendfunc == 3)
p->pshader = subshock;
else
p->pshader = alfshock;
p->colortype = P_LFX;
VectorCopy(org, p->org);
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
//p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16));
p->org[j] = org[j];
p->vel[j] = (crandom() * dir[j]) * speed;
p->vel[j] += ((crandom() * (spread)) - (spread/2));
}
// Manage the Air Friction hack.
// for (j = 0; j < 3; j++) {
// p->accel[j] = (p->vel[j] * -1);
// }
//p->accel[0] = p->accel[1] = p->accel[2] = 0;
//p->accel[2] = -(PARTICLE_GRAVITY / 2);
p->airfriction = 0;
}
}
void R_LFX_Spark (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc)
{
int i, j;
int cont = 50;
particle_t *p;
cont = count;
for (i = 0; i < cont; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->rendertype = LFXSPARK;
//p->color = EMISIVEFADE;
p->alpha = 1.0f;
p->alphavel = 0.0f;
//p->qolor = (color & ~7) + (rand() & 7);
p->height = p->width = scaleup;
p->endheight = p->height;
p->endwidth = p->width;
p->rotate = qfalse; // sparks don't rotate
p->roll = 0; // sparks don't roll
p->accel[0] = p->accel[1] = p->accel[2] = 0;
p->bubbleit = 1;
p->cols[0][0] = color1[0];
p->cols[1][0] = color1[1];
p->cols[2][0] = color1[2];
p->cols[3][0] = color1[3];
p->cols[0][1] = color2[0];
p->cols[1][1] = color2[1];
p->cols[2][1] = color2[2];
p->cols[3][1] = color2[3];
p->cols[0][2] = color3[0];
p->cols[1][2] = color3[1];
p->cols[2][2] = color3[2];
p->cols[3][2] = color3[3];
p->cols[0][3] = color4[0];
p->cols[1][3] = color4[1];
p->cols[2][3] = color4[2];
p->cols[3][3] = color4[3];
p->cols[0][4] = color5[0];
p->cols[1][4] = color5[1];
p->cols[2][4] = color5[2];
p->cols[3][4] = color5[3];
// Manage blending Functions
if (blendfunc == 1)
p->pshader = addball;
else if (blendfunc == 2)
p->pshader = modball;
else if (blendfunc == 3)
p->pshader = subball;
else if (blendfunc == 666)
p->pshader = blood1;
else
p->pshader = alfball;
//p->pshader = cgs.media.whiteShader;
//
p->colortype = P_LFX;
VectorCopy(org, p->org);
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
p->org[j] = org[j];
p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f);
p->vel[j] += dir[j];
p->vel[j] += (dir[j] * (rand() & (int)speed));
}
/*
for (j = 0; j < 3; j++) {
float sped = speed * (1 + crandom()) + (speed * 0.3f);
//p->org[j] = org[j] + ((crandom() * (spread / 8)) - (spread/16));
p->org[j] = org[j];
p->vel[j] = (dir[j]) * sped;
p->vel[j] += ((crandom() * (spread)) - (spread/2));
// p->vel[j] *= crandom();
}
*/
// a little kick up
p->vel[2] += (speed * 0.4f);
p->accel[0] = p->accel[1] = p->accel[2] = 0;
p->accel[2] = -(800 * 0.5f); // TODO: insert proper gravity.
// prepare the initial stretch frame
p->airfriction = 1.6f;
p->bounce = 1.6f;
if (blendfunc == 666){
p->bounce = 666; // instantly make a red decal and kill itself. for blood
p->accel[2] = -(800); // TODO: insert proper gravity.
}
}
// VectorCopy(p->org,p->torg[0]); // a org to stretch from.
}
void R_LFX_Burst (vec3_t org, vec3_t dir, float spread, float speed, vec4_t color1, vec4_t color2, vec4_t color3, vec4_t color4, vec4_t color5, int count, int duration, float scaleup, int blendfunc)
{
int i, j;
int cont = 50;
particle_t *p;
cont = count;
for (i = 0; i < cont; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->rendertype = LFXBURST;
//p->color = EMISIVEFADE;
p->alpha = 1.0f;
p->alphavel = 0.0f;
//p->qolor = (color & ~7) + (rand() & 7);
p->height = p->width = scaleup;
p->endheight = p->height;
p->endwidth = p->width;
p->rotate = qfalse; // sparks don't rotate
p->roll = 0; // sparks don't roll
p->accel[0] = p->accel[1] = p->accel[2] = 0;
p->cols[0][0] = color1[0];
p->cols[1][0] = color1[1];
p->cols[2][0] = color1[2];
p->cols[3][0] = color1[3];
p->cols[0][1] = color2[0];
p->cols[1][1] = color2[1];
p->cols[2][1] = color2[2];
p->cols[3][1] = color2[3];
p->cols[0][2] = color3[0];
p->cols[1][2] = color3[1];
p->cols[2][2] = color3[2];
p->cols[3][2] = color3[3];
p->cols[0][3] = color4[0];
p->cols[1][3] = color4[1];
p->cols[2][3] = color4[2];
p->cols[3][3] = color4[3];
p->cols[0][4] = color5[0];
p->cols[1][4] = color5[1];
p->cols[2][4] = color5[2];
p->cols[3][4] = color5[3];
// Manage blending Functions
if (blendfunc == 1)
p->pshader = addball;
else if (blendfunc == 2)
p->pshader = modball;
else if (blendfunc == 3)
p->pshader = subball;
else if (blendfunc == 7)
p->pshader = watburst;
else if (blendfunc == 666)
p->pshader = blood2;
else
p->pshader = alfball;
p->colortype = P_LFX;
VectorCopy(org, p->org);
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
float sped = speed * (1 + crandom()) + (speed * 0.3f);
p->vel[j] = ((crandom() * (spread)) - (spread/2)) / 360;
p->vel[j] *= sped;
}
p->accel[0] = p->accel[1] = p->accel[2] = 0;
// prepare the initial stretch frame
p->airfriction = 1.6f;
//p->bounce = 2.0f;
VectorCopy(p->org,p->torg[0]); // a org to stretch from.
if (blendfunc == 666){
p->airfriction = 2.9f;
// p->bounce = 1.3f;
p->accel[2] = -(PARTICLE_GRAVITY/2);
}
// for water splashes
if (blendfunc == 7){
p->airfriction = 1.8f;
p->bounce = 0.0f;
p->vel[0] = dir[0];
p->vel[1] = dir[1];
p->vel[2] = dir[2];
p->height = 2;
p->width = 2;
p->endheight = 8;
p->endwidth = 8;
p->accel[2] = -(PARTICLE_GRAVITY);
}
}
}
// i'll probably fail, but still. GENERIC FUNCTION
void R_LFX_Generic (int type, vec3_t org, vec3_t dir, float alpha, int spread, int orgoff, float randroll, float speed, int cred, int cgreen, int cblue, int count, int duration, float scale, float scaleup, float bounce, float airfriction, float grav, float rollfriction, shader_t *shader)
{
int i, j;
int cont = 50;
particle_t *p;
cont = count;
p = 0; // die warnings
for (i = 0; i < cont; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->time = THEtime;
p->endtime = THEtime+ duration;
p->startfade = THEtime;
p->bubbleit = 0; // don't do bubble check for any generic particles.
p->rendertype = type;
p->alpha = alpha;
p->alphavel = 0.0f;
p->height = p->width = (1.0 * scale);
p->endheight = p->height + scaleup;
p->endwidth = p->width + scaleup;
p->rotate = qtrue;
p->roll = 0;//crandom()*randroll;
// we only use one color for this fine generic function
p->cols[0][0] = cred / 255;
p->cols[1][0] = cgreen / 255;
p->cols[2][0] = cblue / 255;
p->cols[3][0] = 1.0f;
p->cols[0][1] = cred / 255;
p->cols[1][1] = cgreen / 255;
p->cols[2][1] = cblue / 255;
p->cols[3][1] = 1.0f;
p->cols[0][2] = cred / 255;
p->cols[1][2] = cgreen / 255;
p->cols[2][2] = cblue / 255;
p->cols[3][2] = 1.0f;
p->cols[0][3] = cred / 255;
p->cols[1][3] = cgreen / 255;
p->cols[2][3] = cblue / 255;
p->cols[3][3] = 1.0f;
p->cols[0][4] = cred / 255;
p->cols[1][4] = cgreen / 255;
p->cols[2][4] = cblue / 255;
p->cols[3][4] = 1.0f;
p->pshader = shader;
//p->rollvel = crandom() * (50 - 100)*DotProduct(p->vel);
p->rollvel = crandom() * ((p->vel[0]+p->vel[1]+p->vel[2])/6) - ((p->vel[0]+p->vel[1]+p->vel[2])/3);
p->rollfriction = rollfriction;
p->airfriction = airfriction;
p->accel[0] = p->accel[1] = 0;
p->accel[2] = (PARTICLE_GRAVITY*grav);
p->bounce = bounce;
p->colortype = P_LFXSIMPLE; // it's always an lfx for this one.
VectorCopy(org, p->org);
// Manage spread of origin and velocity
for (j = 0; j < 3; j++) {
p->org[j] = org[j] + ((rand() % orgoff) - (int)(orgoff * 0.5f));
//p->org[j] = org[j];
p->vel[j] = (rand() & (int)spread) - (int)(spread * 0.5f);
p->vel[j] += dir[j];
p->vel[j] += (dir[j] * (rand() & (int)speed));
}
}
}
// macros kind of
// give some turbulence to smokes
void R_LFX_PushSmoke (vec3_t there, float force)
{
// will reimplement properly later
}
void R_LetsBounce ( particle_t *p)
{
// will reimplement properly later
}
// QUAKE EFFECTS
// attempt at generic particles function similar to quake...
void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
{
int i, j;
particle_t *p;
for (i = 0; i < count; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 0.1*(rand()%5);
p->color = (color&~7) + (rand()&7);
p->type = pt_slowgrav;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()&15)-8);
p->vel[j] = dir[j]*15;// + (rand()%300)-150;
}
}
}
// also from Quake!
void R_QarticleExplosion(vec3_t org)
{
int i, j;
particle_t *p;
for (i = 0; i < 512; i++) {
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->rendertype = EMISIVEFADE;
p->alpha = 1.0f;
p->alphavel = 1.0f;
p->time = THEtime;
p->bubbleit = 0;
// crap for q3's particle system...
p->endtime = THEtime+ 500;
p->startfade = p->endtime;
p->height = 0.5;
p->width = 0.5;
p->endheight = 0.5;
p->endwidth = 0.5;
p->pshader = alfsmoke;
p->qolor = ramp1[0];
// p->qolor = 44;
VectorCopy(org, p->org);
p->ramp = rand() & 3;
if (i & 1) {
// p->type = P_QUAKE;
for (j = 0; j < 3; j++) {
p->org[j] = org[j] + ((rand() % 32) - 16);
p->vel[j] = (rand() % 512) - 256;
p->accel[j] = p->vel[j] * 4;
}
} else {
// p->type = P_QUAKE;
for (j = 0; j < 3; j++) {
p->org[j] = org[j] + ((rand() % 32) - 16);
p->vel[j] = (rand() % 512) - 256;
p->accel[j] = p->vel[j] * 4;
}
}
}
}
void Q_ParticleExplosion (vec3_t org)
{
int i, j;
particle_t *p;
for (i=0 ; i<1024 ; i++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 5;
p->color = ramp1[0];
p->ramp = rand()&3;
if (i & 1)
{
p->type = pt_explode;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
else
{
p->type = pt_explode2;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
}
}
void Q_RocketTrail (vec3_t start, vec3_t end, int type)
{
vec3_t vec;
float len;
int j;
particle_t *p;
int dec;
static int tracercount;
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
if (type < 128)
dec = 3;
else
{
dec = 1;
type -= 128;
}
while (len > 0)
{
len -= dec;
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
VectorCopy (vec3_origin, p->vel);
p->die = cl.time + 2;
switch (type)
{
case 0: // rocket trail
p->ramp = (rand()&3);
p->qolor = ramp3[(int)p->ramp];
p->type = pt_fire;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 1: // smoke smoke
p->ramp = (rand()&3) + 2;
p->color = ramp3[(int)p->ramp];
p->type = pt_fire;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 2: // blood
p->type = pt_grav;
p->color = 67 + (rand()&3);
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 3:
case 5: // tracer
p->die = cl.time + 0.5;
p->type = pt_static;
if (type == 3)
p->color = 52 + ((tracercount&4)<<1);
else
p->color = 230 + ((tracercount&4)<<1);
tracercount++;
VectorCopy (start, p->org);
if (tracercount & 1)
{
p->vel[0] = 30*vec[1];
p->vel[1] = 30*-vec[0];
}
else
{
p->vel[0] = 30*-vec[1];
p->vel[1] = 30*vec[0];
}
break;
case 4: // slight blood
p->type = pt_grav;
p->color = 67 + (rand()&3);
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
len -= 3;
break;
case 6: // voor trail
p->color = 9*16 + 8 + (rand()&3);
p->type = pt_static;
p->die = cl.time + 0.3;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()&15)-8);
break;
}
VectorAdd (start, vec, start);
}
}
void LFX_ShaderInit ( void )
{
addsmoke = R_FindShader( "psmoke-add", LIGHTMAP_NONE, qtrue );
subsmoke = R_FindShader( "psmoke-sub", LIGHTMAP_NONE, qtrue );
modsmoke = R_FindShader( "psmoke-mod", LIGHTMAP_NONE, qtrue );
alfsmoke = R_FindShader( "psmoke-blend", LIGHTMAP_NONE, qtrue );
blood1 = R_FindShader( "pblood1", LIGHTMAP_NONE, qtrue );
blood2 = R_FindShader( "pblood1", LIGHTMAP_NONE, qtrue );
watsplash = R_FindShader( "pwatersplash", LIGHTMAP_NONE, qtrue );
watburst = R_FindShader( "pwaterburst", LIGHTMAP_NONE, qtrue );
watbubble = R_FindShader( "pwaterbubble", LIGHTMAP_NONE, qtrue );
fireball = R_FindShader( "pfireball", LIGHTMAP_NONE, qtrue );
addball = R_FindShader( "pball-add", LIGHTMAP_NONE, qtrue );
subball = R_FindShader( "pball-sub", LIGHTMAP_NONE, qtrue );
modball = R_FindShader( "pball-mod", LIGHTMAP_NONE, qtrue );
alfball = R_FindShader( "pball-blend", LIGHTMAP_NONE, qtrue );
addshock = R_FindShader( "pshock-add", LIGHTMAP_NONE, qtrue );
subshock = R_FindShader( "pshock-sub", LIGHTMAP_NONE, qtrue );
modshock = R_FindShader( "pshock-mod", LIGHTMAP_NONE, qtrue );
alfshock = R_FindShader( "pshock-blend", LIGHTMAP_NONE, qtrue );
R_ClearParticles ();
}
// 1996 - it's like the first game ok
// - just dots
void LFX_ParticleEffect1996 (int effect, vec3_t org, vec3_t dir)
{
vec3_t notatall;
// Smoke trails on grenades and rockets
if (effect == 1)
{
R_RunParticleEffect (org, notatall, 10, 8);
//Q_RocketTrail(org, dir, r_leidebug->integer);
}
// Bullet Hit
if (effect == 2 || effect == 3)
{
R_RunParticleEffect (org, notatall, 6, 20);
}
// Grenade/Rocket/Prox Explosion
else if (effect == 5 || effect == 4 || effect == 11)
{
Q_ParticleExplosion(org);
}
// Blood Sprays for bullets
if (effect == 14)
{
R_RunParticleEffect (org, dir,21, 20);
}
// Water Splash for bullets
if (effect == 19)
{
R_RunParticleEffect (org, dir,41, 20);
}
}
// 200X - most games of that decade...
// - usually ltos of particles
// - usually
void LFX_ParticleEffect200X (int effect, vec3_t org, vec3_t dir)
{
vec3_t origin, sprOrg, sprVel; // laziness
vec4_t colory, colory2, colory3, colory4;
VectorCopy(org, sprOrg);
VectorCopy(org, origin);
VectorCopy(dir, sprVel);
// Smoke trails on grenades and rockets
if (effect == 1)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 1.0;
colory2[0] = 0.5; colory2[1] = 0.5; colory2[2] = 0.5; colory2[3] = 0.8;
colory3[0] = 0.5; colory3[1] = 0.4; colory3[2] = 0.3; colory3[3] = 0.5;
colory4[0] = 0.5; colory4[1] = 0.4; colory4[2] = 0.3; colory4[3] = 0.0;
R_LFX_Smoke2 (sprOrg, sprVel, 1 + (random()*3), 0.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 2470, 4, 8+ (random()*6), 4);
}
// Bullet Hit
if (effect == 2)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0;
VectorMA( origin, 4, dir, sprOrg );
VectorScale( dir, 1, sprVel );
// Sparks
colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9;
colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
R_LFX_Burst (sprOrg, sprVel, 8366, 2, colory, colory2, colory3, colory4, colory4, 4, 50, 2, 1);
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Spark (sprOrg, sprVel, 95, 325, colory, colory2, colory3, colory4, colory4, 5, 140, 0.5f, 1);
R_LFX_Spark (sprOrg, sprVel, 95, 85, colory, colory2, colory3, colory4, colory4, 1, 1540, 0.5f, 1);
//R_LFX_PushSmoke (sprOrg, 44);
}
// Shotgun Hit
if (effect == 3)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 7, sprVel );
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
colory[0] = 0.9; colory[1] = 0.8; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 0.7; colory2[1] = 0.5; colory2[2] = 0.2; colory2[3] = 0.9;
colory3[0] = 0.1; colory3[1] = 0.1; colory3[2] = 0.1; colory3[3] = 0.7;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 4, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Shock (origin, dir, 0, 32, colory, colory2, colory3, colory4, colory4, 1, 200, 50,1);
colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9;
colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 3, 2540, 0.5f, 1);
}
// Plasma Hit
if (effect == 6)
{
colory[0] = 1.0; colory[1] = 0.7; colory[2] = 1.0; colory[3] = 0.0;
colory2[0] = 0.3; colory2[1] = 0.7; colory2[2] = 1.0; colory2[3] = 0.5;
colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 7, sprVel );
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
VectorMA( origin, 2, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1,600, 80,1);
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 5, 5540, 0.5f, 1);
}
// Lightning Hit
if (effect == 8)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 7, sprVel );
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
}
// Grenade/Rocket/Prox Explosion
else if (effect == 5 || effect == 4 || effect == 11)
{
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 1.0; colory2[1] = 1.0; colory2[2] = 0.5; colory2[3] = 0.9;
colory3[0] = 0.7; colory3[1] = 0.3; colory3[2] = 0.1; colory3[3] = 0.7;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 4, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 500, 270, 1);
// fireball
colory[0] = 1.0; colory[1] = 0.2; colory[2] = 0.1; colory[3] = 0.0;
colory2[0] = 0.5; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.2;
colory3[0] = 0.1; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.7;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 12, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Smoke (sprOrg, sprVel, 32, 3.54, colory, colory2, colory3, colory4, colory4, 16, 1000, 94, 1);
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 0.9; colory[3] = 1.0;
colory2[0] = 1.0; colory2[1] = 0.7; colory2[2] = 0.2; colory2[3] = 0.9;
colory3[0] = 0.3; colory3[1] = 0.2; colory3[2] = 0.1; colory3[3] = 0.7;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
R_LFX_Smoke (sprOrg, sprVel, 62, 2, colory, colory2, colory3, colory4, colory4, 12, 200,84, 8);
R_LFX_Smoke (sprOrg, sprVel, 32, 1.54, colory, colory2, colory3, colory4, colory4, 22, 600, 74, 8);
R_LFX_Smoke (sprOrg, sprVel, 44, 1.3, colory, colory2, colory3, colory4, colory4, 3, 800,3, 8);
R_LFX_Smoke (sprOrg, sprVel, 32, 0.54, colory, colory2, colory3, colory4, colory4, 12, 600, 74, 8);
// Shroom Cloud
VectorMA( origin, 16, dir, sprOrg );
VectorScale( dir, 64, sprVel );
colory[0] = 0.5; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 0.0;
colory2[0] = 1.0; colory2[1] = 1.0; colory2[2] = 0.2; colory2[3] = 0.2;
colory3[0] = 0.5; colory3[1] = 0.1; colory3[2] = 0.0; colory3[3] = 0.5;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
R_LFX_Smoke (sprOrg, sprVel, 3, 0.7, colory, colory2, colory3, colory4, colory4, 22, 300,135, 8);
// Sparks!
colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9;
colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 12, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 15, 240, 22, 1);
R_LFX_Spark (sprOrg, sprVel, 175, 5, colory, colory2, colory3, colory4, colory4, 25, 1240, 0.8f, 1);
}
// BFG
else if (effect == 9)
{
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 0.3; colory2[1] = 1.0; colory2[2] = 0.2; colory2[3] = 0.9;
colory3[0] = 0.0; colory3[1] = 0.3; colory3[2] = 0.1; colory3[3] = 0.7;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 4, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Shock (sprOrg, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 300, 470, 1);
// fireball
VectorMA( origin, 12, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Smoke (sprOrg, sprVel, 32, 3.54, colory, colory2, colory3, colory4, colory4, 16, 200, 174, 1);
R_LFX_Smoke (sprOrg, sprVel, 62, 2, colory, colory2, colory3, colory4, colory4, 12, 800,84, 8);
R_LFX_Smoke (sprOrg, sprVel, 32, 1.54, colory, colory2, colory3, colory4, colory4, 22, 400, 74, 8);
R_LFX_Smoke (sprOrg, sprVel, 44, 1.3, colory, colory2, colory3, colory4, colory4, 3, 500,3, 8);
R_LFX_Smoke (sprOrg, sprVel, 32, 0.54, colory, colory2, colory3, colory4, colory4, 12, 400, 74, 8);
// Shroom Cloud
VectorMA( origin, 16, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Smoke (sprOrg, sprVel, 3, 0.7, colory, colory2, colory3, colory4, colory4, 22, 300,135, 8);
// Sparks!
VectorMA( origin, 12, dir, sprOrg );
VectorScale( dir, 64, sprVel );
R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 15, 140, 32, 1);
R_LFX_Spark (sprOrg, sprVel, 175, 5, colory, colory2, colory3, colory4, colory4, 15, 1040, 0.8f, 1);
}
// Nail Hit
if (effect == 10)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 7, sprVel );
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
colory[0] = 0.7; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 0.0;
colory2[0] = 0.3; colory2[1] = 0.7; colory2[2] = 1.0; colory2[3] = 0.5;
colory3[0] = 0.0; colory3[1] = 0.2; colory3[2] = 0.5; colory3[3] = 0.8;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 4, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Burst (sprOrg, sprVel, 8366, 2, colory, colory2, colory3, colory4, colory4, 4, 150, 3, 1);
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Spark (sprOrg, sprVel, 95, 225, colory, colory2, colory3, colory4, colory4, 5, 140, 0.5f, 1);
R_LFX_Spark (sprOrg, sprVel, 95, 185, colory, colory2, colory3, colory4, colory4, 1, 2540, 0.5f, 1);
}
// Blood Sprays for bullets
if (effect == 14 && com_blood->integer)
{
sprVel[2] += 54;
colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8;
colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 2, 1755, 12, 666);
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 2, sprVel );
//R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 8, 2386, 0.5f, 666);
}
// "Blood" Sprays for bullets
if (effect == 14 && !com_blood->integer)
{
// nonviolent blue center
colory[0] = 0.0; colory[1] = 0.7; colory[2] = 1.0; colory[3] = 0.0;
colory2[0] = 0.0; colory2[1] = 0.0; colory2[2] = 1.0; colory2[3] = 0.5;
colory3[0] = 0.0; colory3[1] = 0.0; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
R_LFX_Burst (sprOrg, sprVel, 175, 15, colory, colory2, colory3, colory4, colory4, 2, 105, 12, 1);
R_LFX_Smoke (sprOrg, sprVel, 0, 0, colory, colory2, colory3, colory4, colory4, 32, 400, -33, 1);
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
colory[0] = 1; colory[1] = 1; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 1; colory2[1] = 1; colory2[2] = 0.8; colory2[3] = 0.9;
colory3[0] = 0.7; colory3[1] = 0.5; colory3[2] = 0.2; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
R_LFX_Spark (sprOrg, sprVel, 25, 85, colory, colory2, colory3, colory4, colory4, 2,586, 0.5f, 1);
R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 255, 39,1);
}
// Blood Spray for a gibbing
if (effect == 16 && com_blood->integer)
{
sprVel[2] += 124;
colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8;
colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
// R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
// R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
R_LFX_Burst (sprOrg, sprVel, 275, 4, colory, colory2, colory3, colory4, colory4, 9, 1455, 42, 666);
}
// Water Splash for bullets
if (effect == 19)
{
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 0.3; colory2[1] = 0.5; colory2[2] = 0.6; colory2[3] = 0.6;
colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.3; colory3[3] = 0.3;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorScale( dir, 39, sprVel );
R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 800, 80,14);
R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 1900, 5, 7);
R_LFX_Spark (sprOrg, sprVel, 134, 4, colory, colory2, colory3, colory4, colory4, 7, 1286, 0.5f, 1);
}
/*
// these are not properly implemented through cgame yet as they call *every* frame instead of being a truly one shot effect.
// muzzieflash plasmagun
if (effect == 66)
{
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 0.3; colory2[1] = 0.5; colory2[2] = 0.6; colory2[3] = 0.5;
colory3[0] = 0.1; colory3[1] = 0.2; colory3[2] = 0.3; colory3[3] = 0.8;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorScale( dir, 39, sprVel );
R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 255, 8,1);
//R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 144, 2, 7);
//R_LFX_Spark (sprOrg, sprVel, 134, 4, colory, colory2, colory3, colory4, colory4, 7, 1556, 0.25f, 1);
}
// muzzleflash shotgun
if (effect == 63)
{
colory[0] = 0.7; colory[1] = 0.7; colory[2] = 0.7; colory[3] = 0.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.6; colory3[2] = 0.6; colory3[3] = 0.8;
colory4[0] = 0.6; colory4[1] = 0.6; colory4[2] = 0.6; colory4[3] = 0.0;
//R_LFX_Burst (sprOrg, sprVel, 22, 266, colory, colory2, colory3, colory4, colory4, 1, 144, 2, 7);
R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*55.7), colory, colory2, colory3, colory4, colory4, 4, 300 + (random()*3000), 2, 8+ (random()*6), 4);
VectorScale( dir, 39, sprVel );
R_LFX_Spark (sprOrg, sprVel, 14, 8, colory, colory2, colory3, colory4, colory4, 22, 556, 0.25f, 1);
}
*/
}
// 1997 -
// - alpha blends ONLY!
// - low amounts of polygons
// - high atlas usage
void LFX_ParticleEffect1997 (int effect, vec3_t org, vec3_t dir)
{
vec3_t origin, sprOrg, sprVel; // laziness
vec4_t colory, colory2, colory3, colory4;
VectorCopy(org, sprOrg);
VectorCopy(org, origin);
VectorCopy(dir, sprVel);
// Smoke trails on grenades and rockets
// this should be several smoke atlases along a line.
if (effect == 1)
{
}
// Bullet Hit
// a smoke puff, a badly looping spark model, and an occasional ball spark (no stretch) of a random amount from 1 to 6 balls.
if (effect == 2)
{
}
// Shotgun Hit
// can be just smoke puffs, preferably atlasy.
if (effect == 3)
{
}
// Plasma Hit
// should become a plain sprite atlas animation.
if (effect == 6)
{
}
// Lightning Hit
// can become a plain sprite, but we already have that, so.....
if (effect == 8)
{
}
// Grenade/Rocket/Prox Explosion
// should be an explosion atlas, but on later versions there's several more delayed explosion atlases to spice up the variety
else if (effect == 5 || effect == 4 || effect == 11)
{
}
// BFG, could be an expanding sphere with an explosion atlas
else if (effect == 9)
{
}
// Blood Sprays for bullets
if (effect == 14 && com_blood->integer)
{
colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8;
colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
}
// "Blood" Sprays for bullets
if (effect == 14 && !com_blood->integer)
{
// usually there are none.
}
// Blood Spray for a gibbing
if (effect == 16 && com_blood->integer)
{
// usually there are none.
}
// Water Splash for bullets - a splash atlas burst animation.
if (effect == 19)
{
}
}
// 1998 - a certain game from washington state
// - some atlas animation, but not much
// - glquake particles are still present
// - alpha and additives only
// - sparks, but sparsely and no collision
// - some flare testing on some effects
void LFX_ParticleEffect1998 (int effect, vec3_t org, vec3_t dir)
{
vec3_t origin, sprOrg, sprVel; // laziness
vec4_t colory, colory2, colory3, colory4;
VectorCopy(org, sprOrg);
VectorCopy(org, origin);
VectorCopy(dir, sprVel);
// Smoke trails on grenades and rockets
// might be a beam.
if (effect == 1)
{
}
// Bullet Hit
// glquake black particles of debris coming off
// followed by a few stretchy sparks of orange that fall out of it
//
if (effect == 2)
{
// Sparks
colory[0] = 0.6; colory[1] = 0.4; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.7; colory2[1] = 0.4; colory2[2] = 0.0; colory2[3] = 0.9;
colory3[0] = 0.5; colory3[1] = 0.2; colory3[2] = 0.0; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
sprVel[2] += 2;
R_LFX_Spark (sprOrg, sprVel, 11, 32, colory, colory2, colory3, colory4, colory4, 4, 440, 0.5f, 1);
sprVel[2] += 64;
R_LFX_Generic
(LFXSMOKE, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
85, // Spread Factor
3, // Random Origin Offset
0, // Random Roll Value
0, // Additional Random Speed
8, // Particle Color Red
8, // Particle Color Green
8, // Particle Color Blue
8, // Particle Count
400, // Particle Life
0.5f, // Particle Scale
0.5f, // Particle Scale Towards
0.1f, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
-16.0f, // Particle Gravity Factor
0.0f, // Particle Rolling Friction
alfball // Particle Shader
);
}
else if (effect == 3)
{
if (rand() < 0.5f){ // only happens for half the pellets
// Sparks
colory[0] = 0.6; colory[1] = 0.4; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.7; colory2[1] = 0.4; colory2[2] = 0.0; colory2[3] = 0.9;
colory3[0] = 0.5; colory3[1] = 0.2; colory3[2] = 0.0; colory3[3] = 0.7;
colory4[0] = 0.1; colory4[1] = 0.06; colory4[2] = 0.0; colory4[3] = 0.0;
VectorMA( origin, 1, dir, sprOrg );
VectorScale( dir, 1, sprVel );
R_LFX_Spark (sprOrg, sprVel, 95, 32, colory, colory2, colory3, colory4, colory4, 3, 440, 0.5f, 1);
sprVel[2] += 64;
R_LFX_Generic
(LFXSMOKE, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
85, // Spread Factor
3, // Random Origin Offset
0, // Random Roll Value
0, // Additional Random Speed
8, // Particle Color Red
8, // Particle Color Green
8, // Particle Color Blue
8, // Particle Count
400, // Particle Life
0.5f, // Particle Scale
0.5f, // Particle Scale Towards
0.1f, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
-16.0f, // Particle Gravity Factor
0.0f, // Particle Rolling Friction
alfball // Particle Shader
);
}
}
// Plasma Hit
// should become a plain sprite atlas animation.
if (effect == 6)
{
}
// Grenade/Rocket/Prox Explosion
// should be an explosion atlas
// plus a smoke atlas that comes in later
// plus a few glquake-ish embers
// plus a couple of sparks that shoots off other sparks
else if (effect == 5 || effect == 4 || effect == 11)
{
}
// BFG, could be just a shockwave.
else if (effect == 9)
{
}
// Blood Sprays for bullets
// should be a nondirectional splat of a center atlas gush
// and then several randomly directed blood drops that roll. all is GE128
if (effect == 14 && com_blood->integer)
{
colory[0] = 1.0; colory[1] = 0.0; colory[2] = 0.0; colory[3] = 1.0;
colory2[0] = 0.8; colory2[1] = 0.0; colory2[2] = 0.0; colory2[3] = 0.5;
colory3[0] = 0.6; colory3[1] = 0.0; colory3[2] = 0.0; colory3[3] = 0.8;
colory4[0] = 0.3; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 6.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 800 + (random()*2000), 2, 8+ (random()*6), 0);
//R_LFX_Smoke2 (sprOrg, sprVel, 2 + (random()*6), 3.54+ (random()*8.7), colory, colory2, colory3, colory4, colory4, 1, 300 + (random()*2000), 2, 8+ (random()*6), 4);
}
}
// 1999 - a certain competing game
// - high emphasis on atlas animations
// - no alpha blending - only alpha blend, subtractive blend (for grenade smoke) and GE128 alpha testing.
void LFX_ParticleEffect1999 (int effect, vec3_t org, vec3_t dir)
{
vec3_t origin, sprOrg, sprVel; // laziness
vec4_t colory, colory2, colory3, colory4;
VectorCopy(org, sprOrg);
VectorCopy(org, origin);
VectorCopy(dir, sprVel);
// Smoke trails on grenades and rockets
// this should be several smoke atlases along a line.
if (effect == 1)
{
}
// Bullet Hit
// a smoke puff, a badly looping spark model, and an occasional ball spark (no stretch) of a random amount from 1 to 6 balls.
if (effect == 2)
{
R_LFX_Generic
(777777, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
96, // Spread Factor
4, // Random Origin Offset
0, // Random Roll Value
200, // Additional Random Speed
255, // Particle Color Red
255, // Particle Color Green
32, // Particle Color Blue
5, // Particle Count
600, // Particle Life
1, // Particle Scale
1, // Particle Scale Towards
0.1f, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
-12.0f, // Particle Gravity Factor
0.0f, // Particle Rolling Friction
addball // Particle Shader
);
}
// Shotgun Hit
// can be just smoke puffs, preferably atlasy.
if (effect == 3)
{
VectorMA( origin, 8, dir, sprOrg );
sprVel[2] += 20;
R_LFX_Generic
(LFXSMOKE, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
0, // Spread Factor
4, // Random Origin Offset
0, // Random Roll Value
0, // Additional Random Speed
255, // Particle Color Red
255, // Particle Color Green
255, // Particle Color Blue
5, // Particle Count
1200, // Particle Life
12, // Particle Scale
12, // Particle Scale Towards
0, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
0, // Particle Gravity Factor
10, // Particle Rolling Friction
addsmoke // Particle Shader
);
}
// Plasma Hit
// should become a plain sprite atlas animation.
if (effect == 6)
{
}
// Lightning Hit
// can become a plain sprite, but we already have that, so.....
if (effect == 8)
{
}
// Grenade/Rocket/Prox Explosion
// should be an explosion atlas, but on later versions there's several more delayed explosion atlases to spice up the variety
else if (effect == 5 || effect == 4 || effect == 11)
{
}
// BFG, could be an expanding sphere with an explosion atlas
else if (effect == 9)
{
}
// Blood Sprays for bullets
// should be an additive smoke puff that doesn't move (but go through an atlas animation)
// as well as a model that has autosprites for ge128 blood sprays, which is kinda cheesy but we can replicate this effect
// withi particles anyhow because we're awesome for having a real particle system ha ha ha ha ha
if (effect == 14 && com_blood->integer)
{
VectorMA( origin, 8, dir, sprOrg );
sprVel[2] = 0;
sprVel[1] = 0;
sprVel[0] = 0;
R_LFX_Generic
(LFXSMOKE, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
0, // Spread Factor
4, // Random Origin Offset
0, // Random Roll Value
0, // Additional Random Speed
255, // Particle Color Red
0, // Particle Color Green
0, // Particle Color Blue
1, // Particle Count
700, // Particle Life
8, // Particle Scale
8, // Particle Scale Towards
0, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
0, // Particle Gravity Factor
10, // Particle Rolling Friction
addsmoke // Particle Shader
);
R_LFX_Generic
(LFXSMOKE, // Particle Type
sprOrg, // Origin
sprVel, // Velocity
1.0f, // Starting Alpha
96, // Spread Factor
4, // Random Origin Offset
0, // Random Roll Value
200, // Additional Random Speed
255, // Particle Color Red
0, // Particle Color Green
0, // Particle Color Blue
5, // Particle Count
600, // Particle Life
1, // Particle Scale
1, // Particle Scale Towards
0.1f, // Particle Bounce Factor
0, // Air Friction (stopping particle velocity in air)
-12.0f, // Particle Gravity Factor
0.0f, // Particle Rolling Friction
alfsmoke // Particle Shader
);
}
// "Blood" Sprays for bullets
if (effect == 14 && !com_blood->integer)
{
// not yet. this should be an additive green puff
}
// Blood Spray for a gibbing
if (effect == 16 && com_blood->integer)
{
// not yet.
}
// Water Splash for bullets - there should only be a polygonal white ring. but we don't do model drawing right now
if (effect == 19)
{
colory[0] = 1.0; colory[1] = 1.0; colory[2] = 1.0; colory[3] = 1.0;
colory2[0] = 0.7; colory2[1] = 0.7; colory2[2] = 0.7; colory2[3] = 0.6;
colory3[0] = 0.4; colory3[1] = 0.4; colory3[2] = 0.4; colory3[3] = 0.3;
colory4[0] = 0.0; colory4[1] = 0.0; colory4[2] = 0.0; colory4[3] = 0.0;
VectorScale( dir, 39, sprVel );
R_LFX_Shock (origin, dir, 0, 0, colory, colory2, colory3, colory4, colory4, 1, 800, 80,14);
}
}
void LFX_ParticleEffect (int effect, vec3_t org, vec3_t dir)
{
// choosing particle sets
if (r_particles->value == 1996) // Mimicing the grand old game
LFX_ParticleEffect1996(effect, org, dir);
else if (r_particles->value == 1997) // Mimicing games for an allegedly 64-bit video game system
LFX_ParticleEffect1997(effect, org, dir);
else if (r_particles->value == 1998) // Mimicing a certain game from Washington state
LFX_ParticleEffect1998(effect, org, dir);
else if (r_particles->value == 1999) // Mimicing a certain competing game
LFX_ParticleEffect1999(effect, org, dir);
else
LFX_ParticleEffect200X(effect, org, dir);
}