00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "particles.h"
00026
00027 PARTICLE::PARTICLE()
00028 {
00029 drawlist = 0;
00030
00031
00032
00033 slotguess = 0;
00034
00035 VERTEX direction;
00036 direction.y = 1.0;
00037
00038 params[0].transparency = 1.0;
00039 params[0].longevity = 2.0;
00040 params[0].speed = 0.5;
00041 params[0].direction = direction;
00042 params[0].size = 1.0;
00043
00044 params[1].transparency = 1.0;
00045 params[1].longevity = 2.0;
00046 params[1].speed = 0.5;
00047 params[1].direction = direction;
00048 params[1].size = 1.0;
00049
00050 srand(1337);
00051
00052 curtime = 0;
00053 curtex = 0;
00054
00055 loaded = false;
00056 }
00057
00058 extern bool verbose_output;
00059 PARTICLE::~PARTICLE()
00060 {
00061 if (verbose_output)
00062 cout << "particle deinit" << endl;
00063
00064 if (loaded)
00065 {
00066
00067 glDeleteLists(drawlist, 1);
00068 drawlist = 0;
00069
00070 for (int i = 0; i < PARTICLE_TEXTURES; i++)
00071 {
00072 char fname[128];
00073 sprintf(fname, "smoke/particle%i.png", i);
00074
00075 texture[i].Unload();
00076 }
00077 }
00078 }
00079
00080 void PARTICLE::Load()
00081 {
00082 int i;
00083
00084 if (loaded)
00085 {
00086
00087
00088 for (i = 0; i < PARTICLE_TEXTURES; i++)
00089 {
00090
00091 char fname[128];
00092 sprintf(fname, "smoke/particle%i.png", i);
00093
00094 texture[i].Unload();
00095 }
00096 glDeleteLists(drawlist, 1);
00097 drawlist = 0;
00098 }
00099
00100 for (i = 0; i < MAX_PARTICLES; i++)
00101 {
00102 particle[i].active = false;
00103 }
00104
00105
00106 char fname[128];
00107 for (i = 0; i < PARTICLE_TEXTURES; i++)
00108 {
00109 sprintf(fname, "smoke/particle%i.png", i);
00110
00111
00112 texture[i].Load(fname, false);
00113
00114
00115 }
00116
00117
00118 if (!drawlist)
00119 {
00120 drawlist = glGenLists(1);
00121 glNewList (drawlist, GL_COMPILE);
00122
00123 for (i = 0; i <= NUM_ROTATIONS; i++)
00124 {
00125 float thisrot = 90.0 / (float) NUM_ROTATIONS;
00126 thisrot *= i;
00127
00128 glPushMatrix();
00129 glRotatef(thisrot,0,1,0);
00130
00131 init_draw();
00132 glPopMatrix();
00133
00134
00135
00136
00137
00138
00139
00140
00141 }
00142
00143 glEndList ();
00144 }
00145
00146 curtime = 0;
00147
00148 loaded = true;
00149 }
00150
00151 void PARTICLE::init_draw()
00152 {
00153 float x1 = .5;
00154 float x2 = -.5;
00155 float y1 = .5;
00156 float y2 = -.5;
00157
00158 pheight = y1 - y2;
00159 if (pheight < 0)
00160 pheight = -pheight;
00161
00162 glBegin(GL_QUADS);
00163 glTexCoord2d(0,0);
00164 glVertex3f(x1, y1, 0);
00165
00166 glTexCoord2d(0,1);
00167 glVertex3f(x1, y2, 0);
00168
00169 glTexCoord2d(1,1);
00170 glVertex3f(x2, y2, 0);
00171
00172 glTexCoord2d(1,0);
00173 glVertex3f(x2, y1, 0);
00174 glEnd();
00175 }
00176
00177 void PARTICLE::SetParams(float transmin, float transmax, float longmin, float longmax,
00178 float speedmin, float speedmax, VERTEX direction, float sizemin,
00179 float sizemax)
00180 {
00181 params[0].transparency = transmin;
00182 params[0].longevity = longmin;
00183 params[0].speed = speedmin;
00184 params[0].direction = direction;
00185 params[0].size = sizemin;
00186
00187 params[1].transparency = transmax;
00188 params[1].longevity = longmax;
00189 params[1].speed = speedmax;
00190 params[1].direction = direction;
00191 params[1].size = sizemax;
00192 }
00193
00194 void PARTICLE::AddParticle(VERTEX pos)
00195 {
00196 int idx = slotguess;
00197 int i;
00198 for (i = 0; i < MAX_PARTICLES; i++)
00199 {
00200 if (!particle[idx].active)
00201 {
00202 particle[idx].active = true;
00203 particle[idx].start_position = pos;
00204 VERTEX noise;
00205 float noisemag = 0.1;
00206 noise.x = randf(-noisemag, noisemag);
00207 noise.y = randf(-noisemag, noisemag);
00208 noise.z = randf(-noisemag, noisemag);
00209 particle[idx].direction = (params[0].direction + noise + wind).normalize();
00210 particle[idx].timestamp = curtime;
00211
00212 particle[idx].speed = randf(params[0].speed, params[1].speed);
00213 particle[idx].transparency = randf(params[0].transparency, params[1].transparency);
00214 particle[idx].longevity = randf(params[0].longevity, params[1].longevity);
00215 particle[idx].size = randf(params[0].size, params[1].size);
00216
00217 particle[idx].rotation = randf(0,360);
00218 particle[idx].texture = curtex;
00219 curtex++;
00220 if (curtex >= PARTICLE_TEXTURES)
00221 curtex -= PARTICLE_TEXTURES;
00222
00223 slotguess = idx+1;
00224 if (slotguess >= MAX_PARTICLES)
00225 slotguess = 0;
00226
00227 i = MAX_PARTICLES;
00228 }
00229 else
00230 {
00231 idx++;
00232 if (idx >= MAX_PARTICLES)
00233 idx -= MAX_PARTICLES;
00234 }
00235 }
00236 }
00237
00238 float PARTICLE::randf(float min, float max)
00239 {
00240 if (min > max)
00241 {
00242 float temp = min;
00243 min = max;
00244 max = temp;
00245 }
00246
00247 float r = (float) rand() / (float) RAND_MAX;
00248
00249 r *= max-min;
00250 r += min;
00251 return r;
00252 }
00253
00254 void PARTICLE::Update(float timefactor, float fps)
00255 {
00256 curtime += timefactor/fps;
00257 }
00258
00259 void PARTICLE::Draw()
00260 {
00261 glPushAttrib(GL_ALL_ATTRIB_BITS);
00262 glDisable(GL_LIGHTING);
00263 glEnable(GL_BLEND);
00264 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00265 glDepthMask(0);
00266 int i;
00267 for (i = 0; i < MAX_PARTICLES; i++)
00268 {
00269 if (particle[i].active)
00270 {
00271 if (curtime - particle[i].timestamp > particle[i].longevity)
00272 particle[i].active = false;
00273 else
00274 DrawParticle(particle[i]);
00275 }
00276 }
00277 glDepthMask(1);
00278 glPopAttrib();
00279 }
00280
00281 void PARTICLE::DrawParticle(struct SINGLE_PARTICLE & p)
00282 {
00283 VERTEX drawpos;
00284 drawpos = p.start_position;
00285 float age = curtime - p.timestamp;
00286 VERTEX offset = p.direction.ScaleR(age*p.speed);
00287 drawpos = drawpos + offset;
00288
00289 glPushMatrix();
00290 glTranslatef(drawpos.x, drawpos.y, drawpos.z);
00291
00292 float trans = 0.5;
00293 float sizescale = 1.0;
00294 if (p.longevity > 0)
00295 {
00296 trans = p.transparency*pow((double)(1.0f-age/p.longevity),4.0)*1.0f/((float)NUM_ROTATIONS+1.0f);
00297 float transmax = 0.5/(NUM_ROTATIONS+1.0f);
00298 if (trans > transmax)
00299 trans = transmax;
00300 if (trans < 0.0)
00301 trans = 0.0;
00302
00303 sizescale = 15.0*(age/p.longevity)+1.0;
00304 }
00305 glColor4f(1,1,1,trans);
00306
00307 texture[p.texture].Activate();
00308
00309
00310 glScalef(p.size*sizescale, p.size*sizescale, p.size*sizescale);
00311
00312
00313
00314 glCallList(drawlist);
00315
00316 glPopMatrix();
00317 }
00318
00319 void PARTICLE::ProbAddParticle(VERTEX pos, float probability)
00320 {
00321 float roll = randf(0,1);
00322 if (probability > roll)
00323 {
00324 AddParticle(pos);
00325 }
00326 }
00327
00328 float PARTICLE::ParticleHeight()
00329 {
00330 return pheight;
00331 }
00332
00333 void PARTICLE::ClipParticles(VERTEX * rect)
00334 {
00335
00336
00337 float height = 0;
00338 int j;
00339 for (j = 0; j < 4; j++)
00340 {
00341 height += rect[j].y;
00342 }
00343 height /= 4.0f;
00344
00345 height += 0.2f;
00346
00347 int i;
00348 for (i = 0; i < MAX_PARTICLES; i++)
00349 {
00350 if (particle[i].active)
00351 {
00352 VERTEX drawpos;
00353 drawpos = particle[i].start_position;
00354 float age = curtime - particle[i].timestamp;
00355 VERTEX offset = particle[i].direction.ScaleR(age*particle[i].speed);
00356 drawpos = drawpos + offset;
00357
00358 float dimension = 0.5f;
00359 VERTEX dprect[4];
00360 dprect[0] = drawpos;
00361 dprect[0].x -= dimension;
00362 dprect[0].z -= dimension;
00363 dprect[1] = drawpos;
00364 dprect[1].x -= dimension;
00365 dprect[1].z += dimension;
00366 dprect[2] = drawpos;
00367 dprect[2].x += dimension;
00368 dprect[2].z += dimension;
00369 dprect[3] = drawpos;
00370 dprect[3].x += dimension;
00371 dprect[3].z -= dimension;
00372
00373
00374 if (overlap(rect, dprect) && drawpos.y > height)
00375 {
00376 if (drawpos.y - height <= 0.2)
00377 {
00378 float age = (curtime - particle[i].timestamp);
00379 particle[i].start_position = drawpos;
00380 particle[i].start_position.y = height;
00381 particle[i].longevity = particle[i].longevity - age;
00382 particle[i].timestamp = curtime;
00383 particle[i].transparency = particle[i].transparency*(1.0f-age/particle[i].longevity)*1.0f/((float)NUM_ROTATIONS+1.0f);
00384 }
00385 else
00386 particle[i].active = false;
00387 }
00388 }
00389 }
00390 }
00391
00392 bool PARTICLE::inrect (VERTEX * rect, VERTEX p)
00393 {
00394 int i;
00395
00396 int positive = 0;
00397
00398 float x0, x1, x2, y0, y1, y2;
00399
00400 for (i = 0; i < 4; i++)
00401 {
00402 x2 = p.x;
00403 y2 = p.z;
00404
00405 x0 = rect[i].x;
00406 y0 = rect[i].z;
00407
00408 int nexti = i+1;
00409 if (nexti >= 4)
00410 nexti = 0;
00411 x1 = rect[nexti].x;
00412 y1 = rect[nexti].z;
00413
00414 if ((.5)*(x1*y2 - y1*x2 -x0*y2 + y0*x2 + x0*y1 - y0*x1) < 0)
00415 positive ++;
00416 }
00417
00418 if (positive == 4)
00419 return true;
00420
00421
00422
00423 return false;
00424 }
00425
00426 bool PARTICLE::inrange(float x1, float x2, float val)
00427 {
00428 if (x1 >= x2 && val >= x2 && val <= x1)
00429 return true;
00430 if (x2 > x1 && val <= x2 && val >= x1)
00431 return true;
00432
00433 return false;
00434 }
00435
00436 bool PARTICLE::overlap (VERTEX * rect1, VERTEX * rect2)
00437 {
00438 return (inrect(rect1, rect2[0]) || inrect(rect1, rect2[1])
00439 || inrect(rect1, rect2[2]) || inrect(rect1, rect2[3]));
00440 }
00441
00442 void PARTICLE::Clear()
00443 {
00444 int i;
00445 for (i = 0; i < MAX_PARTICLES; i++)
00446 {
00447 particle[i].active = false;
00448 }
00449 }