r_particle.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "r_local.h"
00026 #include "r_particle.h"
00027 
00028 ptlArt_t r_particlesArt[MAX_PTL_ART];
00029 int r_numParticlesArt;
00030 
00031 ptl_t r_particles[MAX_PTLS];
00032 int r_numParticles;
00033 
00034 /*
00035 =============================================================
00036 PARTICLE DRAWING
00037 =============================================================
00038 */
00039 
00047 static void R_GetSpriteVectors (const ptl_t *p, vec3_t right, vec3_t up)
00048 {
00049     /* get transformation */
00050     switch (p->style) {
00051     case STYLE_FACING:
00052         VectorScale(r_locals.right, p->size[0], right);
00053         VectorScale(r_locals.up, p->size[1], up);
00054         break;
00055 
00056     case STYLE_ROTATED:
00057         AngleVectors(p->angles, NULL, right, up);
00058         VectorScale(right, p->size[0], right);
00059         VectorScale(up, p->size[1], up);
00060         break;
00061 
00062     case STYLE_BEAM:
00063     case STYLE_AXIS:
00064         AngleVectors(p->angles, right, NULL, NULL);
00065         CrossProduct(right, r_locals.forward, up);
00066         VectorNormalize(up);
00067         VectorScale(right, p->size[0], right);
00068         VectorScale(up, p->size[1], up);
00069         break;
00070 
00071     default:
00072         Com_Error(ERR_FATAL, "R_GetSpriteVectors: unknown style");
00073     }
00074 }
00075 
00080 static inline void R_SpriteTexcoords (const ptl_t *p, float out[8])
00081 {
00082     const float s = p->scrollS * refdef.time;
00083     const float t = p->scrollT * refdef.time;
00084 
00085     out[0] = 0.0 + s;
00086     out[1] = 0.0 + t;
00087 
00088     out[2] = 0.0 + s;
00089     out[3] = 1.0 + t;
00090 
00091     out[4] = 1.0 + s;
00092     out[5] = 1.0 + t;
00093 
00094     out[6] = 1.0 + s;
00095     out[7] = 0.0 + t;
00096 }
00097 
00101 static void R_DrawSprite (const ptl_t * p)
00102 {
00103     const ptl_t *q;
00104     vec3_t up, right;
00105     vec3_t nup, nright;
00106     vec3_t pos;
00107     float texcoords[8];
00108 
00109     /* load texture set up coordinates */
00110     assert(p->pic);
00111     R_BindTexture(p->pic->art.image->texnum);
00112 
00113     /* calculate main position and normalised up and right vectors */
00114     q = p->parent ? p->parent : p;
00115     R_GetSpriteVectors(q, right, up);
00116 
00117     /* Calculate normalised */
00118     VectorCopy(up, nup);
00119     VectorCopy(right, nright);
00120     VectorNormalize(nup);
00121     VectorNormalize(nright);
00122 
00123     /* offset */
00124     VectorCopy(q->s, pos);
00125     VectorMA(pos, q->offset[0], nup, pos);
00126     VectorMA(pos, q->offset[1], nright, pos);
00127 
00128     if (p->parent) {
00129         /* if this is a child then calculate our own up and right vectors and offsets */
00130         R_GetSpriteVectors(p, right, up);
00131 
00132         /* but offset by our parent's nup and nright */
00133         VectorMA(pos, p->offset[0], nup, pos);
00134         VectorMA(pos, p->offset[1], nright, pos);
00135     }
00136 
00137     /* center image */
00138     VectorMA(pos, -0.5, up, pos);
00139     VectorMA(pos, -0.5, right, pos);
00140 
00141     R_SpriteTexcoords(p, texcoords);
00142 
00143     R_Color(p->color);
00144     /* draw it */
00145     glBegin(GL_TRIANGLE_FAN);
00146 
00147     glTexCoord2f(texcoords[0], texcoords[1]);
00148     glVertex3fv(pos);
00149 
00150     VectorAdd(pos, up, pos);
00151     glTexCoord2f(texcoords[2], texcoords[3]);
00152     glVertex3fv(pos);
00153 
00154     VectorAdd(pos, right, pos);
00155     glTexCoord2f(texcoords[4], texcoords[5]);
00156     glVertex3fv(pos);
00157 
00158     VectorSubtract(pos, up, pos);
00159     glTexCoord2f(texcoords[6], texcoords[7]);
00160     glVertex3fv(pos);
00161 
00162     glEnd();
00163 }
00164 
00165 
00169 static void R_DrawParticleModel (ptl_t * p)
00170 {
00171     modelInfo_t mi;
00172 
00173     /* initialize model info */
00174     memset(&mi, 0, sizeof(mi));
00175     mi.color = p->color;
00176     mi.origin = p->s;
00177     mi.angles = p->angles;
00178     assert(p->model);
00179     mi.model = p->model->art.model;
00180     mi.skin = p->skin;
00181 
00182     /* draw it */
00183     R_DrawModelParticle(&mi);
00184 }
00185 
00191 static void R_DrawPtlCircle (const ptl_t* p)
00192 {
00193     const float radius = p->size[0];
00194     const int thickness = (int)p->size[1];
00195     float theta;
00196     const float accuracy = 5.0f;
00197 
00198     R_EnableTexture(&texunit_diffuse, qfalse);
00199 
00200     R_Color(p->color);
00201 
00202     glEnable(GL_LINE_SMOOTH);
00203 
00204     assert(radius > thickness);
00205     if (thickness <= 1) {
00206         glBegin(GL_LINE_LOOP);
00207         for (theta = 0.0f; theta < 2.0f * M_PI; theta += M_PI / (radius * accuracy)) {
00208             glVertex3f(p->s[0] + radius * cos(theta), p->s[1] + radius * sin(theta), p->s[2]);
00209         }
00210         glEnd();
00211     } else {
00212         const float delta = M_PI / (radius * accuracy);
00213         glBegin(GL_TRIANGLE_STRIP);
00214         for (theta = 0; theta <= 2 * M_PI; theta += delta) {
00215             const float f = theta - M_PI / (radius * accuracy);
00216             glVertex3f(p->s[0] + radius * cos(theta), p->s[1] + radius * sin(theta), p->s[2]);
00217             glVertex3f(p->s[0] + radius * cos(f), p->s[1] + radius * sin(f), p->s[2]);
00218             glVertex3f(p->s[0] + (radius - thickness) * cos(f), p->s[1] + (radius - thickness) * sin(f), p->s[2]);
00219             glVertex3f(p->s[0] + (radius - thickness) * cos(theta), p->s[1] + (radius - thickness) * sin(theta), p->s[2]);
00220         }
00221         glEnd();
00222     }
00223 
00224     glDisable(GL_LINE_SMOOTH);
00225 
00226     R_EnableTexture(&texunit_diffuse, qtrue);
00227 }
00228 
00232 static void R_DrawPtlLine (const ptl_t * p)
00233 {
00234     R_EnableTexture(&texunit_diffuse, qfalse);
00235 
00236     glEnable(GL_LINE_SMOOTH);
00237 
00238     R_Color(p->color);
00239 
00240     /* draw line from s to v */
00241     glBegin(GL_LINE_STRIP);
00242     glVertex3fv(p->s);
00243     glVertex3fv(p->v);
00244     glEnd();
00245 
00246     glDisable(GL_LINE_SMOOTH);
00247 
00248     R_EnableTexture(&texunit_diffuse, qtrue);
00249 }
00250 
00251 
00252 /*
00253 =============================================================
00254 GENERIC PARTICLE FUNCTIONS
00255 =============================================================
00256 */
00257 
00261 static void R_SetBlendMode (int mode)
00262 {
00263     switch (mode) {
00264     case BLEND_REPLACE:
00265         R_TexEnv(GL_REPLACE);
00266         break;
00267     case BLEND_ONE:
00268         R_BlendFunc(GL_SRC_ALPHA, GL_ONE);
00269         break;
00270     case BLEND_BLEND:
00271         R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00272         break;
00273     case BLEND_ADD:
00274         R_BlendFunc(GL_ONE, GL_ONE);
00275         break;
00276     case BLEND_FILTER:
00277         R_BlendFunc(GL_ZERO, GL_SRC_COLOR);
00278         break;
00279     case BLEND_INVFILTER:
00280         R_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
00281         break;
00282     default:
00283         Com_Error(ERR_DROP, "unknown blend mode");
00284         break;
00285     }
00286 }
00287 
00292 void R_DrawParticles (void)
00293 {
00294     ptl_t *p;
00295     int i;
00296 
00297     for (i = 0, p = r_particles; i < r_numParticles; i++, p++)
00298         if (p->inuse && !p->invis) {
00299             /* test for visibility */
00300             if (p->levelFlags && !((1 << refdef.worldlevel) & p->levelFlags))
00301                 continue;
00302 
00303             if (p->program != NULL)
00304                 R_UseProgram(p->program);
00305 
00306             /* set blend mode and draw gfx */
00307             R_SetBlendMode(p->blend);
00308             switch (p->style) {
00309             case STYLE_LINE:
00310                 R_DrawPtlLine(p);
00311                 break;
00312             case STYLE_CIRCLE:
00313                 R_DrawPtlCircle(p);
00314                 break;
00315             default:
00316                 break;
00317             }
00318             if (p->pic)
00319                 R_DrawSprite(p);
00320             if (p->model)
00321                 R_DrawParticleModel(p);
00322             R_TexEnv(GL_MODULATE);
00323 
00324             R_UseProgram(NULL);
00325         }
00326 
00327     R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00328 
00329     R_Color(NULL);
00330 }

Generated by  doxygen 1.6.2