diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cgame/cg_event.c | 5 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 40 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 2 | ||||
-rw-r--r-- | src/cgame/cg_particles.c | 2013 | ||||
-rw-r--r-- | src/cgame/cg_servercmds.c | 5 | ||||
-rw-r--r-- | src/cgame/cg_trails.c | 728 | ||||
-rw-r--r-- | src/cgame/cg_view.c | 4 | ||||
-rw-r--r-- | src/cgame/cg_weapons.c | 18 | ||||
-rw-r--r-- | src/game/bg_public.h | 9 | ||||
-rw-r--r-- | src/game/g_weapon.c | 2 | ||||
-rw-r--r-- | src/game/q_math.c | 48 |
11 files changed, 849 insertions, 2025 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 7ea62220..1a28c2a8 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -959,12 +959,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) case EV_TESLATRAIL: DEBUGNAME("EV_TESLATRAIL"); cent->currentState.weapon = WP_TESLAGEN; - // if the end was on a nomark surface, don't make an explosion CG_TeslaTrail( es->origin2, es->pos.trBase ); - if ( es->eventParm != 255 ) { - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT, 0 ); - } break; case EV_BULLET_HIT_WALL: diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index dc9af0e9..184c3830 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -72,6 +72,19 @@ #define NUM_CROSSHAIRS 10 +//TA: ripped from wolf source +// Ridah, trails +#define STYPE_STRETCH 0 +#define STYPE_REPEAT 1 + +#define TJFL_FADEIN (1<<0) +#define TJFL_CROSSOVER (1<<1) +#define TJFL_NOCULL (1<<2) +#define TJFL_FIXDISTORT (1<<3) +#define TJFL_SPARKHEADFLARE (1<<4) +#define TJFL_NOPOLYMERGE (1<<5) +// done. + #define TEAM_OVERLAY_MAXNAME_WIDTH 12 #define TEAM_OVERLAY_MAXLOCATION_WIDTH 16 @@ -213,6 +226,7 @@ typedef struct markPoly_s { typedef enum { LE_MARK, LE_EXPLOSION, + LE_LIGHTNING_BOLT, //wolf trail LE_SPRITE_EXPLOSION, LE_FRAGMENT, LE_MOVE_SCALE_FADE, @@ -1025,6 +1039,8 @@ typedef struct { sfxHandle_t wstbimpdSound; sfxHandle_t wstbactvSound; + //TA: for wolf trail effects + qhandle_t sparkFlareShader; } cgMedia_t; @@ -1519,6 +1535,30 @@ localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, qhandle_t hModel, qhandle_t shader, int msec, qboolean isSprite ); +//TA: wolf tesla effect +void CG_DynamicLightningBolt( qhandle_t shader, vec3_t start, vec3_t pend, + int numBolts, float maxWidth, qboolean fade, + float startAlpha, int recursion, int randseed ); + +// Ridah, trails +// +// cg_trails.c +// +int CG_AddTrailJunc( int headJuncIndex, qhandle_t shader, int spawnTime, + int sType, vec3_t pos, int trailLife, float alphaStart, + float alphaEnd, float startWidth, float endWidth, int flags, + vec3_t colorStart, vec3_t colorEnd, float sRatio, float animSpeed ); +int CG_AddSparkJunc( int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, + float alphaStart, float alphaEnd, float startWidth, float endWidth ); +int CG_AddSmokeJunc( int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, + float alpha, float startWidth, float endWidth ); +int CG_AddFireJunc( int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, + float alpha, float startWidth, float endWidth ); +void CG_AddTrails( void ); +void CG_ClearTrails( void ); +// done. + + // // cg_snapshot.c // diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 9b874dcb..1ffc578f 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -893,8 +893,6 @@ static void CG_RegisterGraphics( void ) { } cgs.gameShaders[i] = trap_R_RegisterShader( shaderName ); } - - CG_ClearParticles (); } diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c deleted file mode 100644 index 697d6a7d..00000000 --- a/src/cgame/cg_particles.c +++ /dev/null @@ -1,2013 +0,0 @@ -// Rafael particles -// cg_particles.c - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * 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. - */ - -#include "cg_local.h" - -#define BLOODRED 2 -#define EMISIVEFADE 3 -#define GREY75 4 - -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; - qhandle_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; - -} cparticle_t; - -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 -} particle_type_t; - -#define MAX_SHADER_ANIMS 32 -#define MAX_SHADER_ANIM_FRAMES 64 - -static char *shaderAnimNames[MAX_SHADER_ANIMS] = { - "explode1", - "blacksmokeanim", - "twiltb2", - "expblue", - "blacksmokeanimb", // uses 'explode1' sequence - "blood", - NULL -}; -static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES]; -static int shaderAnimCounts[MAX_SHADER_ANIMS] = { - 23, - 25, - 45, - 25, - 23, - 5, -}; -static float shaderAnimSTRatio[MAX_SHADER_ANIMS] = { - 1.405f, - 1.0f, - 1.0f, - 1.0f, - 1.0f, - 1.0f, -}; -static int numShaderAnims; -// done. - -#define PARTICLE_GRAVITY 40 -#define MAX_PARTICLES 1024 * 8 - -cparticle_t *active_particles, *free_particles; -cparticle_t particles[MAX_PARTICLES]; -int cl_numparticles = MAX_PARTICLES; - -qboolean initparticles = qfalse; -vec3_t vforward, vright, vup; -vec3_t rforward, rright, rup; - -float oldtime; - -/* -=============== -CL_ClearParticles -=============== -*/ -void CG_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 = cg.time; - - // Ridah, init the shaderAnims - //for (i=0; shaderAnimNames[i]; i++) { - //TA: figure out this thing works... - i = 0; - { - int j; - - for (j=0; j<shaderAnimCounts[i]; j++) { - shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) ); - } - } - numShaderAnims = i; - // done. - - initparticles = qtrue; -} - - -/* -===================== -CG_AddParticleToScene -===================== -*/ -void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha) -{ - - vec3_t point; - polyVert_t verts[4]; - float width; - float height; - float time, time2; - float ratio; - float invratio; - vec3_t color; - polyVert_t TRIverts[3]; - vec3_t rright2, rup2; - - if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY - || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - {// create a front facing polygon - - if (p->type != P_WEATHER_FLURRY) - { - if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - { - if (org[2] > p->end) - { - p->time = cg.time; - VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground - - p->org[2] = ( p->start + crandom () * 4 ); - - - if (p->type == P_BUBBLE_TURBULENT) - { - p->vel[0] = crandom() * 4; - p->vel[1] = crandom() * 4; - } - - } - } - else - { - if (org[2] < p->end) - { - p->time = cg.time; - VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground - - while (p->org[2] < p->end) - { - p->org[2] += (p->start - p->end); - } - - - if (p->type == P_WEATHER_TURBULENT) - { - p->vel[0] = crandom() * 16; - p->vel[1] = crandom() * 16; - } - - } - } - - - // Rafael snow pvs check - if (!p->link) - return; - - p->alpha = 1; - } - - // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp - if (Distance( cg.snap->ps.origin, org ) > 1024) { - return; - } - // done. - - if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255 * p->alpha; - - VectorMA (org, -p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255 * p->alpha; - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy( point, TRIverts[0].xyz ); - TRIverts[0].st[0] = 1; - TRIverts[0].st[1] = 0; - TRIverts[0].modulate[0] = 255; - TRIverts[0].modulate[1] = 255; - TRIverts[0].modulate[2] = 255; - TRIverts[0].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - VectorCopy (point, TRIverts[1].xyz); - TRIverts[1].st[0] = 0; - TRIverts[1].st[1] = 0; - TRIverts[1].modulate[0] = 255; - TRIverts[1].modulate[1] = 255; - TRIverts[1].modulate[2] = 255; - TRIverts[1].modulate[3] = 255 * p->alpha; - - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - VectorCopy (point, TRIverts[2].xyz); - TRIverts[2].st[0] = 0; - TRIverts[2].st[1] = 1; - TRIverts[2].modulate[0] = 255; - TRIverts[2].modulate[1] = 255; - TRIverts[2].modulate[2] = 255; - TRIverts[2].modulate[3] = 255 * p->alpha; - } - - } - else if (p->type == P_SPRITE) - { - vec3_t rr, ru; - vec3_t rotate_ang; - - VectorSet (color, 1.0, 1.0, 1.0); - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (p->roll) { - vectoangles( cg.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, vup, point); - VectorMA (point, -width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*height, ru, point); - } else { - VectorMA (point, 2*height, vup, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*width, rr, point); - } else { - VectorMA (point, 2*width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, -2*height, ru, point); - } else { - VectorMA (point, -2*height, vup, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - } - else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) - {// create a front rotating facing polygon - - if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) { - return; - } - - if (p->color == BLOODRED) - VectorSet (color, 0.22f, 0.0f, 0.0f); - else if (p->color == GREY75) - { - float len; - float greyit; - float val; - len = Distance (cg.snap->ps.origin, org); - if (!len) - len = 1; - - val = 4096/len; - greyit = 0.25 * val; - if (greyit > 0.5) - greyit = 0.5; - - VectorSet (color, greyit, greyit, greyit); - } - else - VectorSet (color, 1.0, 1.0, 1.0); - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - if (cg.time > p->startfade) - { - invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) ); - - if (p->color == EMISIVEFADE) - { - float fval; - fval = (invratio * invratio); - if (fval < 0) - fval = 0; - VectorSet (color, fval , fval , fval ); - } - invratio *= p->alpha; - } - else - invratio = 1 * p->alpha; - - if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) - invratio = 1; - - if (invratio > 1) - invratio = 1; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (p->type != P_SMOKE_IMPACT) - { - vec3_t temp; - - vectoangles (rforward, temp); - p->accumroll += p->roll; - temp[ROLL] += p->accumroll * 0.1; - AngleVectors ( temp, NULL, rright2, rup2); - } - else - { - VectorCopy (rright, rright2); - VectorCopy (rup, rup2); - } - - if (p->rotate) - { - VectorMA (org, -height, rup2, point); - VectorMA (point, -width, rright2, point); - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, -p->width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255 * color[0]; - verts[0].modulate[1] = 255 * color[1]; - verts[0].modulate[2] = 255 * color[2]; - verts[0].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, -height, rup2, point); - VectorMA (point, width, rright2, point); - } - else - { - VectorMA (org, -p->height, vup, point); - VectorMA (point, p->width, vright, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255 * color[0]; - verts[1].modulate[1] = 255 * color[1]; - verts[1].modulate[2] = 255 * color[2]; - verts[1].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, height, rup2, point); - VectorMA (point, width, rright2, point); - } - else - { - VectorMA (org, p->height, vup, point); - VectorMA (point, p->width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255 * color[0]; - verts[2].modulate[1] = 255 * color[1]; - verts[2].modulate[2] = 255 * color[2]; - verts[2].modulate[3] = 255 * invratio; - - if (p->rotate) - { - VectorMA (org, height, rup2, point); - VectorMA (point, -width, rright2, point); - } - else - { - VectorMA (org, p->height, vup, point); - VectorMA (point, -p->width, vright, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255 * color[0]; - verts[3].modulate[1] = 255 * color[1]; - verts[3].modulate[2] = 255 * color[2]; - verts[3].modulate[3] = 255 * invratio; - - } - else if (p->type == P_BLEED) - { - vec3_t rr, ru; - vec3_t rotate_ang; - float alpha; - - alpha = p->alpha; - - if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) - alpha = 1; - - if (p->roll) - { - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - rotate_ang[ROLL] += p->roll; - AngleVectors ( rotate_ang, NULL, rr, ru); - } - else - { - VectorCopy (vup, ru); - VectorCopy (vright, rr); - } - - VectorMA (org, -p->height, ru, point); - VectorMA (point, -p->width, rr, point); - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 111; - verts[0].modulate[1] = 19; - verts[0].modulate[2] = 9; - verts[0].modulate[3] = 255 * alpha; - - VectorMA (org, -p->height, ru, point); - VectorMA (point, p->width, rr, point); - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 111; - verts[1].modulate[1] = 19; - verts[1].modulate[2] = 9; - verts[1].modulate[3] = 255 * alpha; - - VectorMA (org, p->height, ru, point); - VectorMA (point, p->width, rr, point); - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 111; - verts[2].modulate[1] = 19; - verts[2].modulate[2] = 9; - verts[2].modulate[3] = 255 * alpha; - - VectorMA (org, p->height, ru, point); - VectorMA (point, -p->width, rr, point); - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 111; - verts[3].modulate[1] = 19; - verts[3].modulate[2] = 9; - verts[3].modulate[3] = 255 * alpha; - - } - else if (p->type == P_FLAT_SCALEUP) - { - float width, height; - float sinR, cosR; - - if (p->color == BLOODRED) - VectorSet (color, 1, 1, 1); - else - VectorSet (color, 0.5, 0.5, 0.5); - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - if (width > p->endwidth) - width = p->endwidth; - - if (height > p->endheight) - height = p->endheight; - - sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2); - cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2); - - VectorCopy (org, verts[0].xyz); - verts[0].xyz[0] -= sinR; - verts[0].xyz[1] -= cosR; - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255 * color[0]; - verts[0].modulate[1] = 255 * color[1]; - verts[0].modulate[2] = 255 * color[2]; - verts[0].modulate[3] = 255; - - VectorCopy (org, verts[1].xyz); - verts[1].xyz[0] -= cosR; - verts[1].xyz[1] += sinR; - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255 * color[0]; - verts[1].modulate[1] = 255 * color[1]; - verts[1].modulate[2] = 255 * color[2]; - verts[1].modulate[3] = 255; - - VectorCopy (org, verts[2].xyz); - verts[2].xyz[0] += sinR; - verts[2].xyz[1] += cosR; - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255 * color[0]; - verts[2].modulate[1] = 255 * color[1]; - verts[2].modulate[2] = 255 * color[2]; - verts[2].modulate[3] = 255; - - VectorCopy (org, verts[3].xyz); - verts[3].xyz[0] += cosR; - verts[3].xyz[1] -= sinR; - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255 * color[0]; - verts[3].modulate[1] = 255 * color[1]; - verts[3].modulate[2] = 255 * color[2]; - verts[3].modulate[3] = 255; - } - else if (p->type == P_FLAT) - { - - VectorCopy (org, verts[0].xyz); - verts[0].xyz[0] -= p->height; - verts[0].xyz[1] -= p->width; - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - VectorCopy (org, verts[1].xyz); - verts[1].xyz[0] -= p->height; - verts[1].xyz[1] += p->width; - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - VectorCopy (org, verts[2].xyz); - verts[2].xyz[0] += p->height; - verts[2].xyz[1] += p->width; - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - VectorCopy (org, verts[3].xyz); - verts[3].xyz[0] += p->height; - verts[3].xyz[1] -= p->width; - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - } - // Ridah - else if (p->type == P_ANIM) { - vec3_t rr, ru; - vec3_t rotate_ang; - int i, j; - - time = cg.time - p->time; - time2 = p->endtime - p->time; - ratio = time / time2; - if (ratio >= 1.0f) { - ratio = 0.9999f; - } - - width = p->width + ( ratio * ( p->endwidth - p->width) ); - height = p->height + ( ratio * ( p->endheight - p->height) ); - - // if we are "inside" this sprite, don't draw - if (Distance( cg.snap->ps.origin, org ) < width/1.5) { - return; - } - - i = p->shaderAnim; - j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); - p->pshader = shaderAnims[i][j]; - - if (p->roll) { - vectoangles( cg.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, vup, point); - VectorMA (point, -width, vright, point); - } - VectorCopy (point, verts[0].xyz); - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*height, ru, point); - } else { - VectorMA (point, 2*height, vup, point); - } - VectorCopy (point, verts[1].xyz); - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, 2*width, rr, point); - } else { - VectorMA (point, 2*width, vright, point); - } - VectorCopy (point, verts[2].xyz); - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; - - if (p->roll) { - VectorMA (point, -2*height, ru, point); - } else { - VectorMA (point, -2*height, vup, point); - } - VectorCopy (point, verts[3].xyz); - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - } - // done. - - if (!p->pshader) { -// (SA) temp commented out for DM -// CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); - return; - } - - if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) - trap_R_AddPolyToScene( p->pshader, 3, TRIverts ); - else - trap_R_AddPolyToScene( p->pshader, 4, verts ); - -} - -// Ridah, made this static so it doesn't interfere with other files -static float roll = 0.0; - -/* -=============== -CG_AddParticles -=============== -*/ -void CG_AddParticles (void) -{ - cparticle_t *p, *next; - float alpha; - float time, time2; - vec3_t org; - int color; - cparticle_t *active, *tail; - int type; - vec3_t rotate_ang; - - if (!initparticles) - CG_ClearParticles (); - - VectorCopy( cg.refdef.viewaxis[0], vforward ); - VectorCopy( cg.refdef.viewaxis[1], vright ); - VectorCopy( cg.refdef.viewaxis[2], vup ); - - vectoangles( cg.refdef.viewaxis[0], rotate_ang ); - roll += ((cg.time - oldtime) * 0.1) ; - rotate_ang[ROLL] += (roll*0.9); - AngleVectors ( rotate_ang, rforward, rright, rup); - - oldtime = cg.time; - - active = NULL; - tail = NULL; - - for (p=active_particles ; p ; p=next) - { - - next = p->next; - - time = (cg.time - p->time)*0.001; - - alpha = p->alpha + time*p->alphavel; - if (alpha <= 0) - { // faded out - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - - continue; - } - - } - - if (p->type == P_WEATHER_FLURRY) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - - continue; - } - } - - - if (p->type == P_FLAT_SCALEUP_FADE) - { - if (cg.time > p->endtime) - { - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - } - - if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) { - // temporary sprite - CG_AddParticleToScene (p, p->org, alpha); - p->next = free_particles; - free_particles = p; - p->type = 0; - p->color = 0; - p->alpha = 0; - continue; - } - - p->next = NULL; - if (!tail) - active = tail = p; - else - { - tail->next = p; - tail = p; - } - - if (alpha > 1.0) - alpha = 1; - - color = p->color; - - time2 = time*time; - - org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2; - org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2; - org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2; - - type = p->type; - - CG_AddParticleToScene (p, org, alpha); - } - - active_particles = active; -} - -/* -====================== -CG_AddParticles -====================== -*/ -void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - qboolean turb = qtrue; - - if (!pshader) - CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.90f; - p->alphavel = 0; - - p->start = cent->currentState.origin2[0]; - p->end = cent->currentState.origin2[1]; - - p->endtime = cg.time + cent->currentState.time; - p->startfade = cg.time + cent->currentState.time2; - - p->pshader = pshader; - - if (rand()%100 > 90) - { - p->height = 32; - p->width = 32; - p->alpha = 0.10f; - } - else - { - p->height = 1; - p->width = 1; - } - - p->vel[2] = -20; - - p->type = P_WEATHER_FLURRY; - - if (turb) - p->vel[2] = -10; - - VectorCopy(cent->currentState.origin, p->org); - - p->org[0] = p->org[0]; - p->org[1] = p->org[1]; - p->org[2] = p->org[2]; - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16); - p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16); - p->vel[2] += cent->currentState.angles[2]; - - if (turb) - { - p->accel[0] = crandom () * 16; - p->accel[1] = crandom () * 16; - } - -} - -void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.40f; - p->alphavel = 0; - p->start = origin[2]; - p->end = origin2[2]; - p->pshader = pshader; - p->height = 1; - p->width = 1; - - p->vel[2] = -50; - - if (turb) - { - p->type = P_WEATHER_TURBULENT; - p->vel[2] = -50 * 1.3; - } - else - { - p->type = P_WEATHER; - } - - VectorCopy(origin, p->org); - - p->org[0] = p->org[0] + ( crandom() * range); - p->org[1] = p->org[1] + ( crandom() * range); - p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - if (turb) - { - p->vel[0] = crandom() * 16; - p->vel[1] = crandom() * 16; - } - - // Rafael snow pvs check - p->snum = snum; - p->link = qtrue; - -} - -void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum) -{ - cparticle_t *p; - float randsize; - - if (!pshader) - CG_Printf ("CG_ParticleSnow pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->color = 0; - p->alpha = 0.40f; - p->alphavel = 0; - p->start = origin[2]; - p->end = origin2[2]; - p->pshader = pshader; - - randsize = 1 + (crandom() * 0.5); - - p->height = randsize; - p->width = randsize; - - p->vel[2] = 50 + ( crandom() * 10 ); - - if (turb) - { - p->type = P_BUBBLE_TURBULENT; - p->vel[2] = 50 * 1.3; - } - else - { - p->type = P_BUBBLE; - } - - VectorCopy(origin, p->org); - - p->org[0] = p->org[0] + ( crandom() * range); - p->org[1] = p->org[1] + ( crandom() * range); - p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); - - p->vel[0] = p->vel[1] = 0; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - if (turb) - { - p->vel[0] = crandom() * 4; - p->vel[1] = crandom() * 4; - } - - // Rafael snow pvs check - p->snum = snum; - p->link = qtrue; - -} - -void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent) -{ - - // using cent->density = enttime - // cent->frame = startfade - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleSmoke == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + cent->currentState.time; - p->startfade = cg.time + cent->currentState.time2; - - p->color = 0; - p->alpha = 1.0; - p->alphavel = 0; - p->start = cent->currentState.origin[2]; - p->end = cent->currentState.origin2[2]; - p->pshader = pshader; - p->rotate = qfalse; - p->height = 8; - p->width = 8; - p->endheight = 32; - p->endwidth = 32; - p->type = P_SMOKE; - - VectorCopy(cent->currentState.origin, p->org); - - p->vel[0] = p->vel[1] = 0; - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[2] = 5; - - if (cent->currentState.frame == 1)// reverse gravity - p->vel[2] *= -1; - - p->roll = 8 + (crandom() * 4); -} - - -void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration) -{ - - cparticle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + duration; - p->startfade = cg.time + duration/2; - - p->color = EMISIVEFADE; - p->alpha = 1.0; - p->alphavel = 0; - - p->height = 0.5; - p->width = 0.5; - p->endheight = 0.5; - p->endwidth = 0.5; - - p->pshader = cgs.media.tracerShader; - - p->type = P_SMOKE; - - VectorCopy(org, p->org); - - p->vel[0] = vel[0]; - p->vel[1] = vel[1]; - p->vel[2] = vel[2]; - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->accel[2] = -60; - p->vel[2] += -20; - -} - -/* -====================== -CG_ParticleExplosion -====================== -*/ - -void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd) -{ - cparticle_t *p; - int anim; - - if (animStr < (char *)10) - CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" ); - - // find the animation string - for (anim=0; shaderAnimNames[anim]; anim++) { - if (!Q_stricmp( animStr, shaderAnimNames[anim] )) - break; - } - if (!shaderAnimNames[anim]) { - CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr); - return; - } - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - - if (duration < 0) { - duration *= -1; - p->roll = 0; - } else { - p->roll = crandom()*179; - } - - p->shaderAnim = anim; - - p->width = sizeStart; - p->height = sizeStart*shaderAnimSTRatio[anim]; // for sprites that are stretch in either direction - - p->endheight = sizeEnd; - p->endwidth = sizeEnd*shaderAnimSTRatio[anim]; - - p->endtime = cg.time + duration; - - p->type = P_ANIM; - - VectorCopy( origin, p->org ); - VectorCopy( vel, p->vel ); - VectorClear( p->accel ); - -} - -// Rafael Shrapnel -void CG_AddParticleShrapnel (localEntity_t *le) -{ - return; -} -// done. - -int CG_NewParticleArea (int num) -{ - // const char *str; - char *str; - char *token; - int type; - vec3_t origin, origin2; - int i; - float range = 0; - int turb; - int numparticles; - int snum; - - str = (char *) CG_ConfigString (num); - if (!str[0]) - return (0); - - // returns type 128 64 or 32 - token = COM_Parse (&str); - type = atoi (token); - - if (type == 1) - range = 128; - else if (type == 2) - range = 64; - else if (type == 3) - range = 32; - else if (type == 0) - range = 256; - else if (type == 4) - range = 8; - else if (type == 5) - range = 16; - else if (type == 6) - range = 32; - else if (type == 7) - range = 64; - - - for (i=0; i<3; i++) - { - token = COM_Parse (&str); - origin[i] = atof (token); - } - - for (i=0; i<3; i++) - { - token = COM_Parse (&str); - origin2[i] = atof (token); - } - - token = COM_Parse (&str); - numparticles = atoi (token); - - token = COM_Parse (&str); - turb = atoi (token); - - token = COM_Parse (&str); - snum = atoi (token); - - for (i=0; i<numparticles; i++) - { - if (type >= 4) - CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); - else - CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum); - } - - return (1); -} - -void CG_SnowLink (centity_t *cent, qboolean particleOn) -{ - cparticle_t *p, *next; - int id; - - id = cent->currentState.frame; - - for (p=active_particles ; p ; p=next) - { - next = p->next; - - if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT) - { - if (p->snum == id) - { - if (particleOn) - p->link = qtrue; - else - p->link = qfalse; - } - } - - } -} - -void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 0.25; - p->alphavel = 0; - p->roll = crandom()*179; - - p->pshader = pshader; - - p->endtime = cg.time + 1000; - p->startfade = cg.time + 100; - - p->width = rand()%4 + 8; - p->height = rand()%4 + 8; - - p->endheight = p->height *2; - p->endwidth = p->width * 2; - - p->endtime = cg.time + 500; - - p->type = P_SMOKE_IMPACT; - - VectorCopy( origin, p->org ); - VectorSet(p->vel, 0, 0, 20); - VectorSet(p->accel, 0, 0, 20); - - p->rotate = qtrue; -} - -void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - p->endtime = cg.time + duration; - - if (fleshEntityNum) - p->startfade = cg.time; - else - p->startfade = cg.time + 100; - - p->width = 4; - p->height = 4; - - p->endheight = 4+rand()%3; - p->endwidth = p->endheight; - - p->type = P_SMOKE; - - VectorCopy( start, p->org ); - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = -20; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->color = BLOODRED; - p->alpha = 0.75; - -} - -void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - - int time; - int time2; - float ratio; - - float duration = 1500; - - time = cg.time; - time2 = cg.time + cent->currentState.time; - - ratio =(float)1 - ((float)time / (float)time2); - - if (!pshader) - CG_Printf ("CG_Particle_OilParticle == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - p->endtime = cg.time + duration; - - p->startfade = p->endtime; - - p->width = 1; - p->height = 3; - - p->endheight = 3; - p->endwidth = 1; - - p->type = P_SMOKE; - - VectorCopy(cent->currentState.origin, p->org ); - - p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio)); - p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio)); - p->vel[2] = (cent->currentState.origin2[2]); - - p->snum = 1.0f; - - VectorClear( p->accel ); - - p->accel[2] = -20; - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - -} - - -void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_Particle_OilSlick == ZERO!\n"); - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - if (cent->currentState.angles2[2]) - p->endtime = cg.time + cent->currentState.angles2[2]; - else - p->endtime = cg.time + 60000; - - p->startfade = p->endtime; - - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - if (cent->currentState.angles2[0] || cent->currentState.angles2[1]) - { - p->width = cent->currentState.angles2[0]; - p->height = cent->currentState.angles2[0]; - - p->endheight = cent->currentState.angles2[1]; - p->endwidth = cent->currentState.angles2[1]; - } - else - { - p->width = 8; - p->height = 8; - - p->endheight = 16; - p->endwidth = 16; - } - - p->type = P_FLAT_SCALEUP; - - p->snum = 1.0; - - VectorCopy(cent->currentState.origin, p->org ); - - p->org[2]+= 0.55 + (crandom() * 0.5); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = 0; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - -} - -void CG_OilSlickRemove (centity_t *cent) -{ - cparticle_t *p, *next; - int id; - - id = 1.0f; - - if (!id) - CG_Printf ("CG_OilSlickRevove NULL id\n"); - - for (p=active_particles ; p ; p=next) - { - next = p->next; - - if (p->type == P_FLAT_SCALEUP) - { - if (p->snum == id) - { - p->endtime = cg.time + 100; - p->startfade = p->endtime; - p->type = P_FLAT_SCALEUP_FADE; - - } - } - - } -} - -qboolean ValidBloodPool (vec3_t start) -{ -#define EXTRUDE_DIST 0.5 - - vec3_t angles; - vec3_t right, up; - vec3_t this_pos, x_pos, center_pos, end_pos; - float x, y; - float fwidth, fheight; - trace_t trace; - vec3_t normal; - - fwidth = 16; - fheight = 16; - - VectorSet (normal, 0, 0, 1); - - vectoangles (normal, angles); - AngleVectors (angles, NULL, right, up); - - VectorMA (start, EXTRUDE_DIST, normal, center_pos); - - for (x= -fwidth/2; x<fwidth; x+= fwidth) - { - VectorMA (center_pos, x, right, x_pos); - - for (y= -fheight/2; y<fheight; y+= fheight) - { - VectorMA (x_pos, y, up, this_pos); - VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos); - - CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID); - - - if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world - return qfalse; - - if (!(!trace.startsolid && trace.fraction < 1)) - return qfalse; - - } - } - - return qtrue; -} - -void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr) -{ - cparticle_t *p; - qboolean legit; - vec3_t start; - float rndSize; - - if (!pshader) - CG_Printf ("CG_BloodPool pshader == ZERO!\n"); - - if (!free_particles) - return; - - VectorCopy (tr->endpos, start); - legit = ValidBloodPool (start); - - if (!legit) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + 3000; - p->startfade = p->endtime; - - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = pshader; - - rndSize = 0.4 + random()*0.6; - - p->width = 8*rndSize; - p->height = 8*rndSize; - - p->endheight = 16*rndSize; - p->endwidth = 16*rndSize; - - p->type = P_FLAT_SCALEUP; - - VectorCopy(start, p->org ); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = 0; - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - - p->color = BLOODRED; -} - -#define NORMALSIZE 16 -#define LARGESIZE 32 - -void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir) -{ - float length; - float dist; - float crittersize; - vec3_t angles, forward; - vec3_t point; - cparticle_t *p; - int i; - - dist = 0; - - length = VectorLength (dir); - vectoangles (dir, angles); - AngleVectors (angles, forward, NULL, NULL); - - crittersize = LARGESIZE; - - if (length) - dist = length / crittersize; - - if (dist < 1) - dist = 1; - - VectorCopy (origin, point); - - for (i=0; i<dist; i++) - { - VectorMA (point, crittersize, forward, point); - - if (!free_particles) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = cgs.media.smokePuffShader; - - p->endtime = cg.time + 350 + (crandom() * 100); - - p->startfade = cg.time; - - p->width = LARGESIZE; - p->height = LARGESIZE; - p->endheight = LARGESIZE; - p->endwidth = LARGESIZE; - - p->type = P_SMOKE; - - VectorCopy( origin, p->org ); - - p->vel[0] = 0; - p->vel[1] = 0; - p->vel[2] = -1; - - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->color = BLOODRED; - - p->alpha = 0.75; - - } - - -} - -void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed) -{ - cparticle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - - p->endtime = cg.time + duration; - p->startfade = cg.time + duration/2; - - p->color = EMISIVEFADE; - p->alpha = 0.4f; - p->alphavel = 0; - - p->height = 0.5; - p->width = 0.5; - p->endheight = 0.5; - p->endwidth = 0.5; - - p->pshader = cgs.media.tracerShader; - - p->type = P_SMOKE; - - VectorCopy(org, p->org); - - p->org[0] += (crandom() * x); - p->org[1] += (crandom() * y); - - p->vel[0] = vel[0]; - p->vel[1] = vel[1]; - p->vel[2] = vel[2]; - - p->accel[0] = p->accel[1] = p->accel[2] = 0; - - p->vel[0] += (crandom() * 4); - p->vel[1] += (crandom() * 4); - p->vel[2] += (20 + (crandom() * 10)) * speed; - - p->accel[0] = crandom () * 4; - p->accel[1] = crandom () * 4; - -} - -void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir) -{ - float length; - float dist; - float crittersize; - vec3_t angles, forward; - vec3_t point; - cparticle_t *p; - int i; - - dist = 0; - - VectorNegate (dir, dir); - length = VectorLength (dir); - vectoangles (dir, angles); - AngleVectors (angles, forward, NULL, NULL); - - crittersize = LARGESIZE; - - if (length) - dist = length / crittersize; - - if (dist < 1) - dist = 1; - - VectorCopy (origin, point); - - for (i=0; i<dist; i++) - { - VectorMA (point, crittersize, forward, point); - - if (!free_particles) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - p->time = cg.time; - p->alpha = 5.0; - p->alphavel = 0; - p->roll = 0; - - p->pshader = cgs.media.smokePuffShader; - - // RF, stay around for long enough to expand and dissipate naturally - if (length) - p->endtime = cg.time + 4500 + (crandom() * 3500); - else - p->endtime = cg.time + 750 + (crandom() * 500); - - p->startfade = cg.time; - - p->width = LARGESIZE; - p->height = LARGESIZE; - - // RF, expand while falling - p->endheight = LARGESIZE*3.0; - p->endwidth = LARGESIZE*3.0; - - if (!length) - { - p->width *= 0.2f; - p->height *= 0.2f; - - p->endheight = NORMALSIZE; - p->endwidth = NORMALSIZE; - } - - p->type = P_SMOKE; - - VectorCopy( point, p->org ); - - p->vel[0] = crandom()*6; - p->vel[1] = crandom()*6; - p->vel[2] = random()*20; - - // RF, add some gravity/randomness - p->accel[0] = crandom()*3; - p->accel[1] = crandom()*3; - p->accel[2] = -PARTICLE_GRAVITY*0.4; - - VectorClear( p->accel ); - - p->rotate = qfalse; - - p->roll = rand()%179; - - p->alpha = 0.75; - - } - - -} - -void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha) -{ - cparticle_t *p; - - if (!pshader) - CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n"); - - if (!free_particles) - return; - - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - p->time = cg.time; - p->alpha = 1.0; - p->alphavel = 0; - p->roll = rand()%179; - - p->pshader = pshader; - - if (duration > 0) - p->endtime = cg.time + duration; - else - p->endtime = duration; - - p->startfade = cg.time; - - p->width = size; - p->height = size; - - p->endheight = size; - p->endwidth = size; - - p->type = P_SPRITE; - - VectorCopy( origin, p->org ); - - p->rotate = qfalse; -} diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c index 2ee0c2e5..6843c217 100644 --- a/src/cgame/cg_servercmds.c +++ b/src/cgame/cg_servercmds.c @@ -459,7 +459,10 @@ static void CG_MapRestart( void ) { CG_InitLocalEntities(); CG_InitMarkPolys(); - CG_ClearParticles (); + + // Ridah, trails + CG_ClearTrails (); + // done. // make sure the "3 frags left" warnings play again cg.fraglimitWarnings = 0; diff --git a/src/cgame/cg_trails.c b/src/cgame/cg_trails.c new file mode 100644 index 00000000..9a2bc8a1 --- /dev/null +++ b/src/cgame/cg_trails.c @@ -0,0 +1,728 @@ +// Ridah, cg_trails.c - draws a trail using multiple junction points + +#include "cg_local.h" + +typedef struct trailJunc_s +{ + struct trailJunc_s *nextGlobal, *prevGlobal; // next junction in the global list it is in (free or used) + struct trailJunc_s *nextJunc; // next junction in the trail + struct trailJunc_s *nextHead, *prevHead; // next head junc in the world + + qboolean inuse, freed; + int ownerIndex; + qhandle_t shader; + + int sType; + int flags; + float sTex; + vec3_t pos; + int spawnTime, endTime; + float alphaStart, alphaEnd; + vec3_t colorStart, colorEnd; + float widthStart, widthEnd; + + // current settings + float alpha; + float width; + vec3_t color; + +} trailJunc_t; + +#define MAX_TRAILJUNCS 4096 + +trailJunc_t trailJuncs[MAX_TRAILJUNCS]; +trailJunc_t *freeTrails, *activeTrails; +trailJunc_t *headTrails; + +qboolean initTrails = qfalse; + +int numTrailsInuse; + +/* +=============== +CG_ClearTrails +=============== +*/ +void CG_ClearTrails (void) +{ + int i; + + memset( trailJuncs, 0, sizeof(trailJunc_t) * MAX_TRAILJUNCS ); + + freeTrails = trailJuncs; + activeTrails = NULL; + headTrails = NULL; + + for (i=0 ;i<MAX_TRAILJUNCS ; i++) + { + trailJuncs[i].nextGlobal = &trailJuncs[i+1]; + + if (i>0) + trailJuncs[i].prevGlobal = &trailJuncs[i-1]; + else + trailJuncs[i].prevGlobal = NULL; + + trailJuncs[i].inuse = qfalse; + } + trailJuncs[MAX_TRAILJUNCS-1].nextGlobal = NULL; + + initTrails = qtrue; + numTrailsInuse = 0; +} + +/* +=============== +CG_SpawnTrailJunc +=============== +*/ +trailJunc_t *CG_SpawnTrailJunc( trailJunc_t *headJunc ) +{ + trailJunc_t *j; + + if (!freeTrails) + return NULL; + + if ( cg_paused.integer ) + return NULL; + + // select the first free trail, and remove it from the list + j = freeTrails; + freeTrails = j->nextGlobal; + if (freeTrails) + freeTrails->prevGlobal = NULL; + + j->nextGlobal = activeTrails; + if (activeTrails) + activeTrails->prevGlobal = j; + activeTrails = j; + j->prevGlobal = NULL; + j->inuse = qtrue; + j->freed = qfalse; + + // if this owner has a headJunc, add us to the start + if (headJunc) { + // remove the headJunc from the list of heads + if (headJunc == headTrails) { + headTrails = headJunc->nextHead; + if (headTrails) + headTrails->prevHead = NULL; + } else { + if (headJunc->nextHead) + headJunc->nextHead->prevHead = headJunc->prevHead; + if (headJunc->prevHead) + headJunc->prevHead->nextHead = headJunc->nextHead; + } + headJunc->prevHead = NULL; + headJunc->nextHead = NULL; + } + // make us the headTrail + if (headTrails) + headTrails->prevHead = j; + j->nextHead = headTrails; + j->prevHead = NULL; + headTrails = j; + + j->nextJunc = headJunc; // if headJunc is NULL, then we'll just be the end of the list + + numTrailsInuse++; + + // debugging +// CG_Printf( "NumTrails: %i\n", numTrailsInuse ); + + return j; +} + + +/* +=============== +CG_AddTrailJunc + + returns the index of the trail junction created + + Used for generic trails +=============== +*/ +int CG_AddTrailJunc(int headJuncIndex, qhandle_t shader, int spawnTime, int sType, vec3_t pos, int trailLife, float alphaStart, float alphaEnd, float startWidth, float endWidth, int flags, vec3_t colorStart, vec3_t colorEnd, float sRatio, float animSpeed) +{ + trailJunc_t *j, *headJunc; + + if (headJuncIndex > 0) { + headJunc = &trailJuncs[headJuncIndex-1]; + + if (!headJunc->inuse) + headJunc = NULL; + } + else + headJunc = NULL; + + j = CG_SpawnTrailJunc(headJunc); + if (!j) { +// CG_Printf("couldnt spawn trail junc\n"); + return 0; + } + + if (alphaStart > 1.0) alphaStart = 1.0; + if (alphaStart < 0.0) alphaStart = 0.0; + if (alphaEnd > 1.0) alphaEnd = 1.0; + if (alphaEnd < 0.0) alphaEnd = 0.0; + + // setup the trail junction + j->shader = shader; + j->sType = sType; + VectorCopy( pos, j->pos ); + j->flags = flags; + + j->spawnTime = spawnTime; + j->endTime = spawnTime + trailLife; + + VectorCopy( colorStart, j->colorStart ); + VectorCopy( colorEnd, j->colorEnd ); + + j->alphaStart = alphaStart; + j->alphaEnd = alphaEnd; + + j->widthStart = startWidth; + j->widthEnd = endWidth; + + if (sType == STYPE_REPEAT) { + if (headJunc) { + j->sTex = headJunc->sTex + ((Distance( headJunc->pos, pos ) / sRatio) / j->widthEnd); + } else { + // FIXME: need a way to specify offset timing + j->sTex = (animSpeed * (1.0 - ((float)(cg.time%1000) / 1000.0))) / (sRatio); +// j->sTex = 0; + } + } + + return ((int)(j - trailJuncs) + 1); +} + +/* +=============== +CG_AddSparkJunc + + returns the index of the trail junction created +=============== +*/ +int CG_AddSparkJunc(int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, float alphaStart, float alphaEnd, float startWidth, float endWidth) +{ + trailJunc_t *j, *headJunc; + + if (headJuncIndex > 0) { + headJunc = &trailJuncs[headJuncIndex-1]; + + if (!headJunc->inuse) + headJunc = NULL; + } + else + headJunc = NULL; + + j = CG_SpawnTrailJunc(headJunc); + if (!j) + return 0; + + // setup the trail junction + j->shader = shader; + j->sType = STYPE_STRETCH; + VectorCopy( pos, j->pos ); + j->flags = TJFL_NOCULL; // don't worry about fading up close + + j->spawnTime = cg.time; + j->endTime = cg.time + trailLife; + + VectorSet(j->colorStart, 1.0, 0.8 + 0.2 * alphaStart, 0.4 + 0.4 * alphaStart); + VectorSet(j->colorEnd, 1.0, 0.8 + 0.2 * alphaEnd, 0.4 + 0.4 * alphaEnd); +// VectorScale( j->colorStart, alphaStart, j->colorStart ); +// VectorScale( j->colorEnd, alphaEnd, j->colorEnd ); + + j->alphaStart = alphaStart*2; + j->alphaEnd = alphaEnd*2; +// j->alphaStart = 1.0; +// j->alphaEnd = 1.0; + + j->widthStart = startWidth; + j->widthEnd = endWidth; + + return ((int)(j - trailJuncs) + 1); +} + +/* +=============== +CG_AddSmokeJunc + + returns the index of the trail junction created +=============== +*/ +int CG_AddSmokeJunc(int headJuncIndex, qhandle_t shader, vec3_t pos, int trailLife, float alpha, float startWidth, float endWidth) +{ +#define ST_RATIO 4.0 // sprite image: width / height + trailJunc_t *j, *headJunc; + + if (headJuncIndex > 0) { + headJunc = &trailJuncs[headJuncIndex-1]; + + if (!headJunc->inuse) + headJunc = NULL; + } + else + headJunc = NULL; + + j = CG_SpawnTrailJunc(headJunc); + if (!j) + return 0; + + // setup the trail junction + j->shader = shader; + j->sType = STYPE_REPEAT; + VectorCopy( pos, j->pos ); + j->flags = TJFL_FADEIN; + + j->spawnTime = cg.time; + j->endTime = cg.time + trailLife; + + // VectorSet(j->colorStart, 0.2, 0.2, 0.2); + VectorSet(j->colorStart, 0.0, 0.0, 0.0); + // VectorSet(j->colorEnd, 0.1, 0.1, 0.1); + VectorSet(j->colorEnd, 0.0, 0.0, 0.0); + + j->alphaStart = alpha; + j->alphaEnd = 0.0; + + j->widthStart = startWidth; + j->widthEnd = endWidth; + + if (headJunc) { + j->sTex = headJunc->sTex + ((Distance( headJunc->pos, pos ) / ST_RATIO) / j->widthEnd); + } else { + // first junction, so this will become the "tail" very soon, make it fade out + j->sTex = 0; + j->alphaStart = 0.0; + j->alphaEnd = 0.0; + } + + return ((int)(j - trailJuncs) + 1); +} + +void CG_KillTrail( trailJunc_t *t ); + +/* +=========== +CG_FreeTrailJunc +=========== +*/ +void CG_FreeTrailJunc( trailJunc_t *junc ) +{ + // kill any juncs after us, so they aren't left hanging + if (junc->nextJunc) + CG_KillTrail( junc ); + + // make it non-active + junc->inuse = qfalse; + junc->freed = qtrue; + if (junc->nextGlobal) + junc->nextGlobal->prevGlobal = junc->prevGlobal; + if (junc->prevGlobal) + junc->prevGlobal->nextGlobal = junc->nextGlobal; + if (junc == activeTrails) + activeTrails = junc->nextGlobal; + + // if it's a head, remove it + if (junc == headTrails) + headTrails = junc->nextHead; + if (junc->nextHead) + junc->nextHead->prevHead = junc->prevHead; + if (junc->prevHead) + junc->prevHead->nextHead = junc->nextHead; + junc->nextHead = NULL; + junc->prevHead = NULL; + + // stick it in the free list + junc->prevGlobal = NULL; + junc->nextGlobal = freeTrails; + if (freeTrails) + freeTrails->prevGlobal = junc; + freeTrails = junc; + + numTrailsInuse--; +} + +/* +=========== +CG_KillTrail +=========== +*/ +void CG_KillTrail( trailJunc_t *t ) +{ + trailJunc_t *next; + + next = t->nextJunc; + + // kill the trail here + t->nextJunc = NULL; + + if (next) + CG_FreeTrailJunc( next ); +} + +/* +============== +CG_AddTrailToScene + + TODO: this can do with some major optimization +============== +*/ +static vec3_t vforward, vright, vup; + +//TA: staticised to please QVM + #define MAX_TRAIL_VERTS 2048 +static polyVert_t verts[MAX_TRAIL_VERTS]; +static polyVert_t outVerts[MAX_TRAIL_VERTS*3]; + +void CG_AddTrailToScene( trailJunc_t *trail, int iteration, int numJuncs ) +{ + int k, i, n, l, numOutVerts; + polyVert_t mid; + float mod[4]; + float sInc = 0.0f, s = 0.0f; // TTimo: init + trailJunc_t *j, *jNext; + vec3_t fwd, up, p, v; + // clipping vars + #define TRAIL_FADE_CLOSE_DIST 64.0 + #define TRAIL_FADE_FAR_SCALE 4.0 + vec3_t viewProj; + float viewDist, fadeAlpha; + + // add spark shader at head position + if (trail->flags & TJFL_SPARKHEADFLARE) { + j = trail; + VectorCopy( j->pos, p ); + VectorMA (p, -j->width*2, vup, p); + VectorMA (p, -j->width*2, vright, p); + VectorCopy (p, verts[0].xyz); + verts[0].st[0] = 0; + verts[0].st[1] = 0; + verts[0].modulate[0] = 255; + verts[0].modulate[1] = 255; + verts[0].modulate[2] = 255; + verts[0].modulate[3] = (unsigned char)(j->alpha*255.0); + + VectorCopy( j->pos, p ); + VectorMA (p, -j->width*2, vup, p); + VectorMA (p, j->width*2, vright, p); + VectorCopy (p, verts[1].xyz); + verts[1].st[0] = 0; + verts[1].st[1] = 1; + verts[1].modulate[0] = 255; + verts[1].modulate[1] = 255; + verts[1].modulate[2] = 255; + verts[1].modulate[3] = (unsigned char)(j->alpha*255.0); + + VectorCopy( j->pos, p ); + VectorMA (p, j->width*2, vup, p); + VectorMA (p, j->width*2, vright, p); + VectorCopy (p, verts[2].xyz); + verts[2].st[0] = 1; + verts[2].st[1] = 1; + verts[2].modulate[0] = 255; + verts[2].modulate[1] = 255; + verts[2].modulate[2] = 255; + verts[2].modulate[3] = (unsigned char)(j->alpha*255.0); + + VectorCopy( j->pos, p ); + VectorMA (p, j->width*2, vup, p); + VectorMA (p, -j->width*2, vright, p); + VectorCopy (p, verts[3].xyz); + verts[3].st[0] = 1; + verts[3].st[1] = 0; + verts[3].modulate[0] = 255; + verts[3].modulate[1] = 255; + verts[3].modulate[2] = 255; + verts[3].modulate[3] = (unsigned char)(j->alpha*255.0); + + trap_R_AddPolyToScene( cgs.media.sparkFlareShader, 4, verts ); + } + +// if (trail->flags & TJFL_CROSSOVER && iteration < 1) { +// iteration = 1; +// } + + if (!numJuncs) { + // first count the number of juncs in the trail + j = trail; + numJuncs = 0; + sInc = 0; + while (j) { + numJuncs++; + + // check for a dead next junc + if (!j->inuse && j->nextJunc && !j->nextJunc->inuse) { + CG_KillTrail( j ); + } else if (j->nextJunc && j->nextJunc->freed) { + // not sure how this can happen, but it does, and causes infinite loops + j->nextJunc = NULL; + } + + if (j->nextJunc) + sInc += VectorDistance( j->nextJunc->pos, j->pos ); + + j = j->nextJunc; + } + } + + if (numJuncs < 2) { + return; + } + + if (trail->sType == STYPE_STRETCH) { + //sInc = ((1.0 - 0.1) / (float)(numJuncs)); // hack, the end of funnel shows a bit of the start (looping) + s = 0.05; + //s = 0.05; + } else if (trail->sType == STYPE_REPEAT) { + s = trail->sTex; + } + + // now traverse the list + j = trail; + jNext = j->nextJunc; + i = 0; + while (jNext) { + + // first get the directional vectors to the next junc + VectorSubtract( jNext->pos, j->pos, fwd ); + GetPerpendicularViewVector( cg.refdef.vieworg, j->pos, jNext->pos, up ); + + // if it's a crossover, draw it twice + if (j->flags & TJFL_CROSSOVER) { + if (iteration > 0) { + ProjectPointOntoVector( cg.refdef.vieworg, j->pos, jNext->pos, viewProj ); + VectorSubtract( cg.refdef.vieworg, viewProj, v ); + VectorNormalize( v ); + + if (iteration == 1) { + VectorMA( up, 0.3, v, up ); + } else { + VectorMA( up, -0.3, v, up ); + } + VectorNormalize( up ); + } + } + // do fading when moving towards the projection point onto the trail segment vector + else if (!(j->flags & TJFL_NOCULL) && (j->widthEnd > 4 || jNext->widthEnd > 4)) { + ProjectPointOntoVector( cg.refdef.vieworg, j->pos, jNext->pos, viewProj ); + viewDist = Distance( viewProj, cg.refdef.vieworg ); + if (viewDist < (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE)) { + if (viewDist < TRAIL_FADE_CLOSE_DIST) { + fadeAlpha = 0.0; + } else { + fadeAlpha = (viewDist - TRAIL_FADE_CLOSE_DIST) / (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE); + } + if (fadeAlpha < j->alpha) { + j->alpha = fadeAlpha; + } + if (fadeAlpha < jNext->alpha) { + jNext->alpha = fadeAlpha; + } + } + } + + // now output the QUAD for this segment + + // 1 ---- + VectorMA( j->pos, 0.5*j->width, up, p ); + VectorCopy( p, verts[i].xyz ); + verts[i].st[0] = s; + verts[i].st[1] = 1.0; + for (k=0; k<3; k++) + verts[i].modulate[k] = (unsigned char)(j->color[k]*255.0); + verts[i].modulate[3] = (unsigned char)(j->alpha*255.0); + + // blend this with the previous junc + if (j != trail) { + VectorAdd( verts[i].xyz, verts[i-1].xyz, verts[i].xyz ); + VectorScale( verts[i].xyz, 0.5, verts[i].xyz ); + VectorCopy( verts[i].xyz, verts[i-1].xyz ); + } else if (j->flags & TJFL_FADEIN) { + verts[i].modulate[3] = 0; // fade in + } + + i++; + + // 2 ---- + VectorMA( p, -1*j->width, up, p ); + VectorCopy( p, verts[i].xyz ); + verts[i].st[0] = s; + verts[i].st[1] = 0.0; + for (k=0; k<3; k++) + verts[i].modulate[k] = (unsigned char)(j->color[k]*255.0); + verts[i].modulate[3] = (unsigned char)(j->alpha*255.0); + + // blend this with the previous junc + if (j != trail) { + VectorAdd( verts[i].xyz, verts[i-3].xyz, verts[i].xyz ); + VectorScale( verts[i].xyz, 0.5, verts[i].xyz ); + VectorCopy( verts[i].xyz, verts[i-3].xyz ); + } else if (j->flags & TJFL_FADEIN) { + verts[i].modulate[3] = 0; // fade in + } + + i++; + + if (trail->sType == STYPE_REPEAT) + s = jNext->sTex; + else { + //s += sInc; + s += VectorDistance( j->pos, jNext->pos ) / sInc; + if (s > 1.0) s = 1.0; + } + + // 3 ---- + VectorMA( jNext->pos, -0.5*jNext->width, up, p ); + VectorCopy( p, verts[i].xyz ); + verts[i].st[0] = s; + verts[i].st[1] = 0.0; + for (k=0; k<3; k++) + verts[i].modulate[k] = (unsigned char)(jNext->color[k]*255.0); + verts[i].modulate[3] = (unsigned char)(jNext->alpha*255.0); + i++; + + // 4 ---- + VectorMA( p, jNext->width, up, p ); + VectorCopy( p, verts[i].xyz ); + verts[i].st[0] = s; + verts[i].st[1] = 1.0; + for (k=0; k<3; k++) + verts[i].modulate[k] = (unsigned char)(jNext->color[k]*255.0); + verts[i].modulate[3] = (unsigned char)(jNext->alpha*255.0); + i++; + + if (i+4 > MAX_TRAIL_VERTS) + break; + + j = jNext; + jNext = j->nextJunc; + } + + if (trail->flags & TJFL_FIXDISTORT) { + // build the list of outVerts, by dividing up the QUAD's into 4 Tri's each, so as to allow + // any shaped (convex) Quad without bilinear distortion + for (k=0, numOutVerts=0; k<i; k+=4) { + VectorCopy(verts[k].xyz, mid.xyz); + mid.st[0] = verts[k].st[0]; + mid.st[1] = verts[k].st[1]; + for (l=0; l<4; l++) { + mod[l] = (float)verts[k].modulate[l]; + } + for (n=1; n<4; n++) { + VectorAdd( verts[k+n].xyz, mid.xyz, mid.xyz ); + mid.st[0] += verts[k+n].st[0]; + mid.st[1] += verts[k+n].st[1]; + for (l=0; l<4; l++) { + mod[l] += (float)verts[k+n].modulate[l]; + } + } + VectorScale( mid.xyz, 0.25, mid.xyz ); + mid.st[0] *= 0.25; + mid.st[1] *= 0.25; + for (l=0; l<4; l++) { + mid.modulate[l] = (unsigned char)(mod[l]/4.0); + } + + // now output the tri's + for (n=0; n<4; n++) { + outVerts[numOutVerts++] = verts[k+n]; + outVerts[numOutVerts++] = mid; + if (n<3) { + outVerts[numOutVerts++] = verts[k+n+1]; + } else { + outVerts[numOutVerts++] = verts[k]; + } + } + + } + + if (!(trail->flags & TJFL_NOPOLYMERGE)) { + trap_R_AddPolysToScene( trail->shader, 3, &outVerts[0], numOutVerts/3 ); + } else { + int k; + for (k=0; k<numOutVerts/3; k++) { + trap_R_AddPolyToScene( trail->shader, 3, &outVerts[k*3] ); + } + } + } + else + { + // send the polygons + // FIXME: is it possible to send a GL_STRIP here? We are actually sending 2x the verts we really need to + if (!(trail->flags & TJFL_NOPOLYMERGE)) { + trap_R_AddPolysToScene( trail->shader, 4, &verts[0], i/4 ); + } else { + int k; + for (k=0; k<i/4; k++) { + trap_R_AddPolyToScene( trail->shader, 4, &verts[k*4] ); + } + } + } + + // do we need to make another pass? + if (trail->flags & TJFL_CROSSOVER) { + if (iteration < 2) { + CG_AddTrailToScene( trail, iteration + 1, numJuncs ); + } + } + +} + +/* +=============== +CG_AddTrails +=============== +*/ +void CG_AddTrails(void) +{ + float lifeFrac; + trailJunc_t *j, *jNext; + + if (!initTrails) { + CG_ClearTrails(); + } + + //AngleVectors( cg.snap->ps.viewangles, vforward, vright, vup ); + VectorCopy( cg.refdef.viewaxis[0], vforward ); + VectorCopy( cg.refdef.viewaxis[1], vright ); + VectorCopy( cg.refdef.viewaxis[2], vup ); + + // update the settings for each junc + j = activeTrails; + while (j) { + lifeFrac = (float)(cg.time - j->spawnTime) / (float)(j->endTime - j->spawnTime); + if (lifeFrac >= 1.0) { + j->inuse = qfalse; // flag it as dead + j->width = j->widthEnd; + j->alpha = j->alphaEnd; + if (j->alpha > 1.0) j->alpha = 1.0; + else if (j->alpha < 0.0) j->alpha = 0.0; + VectorCopy( j->colorEnd, j->color ); + } else { + j->width = j->widthStart + (j->widthEnd - j->widthStart) * lifeFrac; + j->alpha = j->alphaStart + (j->alphaEnd - j->alphaStart) * lifeFrac; + if (j->alpha > 1.0) j->alpha = 1.0; + else if (j->alpha < 0.0) j->alpha = 0.0; + VectorSubtract( j->colorEnd, j->colorStart, j->color ); + VectorMA( j->colorStart, lifeFrac, j->color, j->color ); + } + + j = j->nextGlobal; + } + + // draw the trailHeads + j = headTrails; + while (j) { + jNext = j->nextHead; // in case it gets removed + if (!j->inuse) { + CG_FreeTrailJunc(j); + } else { + CG_AddTrailToScene( j, 0, 0 ); + } + j = jNext; + } +} diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index 489faa37..4d63074f 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -1152,8 +1152,10 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); - CG_AddParticles (); CG_AddLocalEntities(); + + //TA: wolf trails stuff + CG_AddTrails( ); // this must come last, so the trails dropped this frame get drawn } CG_AddViewWeapon( &cg.predictedPlayerState ); diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index 7245a870..0c24001a 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -288,7 +288,7 @@ void CG_TeslaTrail( vec3_t start, vec3_t end ) localEntity_t *le; refEntity_t *re; - start[ 2 ] += 12; //nudge up a bit so the bolt comes from the sphere +/* start[ 2 ] += 12; //nudge up a bit so the bolt comes from the sphere //add a bunch of bolt segments le = CG_AllocLocalEntity(); @@ -316,7 +316,21 @@ void CG_TeslaTrail( vec3_t start, vec3_t end ) le->color[2] = 1.0f; le->color[3] = 1.0f; - AxisClear( re->axis ); + AxisClear( re->axis );*/ + + start[ 2 ] += 12; //nudge up a bit so the bolt comes from the sphere + + //add a bunch of bolt segments + le = CG_AllocLocalEntity(); + re = &le->refEntity; + + le->leType = LE_LIGHTNING_BOLT; + le->startTime = cg.time; + le->endTime = cg.time + cg_teslaTrailTime.value; + le->lifeRate = 1.0 / ( le->endTime - le->startTime ); + + VectorCopy( start, re->origin ); + VectorCopy( end, re->oldorigin ); } /* diff --git a/src/game/bg_public.h b/src/game/bg_public.h index 6f383de1..6cc3328b 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -1158,3 +1158,12 @@ qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTi //TA: conceptually should live in q_shared.h void AxisToAngles( vec3_t axis[3], vec3_t angles ); #define Vector2Set(v, x, y) ((v)[0]=(x), (v)[1]=(y)) + +// Ridah +void GetPerpendicularViewVector( const vec3_t point, const vec3_t p1, + const vec3_t p2, vec3_t up ); +void ProjectPointOntoVector( vec3_t point, vec3_t vStart, + vec3_t vEnd, vec3_t vProj ); +float VectorDistance( vec3_t v1, vec3_t v2 ); +// done. + diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 32db11fc..a9021350 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -711,7 +711,7 @@ ZAP ====================================================================== */ -#define AREAZAP_DAMAGE 500.0f +#define AREAZAP_DAMAGE 100.0f /* =============== diff --git a/src/game/q_math.c b/src/game/q_math.c index dd1a532d..9c0e21d7 100644 --- a/src/game/q_math.c +++ b/src/game/q_math.c @@ -1343,3 +1343,51 @@ void PerpendicularVector( vec3_t dst, const vec3_t src ) */ VectorNormalize( dst ); } + +//TA: wolf trail stuff +// Ridah +/* +================= +GetPerpendicularViewVector + + Used to find an "up" vector for drawing a sprite so that it always faces the view as best as possible +================= +*/ +void GetPerpendicularViewVector( const vec3_t point, const vec3_t p1, const vec3_t p2, vec3_t up ) +{ + vec3_t v1, v2; + + VectorSubtract( point, p1, v1 ); + VectorNormalize( v1 ); + + VectorSubtract( point, p2, v2 ); + VectorNormalize( v2 ); + + CrossProduct( v1, v2, up ); + VectorNormalize( up ); +} + +/* +================ +ProjectPointOntoVector +================ +*/ +void ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ) +{ + vec3_t pVec, vec; + + VectorSubtract( point, vStart, pVec ); + VectorSubtract( vEnd, vStart, vec ); + VectorNormalize( vec ); + // project onto the directional vector for this segment + VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj ); +} + +float VectorDistance(vec3_t v1, vec3_t v2) +{ + vec3_t dir; + + VectorSubtract(v2, v1, dir); + return VectorLength(dir); +} +// done. |