Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

cg_marks.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 // cg_marks.c -- wall marks
00024 
00025 #include "cg_local.h"
00026 
00027 /*
00028 ===================================================================
00029 
00030 MARK POLYS
00031 
00032 ===================================================================
00033 */
00034 
00035 
00036 markPoly_t  cg_activeMarkPolys;         // double linked list
00037 markPoly_t  *cg_freeMarkPolys;          // single linked list
00038 markPoly_t  cg_markPolys[MAX_MARK_POLYS];
00039 static      int markTotal;
00040 
00041 /*
00042 ===================
00043 CG_InitMarkPolys
00044 
00045 This is called at startup and for tournement restarts
00046 ===================
00047 */
00048 void    CG_InitMarkPolys( void ) {
00049     int     i;
00050 
00051     memset( cg_markPolys, 0, sizeof(cg_markPolys) );
00052 
00053     cg_activeMarkPolys.nextMark = &cg_activeMarkPolys;
00054     cg_activeMarkPolys.prevMark = &cg_activeMarkPolys;
00055     cg_freeMarkPolys = cg_markPolys;
00056     for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) {
00057         cg_markPolys[i].nextMark = &cg_markPolys[i+1];
00058     }
00059 }
00060 
00061 
00062 /*
00063 ==================
00064 CG_FreeMarkPoly
00065 ==================
00066 */
00067 void CG_FreeMarkPoly( markPoly_t *le ) {
00068     if ( !le->prevMark ) {
00069         CG_Error( "CG_FreeLocalEntity: not active" );
00070     }
00071 
00072     // remove from the doubly linked active list
00073     le->prevMark->nextMark = le->nextMark;
00074     le->nextMark->prevMark = le->prevMark;
00075 
00076     // the free list is only singly linked
00077     le->nextMark = cg_freeMarkPolys;
00078     cg_freeMarkPolys = le;
00079 }
00080 
00081 /*
00082 ===================
00083 CG_AllocMark
00084 
00085 Will allways succeed, even if it requires freeing an old active mark
00086 ===================
00087 */
00088 markPoly_t  *CG_AllocMark( void ) {
00089     markPoly_t  *le;
00090     int time;
00091 
00092     if ( !cg_freeMarkPolys ) {
00093         // no free entities, so free the one at the end of the chain
00094         // remove the oldest active entity
00095         time = cg_activeMarkPolys.prevMark->time;
00096         while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) {
00097             CG_FreeMarkPoly( cg_activeMarkPolys.prevMark );
00098         }
00099     }
00100 
00101     le = cg_freeMarkPolys;
00102     cg_freeMarkPolys = cg_freeMarkPolys->nextMark;
00103 
00104     memset( le, 0, sizeof( *le ) );
00105 
00106     // link into the active list
00107     le->nextMark = cg_activeMarkPolys.nextMark;
00108     le->prevMark = &cg_activeMarkPolys;
00109     cg_activeMarkPolys.nextMark->prevMark = le;
00110     cg_activeMarkPolys.nextMark = le;
00111     return le;
00112 }
00113 
00114 
00115 
00116 /*
00117 =================
00118 CG_ImpactMark
00119 
00120 origin should be a point within a unit of the plane
00121 dir should be the plane normal
00122 
00123 temporary marks will not be stored or randomly oriented, but immediately
00124 passed to the renderer.
00125 =================
00126 */
00127 #define MAX_MARK_FRAGMENTS  128
00128 #define MAX_MARK_POINTS     384
00129 
00130 void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, 
00131                    float orientation, float red, float green, float blue, float alpha,
00132                    qboolean alphaFade, float radius, qboolean temporary ) {
00133     vec3_t          axis[3];
00134     float           texCoordScale;
00135     vec3_t          originalPoints[4];
00136     byte            colors[4];
00137     int             i, j;
00138     int             numFragments;
00139     markFragment_t  markFragments[MAX_MARK_FRAGMENTS], *mf;
00140     vec3_t          markPoints[MAX_MARK_POINTS];
00141     vec3_t          projection;
00142 
00143     if ( !cg_addMarks.integer ) {
00144         return;
00145     }
00146 
00147     if ( radius <= 0 ) {
00148         CG_Error( "CG_ImpactMark called with <= 0 radius" );
00149     }
00150 
00151     //if ( markTotal >= MAX_MARK_POLYS ) {
00152     //  return;
00153     //}
00154 
00155     // create the texture axis
00156     VectorNormalize2( dir, axis[0] );
00157     PerpendicularVector( axis[1], axis[0] );
00158     RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
00159     CrossProduct( axis[0], axis[2], axis[1] );
00160 
00161     texCoordScale = 0.5 * 1.0 / radius;
00162 
00163     // create the full polygon
00164     for ( i = 0 ; i < 3 ; i++ ) {
00165         originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
00166         originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
00167         originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
00168         originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
00169     }
00170 
00171     // get the fragments
00172     VectorScale( dir, -20, projection );
00173     numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints,
00174                     projection, MAX_MARK_POINTS, markPoints[0],
00175                     MAX_MARK_FRAGMENTS, markFragments );
00176 
00177     colors[0] = red * 255;
00178     colors[1] = green * 255;
00179     colors[2] = blue * 255;
00180     colors[3] = alpha * 255;
00181 
00182     for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
00183         polyVert_t  *v;
00184         polyVert_t  verts[MAX_VERTS_ON_POLY];
00185         markPoly_t  *mark;
00186 
00187         // we have an upper limit on the complexity of polygons
00188         // that we store persistantly
00189         if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
00190             mf->numPoints = MAX_VERTS_ON_POLY;
00191         }
00192         for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
00193             vec3_t      delta;
00194 
00195             VectorCopy( markPoints[mf->firstPoint + j], v->xyz );
00196 
00197             VectorSubtract( v->xyz, origin, delta );
00198             v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
00199             v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
00200             *(int *)v->modulate = *(int *)colors;
00201         }
00202 
00203         // if it is a temporary (shadow) mark, add it immediately and forget about it
00204         if ( temporary ) {
00205             trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
00206             continue;
00207         }
00208 
00209         // otherwise save it persistantly
00210         mark = CG_AllocMark();
00211         mark->time = cg.time;
00212         mark->alphaFade = alphaFade;
00213         mark->markShader = markShader;
00214         mark->poly.numVerts = mf->numPoints;
00215         mark->color[0] = red;
00216         mark->color[1] = green;
00217         mark->color[2] = blue;
00218         mark->color[3] = alpha;
00219         memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
00220         markTotal++;
00221     }
00222 }
00223 
00224 
00225 /*
00226 ===============
00227 CG_AddMarks
00228 ===============
00229 */
00230 #define MARK_TOTAL_TIME     10000
00231 #define MARK_FADE_TIME      1000
00232 
00233 void CG_AddMarks( void ) {
00234     int         j;
00235     markPoly_t  *mp, *next;
00236     int         t;
00237     int         fade;
00238 
00239     if ( !cg_addMarks.integer ) {
00240         return;
00241     }
00242 
00243     mp = cg_activeMarkPolys.nextMark;
00244     for ( ; mp != &cg_activeMarkPolys ; mp = next ) {
00245         // grab next now, so if the local entity is freed we
00246         // still have it
00247         next = mp->nextMark;
00248 
00249         // see if it is time to completely remove it
00250         if ( cg.time > mp->time + MARK_TOTAL_TIME ) {
00251             CG_FreeMarkPoly( mp );
00252             continue;
00253         }
00254 
00255         // fade out the energy bursts
00256         if ( mp->markShader == cgs.media.energyMarkShader ) {
00257 
00258             fade = 450 - 450 * ( (cg.time - mp->time ) / 3000.0 );
00259             if ( fade < 255 ) {
00260                 if ( fade < 0 ) {
00261                     fade = 0;
00262                 }
00263                 if ( mp->verts[0].modulate[0] != 0 ) {
00264                     for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
00265                         mp->verts[j].modulate[0] = mp->color[0] * fade;
00266                         mp->verts[j].modulate[1] = mp->color[1] * fade;
00267                         mp->verts[j].modulate[2] = mp->color[2] * fade;
00268                     }
00269                 }
00270             }
00271         }
00272 
00273         // fade all marks out with time
00274         t = mp->time + MARK_TOTAL_TIME - cg.time;
00275         if ( t < MARK_FADE_TIME ) {
00276             fade = 255 * t / MARK_FADE_TIME;
00277             if ( mp->alphaFade ) {
00278                 for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
00279                     mp->verts[j].modulate[3] = fade;
00280                 }
00281             } else {
00282                 for ( j = 0 ; j < mp->poly.numVerts ; j++ ) {
00283                     mp->verts[j].modulate[0] = mp->color[0] * fade;
00284                     mp->verts[j].modulate[1] = mp->color[1] * fade;
00285                     mp->verts[j].modulate[2] = mp->color[2] * fade;
00286                 }
00287             }
00288         }
00289 
00290 
00291         trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts );
00292     }
00293 }
00294 
00295 // cg_particles.c  
00296 
00297 #define BLOODRED    2
00298 #define EMISIVEFADE 3
00299 #define GREY75      4
00300 
00301 typedef struct particle_s
00302 {
00303     struct particle_s   *next;
00304 
00305     float       time;
00306     float       endtime;
00307 
00308     vec3_t      org;
00309     vec3_t      vel;
00310     vec3_t      accel;
00311     int         color;
00312     float       colorvel;
00313     float       alpha;
00314     float       alphavel;
00315     int         type;
00316     qhandle_t   pshader;
00317     
00318     float       height;
00319     float       width;
00320                 
00321     float       endheight;
00322     float       endwidth;
00323     
00324     float       start;
00325     float       end;
00326 
00327     float       startfade;
00328     qboolean    rotate;
00329     int         snum;
00330     
00331     qboolean    link;
00332 
00333     // Ridah
00334     int         shaderAnim;
00335     int         roll;
00336 
00337     int         accumroll;
00338 
00339 } cparticle_t;
00340 
00341 typedef enum
00342 {
00343     P_NONE,
00344     P_WEATHER,
00345     P_FLAT,
00346     P_SMOKE,
00347     P_ROTATE,
00348     P_WEATHER_TURBULENT,
00349     P_ANIM, // Ridah
00350     P_BAT,
00351     P_BLEED,
00352     P_FLAT_SCALEUP,
00353     P_FLAT_SCALEUP_FADE,
00354     P_WEATHER_FLURRY,
00355     P_SMOKE_IMPACT,
00356     P_BUBBLE,
00357     P_BUBBLE_TURBULENT,
00358     P_SPRITE
00359 } particle_type_t;
00360 
00361 #define MAX_SHADER_ANIMS        32
00362 #define MAX_SHADER_ANIM_FRAMES  64
00363 
00364 static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
00365     "explode1",
00366     NULL
00367 };
00368 static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
00369 static int  shaderAnimCounts[MAX_SHADER_ANIMS] = {
00370     23
00371 };
00372 static float    shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
00373     1.0f
00374 };
00375 static int  numShaderAnims;
00376 // done.
00377 
00378 #define     PARTICLE_GRAVITY    40
00379 #define     MAX_PARTICLES   1024
00380 
00381 cparticle_t *active_particles, *free_particles;
00382 cparticle_t particles[MAX_PARTICLES];
00383 int     cl_numparticles = MAX_PARTICLES;
00384 
00385 qboolean        initparticles = qfalse;
00386 vec3_t          pvforward, pvright, pvup;
00387 vec3_t          rforward, rright, rup;
00388 
00389 float           oldtime;
00390 
00391 /*
00392 ===============
00393 CL_ClearParticles
00394 ===============
00395 */
00396 void CG_ClearParticles (void)
00397 {
00398     int     i;
00399 
00400     memset( particles, 0, sizeof(particles) );
00401 
00402     free_particles = &particles[0];
00403     active_particles = NULL;
00404 
00405     for (i=0 ;i<cl_numparticles ; i++)
00406     {
00407         particles[i].next = &particles[i+1];
00408         particles[i].type = 0;
00409     }
00410     particles[cl_numparticles-1].next = NULL;
00411 
00412     oldtime = cg.time;
00413 
00414     // Ridah, init the shaderAnims
00415     for (i=0; shaderAnimNames[i]; i++) {
00416         int j;
00417 
00418         for (j=0; j<shaderAnimCounts[i]; j++) {
00419             shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
00420         }
00421     }
00422     numShaderAnims = i;
00423     // done.
00424 
00425     initparticles = qtrue;
00426 }
00427 
00428 
00429 /*
00430 =====================
00431 CG_AddParticleToScene
00432 =====================
00433 */
00434 void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
00435 {
00436 
00437     vec3_t      point;
00438     polyVert_t  verts[4];
00439     float       width;
00440     float       height;
00441     float       time, time2;
00442     float       ratio;
00443     float       invratio;
00444     vec3_t      color;
00445     polyVert_t  TRIverts[3];
00446     vec3_t      rright2, rup2;
00447 
00448     if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
00449         || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
00450     {// create a front facing polygon
00451             
00452         if (p->type != P_WEATHER_FLURRY)
00453         {
00454             if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
00455             {
00456                 if (org[2] > p->end)            
00457                 {   
00458                     p->time = cg.time;  
00459                     VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
00460                                     
00461                     p->org[2] = ( p->start + crandom () * 4 );
00462                     
00463                     
00464                     if (p->type == P_BUBBLE_TURBULENT)
00465                     {
00466                         p->vel[0] = crandom() * 4;
00467                         p->vel[1] = crandom() * 4;
00468                     }
00469                 
00470                 }
00471             }
00472             else
00473             {
00474                 if (org[2] < p->end)            
00475                 {   
00476                     p->time = cg.time;  
00477                     VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
00478                                     
00479                     while (p->org[2] < p->end) 
00480                     {
00481                         p->org[2] += (p->start - p->end); 
00482                     }
00483                     
00484                     
00485                     if (p->type == P_WEATHER_TURBULENT)
00486                     {
00487                         p->vel[0] = crandom() * 16;
00488                         p->vel[1] = crandom() * 16;
00489                     }
00490                 
00491                 }
00492             }
00493             
00494 
00495             // Rafael snow pvs check
00496             if (!p->link)
00497                 return;
00498 
00499             p->alpha = 1;
00500         }
00501         
00502         // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
00503         if (Distance( cg.snap->ps.origin, org ) > 1024) {
00504             return;
00505         }
00506         // done.
00507     
00508         if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
00509         {
00510             VectorMA (org, -p->height, pvup, point);    
00511             VectorMA (point, -p->width, pvright, point);    
00512             VectorCopy (point, verts[0].xyz);   
00513             verts[0].st[0] = 0; 
00514             verts[0].st[1] = 0; 
00515             verts[0].modulate[0] = 255; 
00516             verts[0].modulate[1] = 255; 
00517             verts[0].modulate[2] = 255; 
00518             verts[0].modulate[3] = 255 * p->alpha;  
00519 
00520             VectorMA (org, -p->height, pvup, point);    
00521             VectorMA (point, p->width, pvright, point); 
00522             VectorCopy (point, verts[1].xyz);   
00523             verts[1].st[0] = 0; 
00524             verts[1].st[1] = 1; 
00525             verts[1].modulate[0] = 255; 
00526             verts[1].modulate[1] = 255; 
00527             verts[1].modulate[2] = 255; 
00528             verts[1].modulate[3] = 255 * p->alpha;  
00529 
00530             VectorMA (org, p->height, pvup, point); 
00531             VectorMA (point, p->width, pvright, point); 
00532             VectorCopy (point, verts[2].xyz);   
00533             verts[2].st[0] = 1; 
00534             verts[2].st[1] = 1; 
00535             verts[2].modulate[0] = 255; 
00536             verts[2].modulate[1] = 255; 
00537             verts[2].modulate[2] = 255; 
00538             verts[2].modulate[3] = 255 * p->alpha;  
00539 
00540             VectorMA (org, p->height, pvup, point); 
00541             VectorMA (point, -p->width, pvright, point);    
00542             VectorCopy (point, verts[3].xyz);   
00543             verts[3].st[0] = 1; 
00544             verts[3].st[1] = 0; 
00545             verts[3].modulate[0] = 255; 
00546             verts[3].modulate[1] = 255; 
00547             verts[3].modulate[2] = 255; 
00548             verts[3].modulate[3] = 255 * p->alpha;  
00549         }
00550         else
00551         {
00552             VectorMA (org, -p->height, pvup, point);    
00553             VectorMA (point, -p->width, pvright, point);    
00554             VectorCopy( point, TRIverts[0].xyz );
00555             TRIverts[0].st[0] = 1;
00556             TRIverts[0].st[1] = 0;
00557             TRIverts[0].modulate[0] = 255;
00558             TRIverts[0].modulate[1] = 255;
00559             TRIverts[0].modulate[2] = 255;
00560             TRIverts[0].modulate[3] = 255 * p->alpha;   
00561 
00562             VectorMA (org, p->height, pvup, point); 
00563             VectorMA (point, -p->width, pvright, point);    
00564             VectorCopy (point, TRIverts[1].xyz);    
00565             TRIverts[1].st[0] = 0;
00566             TRIverts[1].st[1] = 0;
00567             TRIverts[1].modulate[0] = 255;
00568             TRIverts[1].modulate[1] = 255;
00569             TRIverts[1].modulate[2] = 255;
00570             TRIverts[1].modulate[3] = 255 * p->alpha;   
00571 
00572             VectorMA (org, p->height, pvup, point); 
00573             VectorMA (point, p->width, pvright, point); 
00574             VectorCopy (point, TRIverts[2].xyz);    
00575             TRIverts[2].st[0] = 0;
00576             TRIverts[2].st[1] = 1;
00577             TRIverts[2].modulate[0] = 255;
00578             TRIverts[2].modulate[1] = 255;
00579             TRIverts[2].modulate[2] = 255;
00580             TRIverts[2].modulate[3] = 255 * p->alpha;   
00581         }
00582     
00583     }
00584     else if (p->type == P_SPRITE)
00585     {
00586         vec3_t  rr, ru;
00587         vec3_t  rotate_ang;
00588 
00589         VectorSet (color, 1.0, 1.0, 0.5);
00590         time = cg.time - p->time;
00591         time2 = p->endtime - p->time;
00592         ratio = time / time2;
00593 
00594         width = p->width + ( ratio * ( p->endwidth - p->width) );
00595         height = p->height + ( ratio * ( p->endheight - p->height) );
00596 
00597         if (p->roll) {
00598             vectoangles( cg.refdef.viewaxis[0], rotate_ang );
00599             rotate_ang[ROLL] += p->roll;
00600             AngleVectors ( rotate_ang, NULL, rr, ru);
00601         }
00602 
00603         if (p->roll) {
00604             VectorMA (org, -height, ru, point); 
00605             VectorMA (point, -width, rr, point);    
00606         } else {
00607             VectorMA (org, -height, pvup, point);   
00608             VectorMA (point, -width, pvright, point);   
00609         }
00610         VectorCopy (point, verts[0].xyz);   
00611         verts[0].st[0] = 0; 
00612         verts[0].st[1] = 0; 
00613         verts[0].modulate[0] = 255; 
00614         verts[0].modulate[1] = 255; 
00615         verts[0].modulate[2] = 255; 
00616         verts[0].modulate[3] = 255;
00617 
00618         if (p->roll) {
00619             VectorMA (point, 2*height, ru, point);  
00620         } else {
00621             VectorMA (point, 2*height, pvup, point);    
00622         }
00623         VectorCopy (point, verts[1].xyz);   
00624         verts[1].st[0] = 0; 
00625         verts[1].st[1] = 1; 
00626         verts[1].modulate[0] = 255; 
00627         verts[1].modulate[1] = 255; 
00628         verts[1].modulate[2] = 255; 
00629         verts[1].modulate[3] = 255; 
00630 
00631         if (p->roll) {
00632             VectorMA (point, 2*width, rr, point);   
00633         } else {
00634             VectorMA (point, 2*width, pvright, point);  
00635         }
00636         VectorCopy (point, verts[2].xyz);   
00637         verts[2].st[0] = 1; 
00638         verts[2].st[1] = 1; 
00639         verts[2].modulate[0] = 255; 
00640         verts[2].modulate[1] = 255; 
00641         verts[2].modulate[2] = 255; 
00642         verts[2].modulate[3] = 255; 
00643 
00644         if (p->roll) {
00645             VectorMA (point, -2*height, ru, point); 
00646         } else {
00647             VectorMA (point, -2*height, pvup, point);   
00648         }
00649         VectorCopy (point, verts[3].xyz);   
00650         verts[3].st[0] = 1; 
00651         verts[3].st[1] = 0; 
00652         verts[3].modulate[0] = 255; 
00653         verts[3].modulate[1] = 255; 
00654         verts[3].modulate[2] = 255; 
00655         verts[3].modulate[3] = 255; 
00656     }
00657     else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
00658     {// create a front rotating facing polygon
00659 
00660         if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
00661             return;
00662         }
00663 
00664         if (p->color == BLOODRED)
00665             VectorSet (color, 0.22f, 0.0f, 0.0f);
00666         else if (p->color == GREY75)
00667         {
00668             float   len;
00669             float   greyit;
00670             float   val;
00671             len = Distance (cg.snap->ps.origin, org);
00672             if (!len)
00673                 len = 1;
00674 
00675             val = 4096/len;
00676             greyit = 0.25 * val;
00677             if (greyit > 0.5)
00678                 greyit = 0.5;
00679 
00680             VectorSet (color, greyit, greyit, greyit);
00681         }
00682         else
00683             VectorSet (color, 1.0, 1.0, 1.0);
00684 
00685         time = cg.time - p->time;
00686         time2 = p->endtime - p->time;
00687         ratio = time / time2;
00688         
00689         if (cg.time > p->startfade)
00690         {
00691             invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
00692 
00693             if (p->color == EMISIVEFADE)
00694             {
00695                 float fval;
00696                 fval = (invratio * invratio);
00697                 if (fval < 0)
00698                     fval = 0;
00699                 VectorSet (color, fval , fval , fval );
00700             }
00701             invratio *= p->alpha;
00702         }
00703         else 
00704             invratio = 1 * p->alpha;
00705 
00706         if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
00707             invratio = 1;
00708 
00709         if (invratio > 1)
00710             invratio = 1;
00711     
00712         width = p->width + ( ratio * ( p->endwidth - p->width) );
00713         height = p->height + ( ratio * ( p->endheight - p->height) );
00714 
00715         if (p->type != P_SMOKE_IMPACT)
00716         {
00717             vec3_t temp;
00718 
00719             vectoangles (rforward, temp);
00720             p->accumroll += p->roll;
00721             temp[ROLL] += p->accumroll * 0.1;
00722             AngleVectors ( temp, NULL, rright2, rup2);
00723         }
00724         else
00725         {
00726             VectorCopy (rright, rright2);
00727             VectorCopy (rup, rup2);
00728         }
00729         
00730         if (p->rotate)
00731         {
00732             VectorMA (org, -height, rup2, point);   
00733             VectorMA (point, -width, rright2, point);   
00734         }
00735         else
00736         {
00737             VectorMA (org, -p->height, pvup, point);    
00738             VectorMA (point, -p->width, pvright, point);    
00739         }
00740         VectorCopy (point, verts[0].xyz);   
00741         verts[0].st[0] = 0; 
00742         verts[0].st[1] = 0; 
00743         verts[0].modulate[0] = 255 * color[0];  
00744         verts[0].modulate[1] = 255 * color[1];  
00745         verts[0].modulate[2] = 255 * color[2];  
00746         verts[0].modulate[3] = 255 * invratio;  
00747 
00748         if (p->rotate)
00749         {
00750             VectorMA (org, -height, rup2, point);   
00751             VectorMA (point, width, rright2, point);    
00752         }
00753         else
00754         {
00755             VectorMA (org, -p->height, pvup, point);    
00756             VectorMA (point, p->width, pvright, point); 
00757         }
00758         VectorCopy (point, verts[1].xyz);   
00759         verts[1].st[0] = 0; 
00760         verts[1].st[1] = 1; 
00761         verts[1].modulate[0] = 255 * color[0];  
00762         verts[1].modulate[1] = 255 * color[1];  
00763         verts[1].modulate[2] = 255 * color[2];  
00764         verts[1].modulate[3] = 255 * invratio;  
00765 
00766         if (p->rotate)
00767         {
00768             VectorMA (org, height, rup2, point);    
00769             VectorMA (point, width, rright2, point);    
00770         }
00771         else
00772         {
00773             VectorMA (org, p->height, pvup, point); 
00774             VectorMA (point, p->width, pvright, point); 
00775         }
00776         VectorCopy (point, verts[2].xyz);   
00777         verts[2].st[0] = 1; 
00778         verts[2].st[1] = 1; 
00779         verts[2].modulate[0] = 255 * color[0];  
00780         verts[2].modulate[1] = 255 * color[1];  
00781         verts[2].modulate[2] = 255 * color[2];  
00782         verts[2].modulate[3] = 255 * invratio;  
00783 
00784         if (p->rotate)
00785         {
00786             VectorMA (org, height, rup2, point);    
00787             VectorMA (point, -width, rright2, point);   
00788         }
00789         else
00790         {
00791             VectorMA (org, p->height, pvup, point); 
00792             VectorMA (point, -p->width, pvright, point);    
00793         }
00794         VectorCopy (point, verts[3].xyz);   
00795         verts[3].st[0] = 1; 
00796         verts[3].st[1] = 0; 
00797         verts[3].modulate[0] = 255 * color[0];  
00798         verts[3].modulate[1] = 255 * color[1];  
00799         verts[3].modulate[2] = 255 * color[2];  
00800         verts[3].modulate[3] = 255  * invratio; 
00801         
00802     }
00803     else if (p->type == P_BLEED)
00804     {
00805         vec3_t  rr, ru;
00806         vec3_t  rotate_ang;
00807         float   alpha;
00808 
00809         alpha = p->alpha;
00810         
00811         if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
00812             alpha = 1;
00813 
00814         if (p->roll) 
00815         {
00816             vectoangles( cg.refdef.viewaxis[0], rotate_ang );
00817             rotate_ang[ROLL] += p->roll;
00818             AngleVectors ( rotate_ang, NULL, rr, ru);
00819         }
00820         else
00821         {
00822             VectorCopy (pvup, ru);
00823             VectorCopy (pvright, rr);
00824         }
00825 
00826         VectorMA (org, -p->height, ru, point);  
00827         VectorMA (point, -p->width, rr, point); 
00828         VectorCopy (point, verts[0].xyz);   
00829         verts[0].st[0] = 0; 
00830         verts[0].st[1] = 0; 
00831         verts[0].modulate[0] = 111; 
00832         verts[0].modulate[1] = 19;  
00833         verts[0].modulate[2] = 9;   
00834         verts[0].modulate[3] = 255 * alpha; 
00835 
00836         VectorMA (org, -p->height, ru, point);  
00837         VectorMA (point, p->width, rr, point);  
00838         VectorCopy (point, verts[1].xyz);   
00839         verts[1].st[0] = 0; 
00840         verts[1].st[1] = 1; 
00841         verts[1].modulate[0] = 111; 
00842         verts[1].modulate[1] = 19;  
00843         verts[1].modulate[2] = 9;   
00844         verts[1].modulate[3] = 255 * alpha; 
00845 
00846         VectorMA (org, p->height, ru, point);   
00847         VectorMA (point, p->width, rr, point);  
00848         VectorCopy (point, verts[2].xyz);   
00849         verts[2].st[0] = 1; 
00850         verts[2].st[1] = 1; 
00851         verts[2].modulate[0] = 111; 
00852         verts[2].modulate[1] = 19;  
00853         verts[2].modulate[2] = 9;   
00854         verts[2].modulate[3] = 255 * alpha; 
00855 
00856         VectorMA (org, p->height, ru, point);   
00857         VectorMA (point, -p->width, rr, point); 
00858         VectorCopy (point, verts[3].xyz);   
00859         verts[3].st[0] = 1; 
00860         verts[3].st[1] = 0; 
00861         verts[3].modulate[0] = 111; 
00862         verts[3].modulate[1] = 19;  
00863         verts[3].modulate[2] = 9;   
00864         verts[3].modulate[3] = 255 * alpha; 
00865 
00866     }
00867     else if (p->type == P_FLAT_SCALEUP)
00868     {
00869         float width, height;
00870         float sinR, cosR;
00871 
00872         if (p->color == BLOODRED)
00873             VectorSet (color, 1, 1, 1);
00874         else
00875             VectorSet (color, 0.5, 0.5, 0.5);
00876         
00877         time = cg.time - p->time;
00878         time2 = p->endtime - p->time;
00879         ratio = time / time2;
00880 
00881         width = p->width + ( ratio * ( p->endwidth - p->width) );
00882         height = p->height + ( ratio * ( p->endheight - p->height) );
00883 
00884         if (width > p->endwidth)
00885             width = p->endwidth;
00886 
00887         if (height > p->endheight)
00888             height = p->endheight;
00889 
00890         sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
00891         cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
00892 
00893         VectorCopy (org, verts[0].xyz); 
00894         verts[0].xyz[0] -= sinR;
00895         verts[0].xyz[1] -= cosR;
00896         verts[0].st[0] = 0; 
00897         verts[0].st[1] = 0; 
00898         verts[0].modulate[0] = 255 * color[0];  
00899         verts[0].modulate[1] = 255 * color[1];  
00900         verts[0].modulate[2] = 255 * color[2];  
00901         verts[0].modulate[3] = 255; 
00902 
00903         VectorCopy (org, verts[1].xyz); 
00904         verts[1].xyz[0] -= cosR;    
00905         verts[1].xyz[1] += sinR;    
00906         verts[1].st[0] = 0; 
00907         verts[1].st[1] = 1; 
00908         verts[1].modulate[0] = 255 * color[0];  
00909         verts[1].modulate[1] = 255 * color[1];  
00910         verts[1].modulate[2] = 255 * color[2];  
00911         verts[1].modulate[3] = 255; 
00912 
00913         VectorCopy (org, verts[2].xyz); 
00914         verts[2].xyz[0] += sinR;    
00915         verts[2].xyz[1] += cosR;    
00916         verts[2].st[0] = 1; 
00917         verts[2].st[1] = 1; 
00918         verts[2].modulate[0] = 255 * color[0];  
00919         verts[2].modulate[1] = 255 * color[1];  
00920         verts[2].modulate[2] = 255 * color[2];  
00921         verts[2].modulate[3] = 255; 
00922 
00923         VectorCopy (org, verts[3].xyz); 
00924         verts[3].xyz[0] += cosR;    
00925         verts[3].xyz[1] -= sinR;    
00926         verts[3].st[0] = 1; 
00927         verts[3].st[1] = 0; 
00928         verts[3].modulate[0] = 255 * color[0];  
00929         verts[3].modulate[1] = 255 * color[1];  
00930         verts[3].modulate[2] = 255 * color[2];  
00931         verts[3].modulate[3] = 255;     
00932     }
00933     else if (p->type == P_FLAT)
00934     {
00935 
00936         VectorCopy (org, verts[0].xyz); 
00937         verts[0].xyz[0] -= p->height;   
00938         verts[0].xyz[1] -= p->width;    
00939         verts[0].st[0] = 0; 
00940         verts[0].st[1] = 0; 
00941         verts[0].modulate[0] = 255; 
00942         verts[0].modulate[1] = 255; 
00943         verts[0].modulate[2] = 255; 
00944         verts[0].modulate[3] = 255; 
00945 
00946         VectorCopy (org, verts[1].xyz); 
00947         verts[1].xyz[0] -= p->height;   
00948         verts[1].xyz[1] += p->width;    
00949         verts[1].st[0] = 0; 
00950         verts[1].st[1] = 1; 
00951         verts[1].modulate[0] = 255; 
00952         verts[1].modulate[1] = 255; 
00953         verts[1].modulate[2] = 255; 
00954         verts[1].modulate[3] = 255; 
00955 
00956         VectorCopy (org, verts[2].xyz); 
00957         verts[2].xyz[0] += p->height;   
00958         verts[2].xyz[1] += p->width;    
00959         verts[2].st[0] = 1; 
00960         verts[2].st[1] = 1; 
00961         verts[2].modulate[0] = 255; 
00962         verts[2].modulate[1] = 255; 
00963         verts[2].modulate[2] = 255; 
00964         verts[2].modulate[3] = 255; 
00965 
00966         VectorCopy (org, verts[3].xyz); 
00967         verts[3].xyz[0] += p->height;   
00968         verts[3].xyz[1] -= p->width;    
00969         verts[3].st[0] = 1; 
00970         verts[3].st[1] = 0; 
00971         verts[3].modulate[0] = 255; 
00972         verts[3].modulate[1] = 255; 
00973         verts[3].modulate[2] = 255; 
00974         verts[3].modulate[3] = 255; 
00975 
00976     }
00977     // Ridah
00978     else if (p->type == P_ANIM) {
00979         vec3_t  rr, ru;
00980         vec3_t  rotate_ang;
00981         int i, j;
00982 
00983         time = cg.time - p->time;
00984         time2 = p->endtime - p->time;
00985         ratio = time / time2;
00986         if (ratio >= 1.0f) {
00987             ratio = 0.9999f;
00988         }
00989 
00990         width = p->width + ( ratio * ( p->endwidth - p->width) );
00991         height = p->height + ( ratio * ( p->endheight - p->height) );
00992 
00993         // if we are "inside" this sprite, don't draw
00994         if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
00995             return;
00996         }
00997 
00998         i = p->shaderAnim;
00999         j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
01000         p->pshader = shaderAnims[i][j];
01001 
01002         if (p->roll) {
01003             vectoangles( cg.refdef.viewaxis[0], rotate_ang );
01004             rotate_ang[ROLL] += p->roll;
01005             AngleVectors ( rotate_ang, NULL, rr, ru);
01006         }
01007 
01008         if (p->roll) {
01009             VectorMA (org, -height, ru, point); 
01010             VectorMA (point, -width, rr, point);    
01011         } else {
01012             VectorMA (org, -height, pvup, point);   
01013             VectorMA (point, -width, pvright, point);   
01014         }
01015         VectorCopy (point, verts[0].xyz);   
01016         verts[0].st[0] = 0; 
01017         verts[0].st[1] = 0; 
01018         verts[0].modulate[0] = 255; 
01019         verts[0].modulate[1] = 255; 
01020         verts[0].modulate[2] = 255; 
01021         verts[0].modulate[3] = 255;
01022 
01023         if (p->roll) {
01024             VectorMA (point, 2*height, ru, point);  
01025         } else {
01026             VectorMA (point, 2*height, pvup, point);    
01027         }
01028         VectorCopy (point, verts[1].xyz);   
01029         verts[1].st[0] = 0; 
01030         verts[1].st[1] = 1; 
01031         verts[1].modulate[0] = 255; 
01032         verts[1].modulate[1] = 255; 
01033         verts[1].modulate[2] = 255; 
01034         verts[1].modulate[3] = 255; 
01035 
01036         if (p->roll) {
01037             VectorMA (point, 2*width, rr, point);   
01038         } else {
01039             VectorMA (point, 2*width, pvright, point);  
01040         }
01041         VectorCopy (point, verts[2].xyz);   
01042         verts[2].st[0] = 1; 
01043         verts[2].st[1] = 1; 
01044         verts[2].modulate[0] = 255; 
01045         verts[2].modulate[1] = 255; 
01046         verts[2].modulate[2] = 255; 
01047         verts[2].modulate[3] = 255; 
01048 
01049         if (p->roll) {
01050             VectorMA (point, -2*height, ru, point); 
01051         } else {
01052             VectorMA (point, -2*height, pvup, point);   
01053         }
01054         VectorCopy (point, verts[3].xyz);   
01055         verts[3].st[0] = 1; 
01056         verts[3].st[1] = 0; 
01057         verts[3].modulate[0] = 255; 
01058         verts[3].modulate[1] = 255; 
01059         verts[3].modulate[2] = 255; 
01060         verts[3].modulate[3] = 255; 
01061     }
01062     // done.
01063     
01064     if (!p->pshader) {
01065 // (SA) temp commented out for DM
01066 //      CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
01067         return;
01068     }
01069 
01070     if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
01071         trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
01072     else
01073         trap_R_AddPolyToScene( p->pshader, 4, verts );
01074 
01075 }
01076 
01077 // Ridah, made this static so it doesn't interfere with other files
01078 static float roll = 0.0;
01079 
01080 /*
01081 ===============
01082 CG_AddParticles
01083 ===============
01084 */
01085 void CG_AddParticles (void)
01086 {
01087     cparticle_t     *p, *next;
01088     float           alpha;
01089     float           time, time2;
01090     vec3_t          org;
01091     int             color;
01092     cparticle_t     *active, *tail;
01093     int             type;
01094     vec3_t          rotate_ang;
01095 
01096     if (!initparticles)
01097         CG_ClearParticles ();
01098 
01099     VectorCopy( cg.refdef.viewaxis[0], pvforward );
01100     VectorCopy( cg.refdef.viewaxis[1], pvright );
01101     VectorCopy( cg.refdef.viewaxis[2], pvup );
01102 
01103     vectoangles( cg.refdef.viewaxis[0], rotate_ang );
01104     roll += ((cg.time - oldtime) * 0.1) ;
01105     rotate_ang[ROLL] += (roll*0.9);
01106     AngleVectors ( rotate_ang, rforward, rright, rup);
01107     
01108     oldtime = cg.time;
01109 
01110     active = NULL;
01111     tail = NULL;
01112 
01113     for (p=active_particles ; p ; p=next)
01114     {
01115 
01116         next = p->next;
01117 
01118         time = (cg.time - p->time)*0.001;
01119 
01120         alpha = p->alpha + time*p->alphavel;
01121         if (alpha <= 0)
01122         {   // faded out
01123             p->next = free_particles;
01124             free_particles = p;
01125             p->type = 0;
01126             p->color = 0;
01127             p->alpha = 0;
01128             continue;
01129         }
01130 
01131         if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
01132         {
01133             if (cg.time > p->endtime)
01134             {
01135                 p->next = free_particles;
01136                 free_particles = p;
01137                 p->type = 0;
01138                 p->color = 0;
01139                 p->alpha = 0;
01140             
01141                 continue;
01142             }
01143 
01144         }
01145 
01146         if (p->type == P_WEATHER_FLURRY)
01147         {
01148             if (cg.time > p->endtime)
01149             {
01150                 p->next = free_particles;
01151                 free_particles = p;
01152                 p->type = 0;
01153                 p->color = 0;
01154                 p->alpha = 0;
01155             
01156                 continue;
01157             }
01158         }
01159 
01160 
01161         if (p->type == P_FLAT_SCALEUP_FADE)
01162         {
01163             if (cg.time > p->endtime)
01164             {
01165                 p->next = free_particles;
01166                 free_particles = p;
01167                 p->type = 0;
01168                 p->color = 0;
01169                 p->alpha = 0;
01170                 continue;
01171             }
01172 
01173         }
01174 
01175         if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
01176