00001
00002
00003 #include "ParticleSystem.h"
00004
00005 #include "MathUtils.h"
00006 #include "Renderer.h"
00007 #include "Texture.h"
00008 #include "TextureDatabase.h"
00009
00010
00011 namespace pge {
00012
00013
00014
00015
00016
00017
00018
00019 ParticleSystem::ParticleSystem(const std::string &textureFile, Vector3f startPoint, Vector3f direction, int particleNum) {
00020 m_startPoint = startPoint;
00021 m_startDirection = direction;
00022 m_startDirection.normalize();
00023
00024
00025
00026 m_particleNum = particleNum;
00027 m_distribution = 10;
00028 m_size = 32.0f;
00029 m_velocity = 0.1f;
00030
00031 m_lifeDeg = 0.1f;
00032
00033
00034 glGetFloatv(GL_POINT_SIZE_MAX_ARB, &m_maxSizeExt);
00035
00036
00037 m_startFade = Vector3f();
00038 m_endFade = Vector3f();
00039 m_fadeEnabled = false;
00040
00041
00042 m_gravity = Vector3f(0.0f, -0.98f, 0.0f);
00043
00044
00045 m_billboard = true;
00046 m_usePointSpriteExt = true;
00047
00048
00049 m_loopMode = ParticleLoopForever;
00050
00051 m_active = false;
00052
00053
00054 m_particleArray = new Particle[m_particleNum];
00055
00056 reset();
00057
00058 m_texture = TextureDatabase::getInstance()->addTexture(textureFile);
00059 }
00060
00061
00062
00063
00064
00065
00066
00067 ParticleSystem::~ParticleSystem(void) {
00068 if(m_particleArray != NULL) {
00069 delete [] m_particleArray;
00070 m_particleArray = NULL;
00071 }
00072 }
00073
00074
00075
00076
00077
00078
00079
00080 void ParticleSystem::setDirection(Vector3f direction) {
00081 m_startDirection = direction;
00082 m_startDirection.normalize();
00083 reset();
00084 }
00085
00086
00087
00088
00089
00090
00091
00092 void ParticleSystem::setStartPoint(Vector3f start) {
00093 m_startPoint = start;
00094 reset();
00095 }
00096
00097
00098
00099
00100
00101
00102
00103 void ParticleSystem::setGravity(Vector3f gravity) {
00104 m_gravity = gravity;
00105 }
00106
00107
00108
00109
00110
00111
00112
00113 void ParticleSystem::setFadeOutStart(Vector3f start) {
00114 m_startFade = start;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123 void ParticleSystem::setFadeOutEnd(Vector3f end) {
00124 m_endFade = end;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133 void ParticleSystem::setFadeOutEnabled(bool enabled) {
00134 m_fadeEnabled = enabled;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 void ParticleSystem::setLifeDegeneration(float lifeDeg) {
00144 m_lifeDeg = lifeDeg;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 void ParticleSystem::setLoopMode(ParticleLoopMode mode) {
00154 m_loopMode = mode;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163 void ParticleSystem::setTexture(Texture *texture) {
00164 m_texture = texture;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173 void ParticleSystem::setParticleNum(int num) {
00174 if(num > 0) {
00175 m_particleNum = num;
00176
00177 if(m_particleArray != NULL) {
00178 delete [] m_particleArray;
00179 m_particleArray = NULL;
00180 }
00181
00182 m_particleArray = new Particle[m_particleNum];
00183 reset();
00184 }
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 void ParticleSystem::setParticleSize(float size) {
00194
00195 if(size <= m_maxSizeExt) {
00196 m_size = size;
00197 } else {
00198 m_size = m_maxSizeExt;
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 void ParticleSystem::setDistribution(int dist) {
00209 if(dist > 0) {
00210 m_distribution = dist;
00211 reset();
00212 }
00213 }
00214
00215
00216
00217
00218
00219
00220
00221 void ParticleSystem::setVelocity(float velocity) {
00222 if(velocity > 0.0f) {
00223 m_velocity = velocity;
00224 }
00225 }
00226
00227
00228
00229
00230
00231
00232
00233 void ParticleSystem::activate(void) {
00234 reset();
00235 m_active = true;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 void ParticleSystem::deactivate(void) {
00245 m_active = false;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254 void ParticleSystem::reset(void) {
00255 int i;
00256
00257 for(i = 0; i < m_particleNum; i++) {
00258 resetParticle(&m_particleArray[i]);
00259 }
00260 }
00261
00262
00263
00264
00265
00266
00267
00268 bool ParticleSystem::init(void) {
00269 return true;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278 void ParticleSystem::render(void) {
00279
00280
00281
00282 int i;
00283 float x;
00284 float y;
00285 float z;
00286 float mat[16];
00287 Vector3f right;
00288 Vector3f up;
00289
00290
00291
00292 if(m_active) {
00293
00294
00295
00296
00297 renderer::setTextureAlphaBlendEnabled(true);
00298
00299
00300
00301 if(m_texture != NULL) {
00302
00303
00304
00305 renderer::setTexture(m_texture, GL_MODULATE);
00306 }
00307
00308
00309 if(m_usePointSpriteExt) {
00310 glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
00311 }
00312
00313
00314
00315
00316
00317 if(m_billboard && !m_usePointSpriteExt) {
00318 glGetFloatv(GL_MODELVIEW_MATRIX, mat);
00319
00320 right = Vector3f(mat[0], mat[4], mat[8]);
00321 up = Vector3f(mat[1], mat[5], mat[9]);
00322 }
00323
00324
00325 for(i = 0; i < m_particleNum; i++) {
00326
00327
00328 x = m_particleArray[i].m_position.m_v[0];
00329 y = m_particleArray[i].m_position.m_v[1];
00330 z = m_particleArray[i].m_position.m_v[2];
00331
00332
00333 if(m_fadeEnabled) {
00334 float alpha = 1.0f;
00335 float distanceToStart;
00336 float distanceToEnd;
00337 float distanceStartEnd;
00338
00339 distanceToStart = m_particleArray[i].m_position.sqrDistance(m_startFade);
00340 distanceToEnd = m_particleArray[i].m_position.sqrDistance(m_endFade);
00341 distanceStartEnd = m_startFade.sqrDistance(m_endFade);
00342
00343
00344
00345
00346 if(distanceToStart <= distanceStartEnd && distanceToEnd <= distanceStartEnd) {
00347
00348
00349
00350 if(distanceStartEnd == 0.0f) {
00351 distanceStartEnd = 1.0f;
00352 }
00353 alpha = distanceToEnd / distanceStartEnd;
00354 }
00355
00356
00357
00358
00359
00360
00361 if(distanceToStart > distanceToEnd && distanceToStart > distanceStartEnd
00362 && distanceToEnd <= distanceStartEnd) {
00363 alpha = 0.0f;
00364 m_particleArray[i].m_life = 0.0f;
00365 }
00366
00367
00369
00370 renderer::color4f(1.0f, 1.0f, 1.0f, alpha);
00371
00372
00373
00374
00375
00376 } else {
00377
00378 renderer::color4f(1.0f, 1.0f, 1.0f, 1.0f);
00379
00380
00381
00382 }
00383
00384
00385 if(!m_billboard && !m_usePointSpriteExt) {
00386
00387
00388
00389 glBegin(GL_TRIANGLE_STRIP);
00390
00391 renderer::vertex3f(x + (m_size / 2.0f), y + (m_size / 2.0f), z, 1.0f, 1.0f);
00392
00393 renderer::vertex3f(x - (m_size / 2.0f), y + (m_size / 2.0f), z, 0.0f, 1.0f);
00394
00395 renderer::vertex3f(x + (m_size / 2.0f), y - (m_size / 2.0f), z, 1.0f, 0.0f);
00396
00397 renderer::vertex3f(x - (m_size / 2.0f), y - (m_size / 2.0f), z, 0.0f, 0.0f);
00398 glEnd();
00399
00400
00401 } else if(m_billboard && !m_usePointSpriteExt) {
00402 Vector3f pos = Vector3f(x, y, z);
00403
00404
00405
00406 glBegin(GL_QUADS);
00407
00408 renderer::vertex3f(pos.add(right.add(up).multiply(-m_size)), 0.0f, 0.0f);
00409
00410 renderer::vertex3f(pos.add(right.subtract(up).multiply(m_size)), 1.0f, 0.0f);
00411
00412 renderer::vertex3f(pos.add(right.add(up).multiply(m_size)), 1.0f, 1.0f);
00413
00414 renderer::vertex3f(pos.add(up.subtract(right).multiply(m_size)), 0.0f, 1.0f);
00415 glEnd();
00416
00417
00418 } else if(m_usePointSpriteExt) {
00419
00420
00421
00422 float quadratic[3];
00423 quadratic[0] = 1.0f;
00424 quadratic[1] = 0.1f;
00425 quadratic[2] = 0.01f;
00426
00427
00428 glEnable(GL_POINT_SPRITE);
00429 glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, quadratic);
00430 glPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f);
00431 glPointParameterf(GL_POINT_SIZE_MIN, 1.0f);
00432 glPointParameterf(GL_POINT_SIZE_MAX, m_maxSizeExt);
00433 glPointSize(m_size);
00434
00435
00436 glBegin(GL_POINTS);
00437 renderer::vertex3f(x, y, z);
00438 glEnd();
00439
00440 glDisable(GL_POINT_SPRITE);
00441 }
00442 }
00443
00444 renderer::color4f(1.0f, 1.0f, 1.0f, 1.0f);
00445 renderer::setTextureAlphaBlendEnabled(false);
00446
00447 }
00448 }
00449
00450
00451
00452
00453
00454
00455
00456 void ParticleSystem::timer(unsigned int delay) {
00457 bool allDead;
00458 int i;
00459
00460 if(m_active) {
00461
00462 allDead = true;
00463
00464
00465 for(i = 0; i < m_particleNum; i++) {
00466
00467
00468 m_particleArray[i].m_position.m_v[0] += m_particleArray[i].m_direction.m_v[0] * m_velocity;
00469 m_particleArray[i].m_position.m_v[1] += m_particleArray[i].m_direction.m_v[1] * m_velocity;
00470 m_particleArray[i].m_position.m_v[2] += m_particleArray[i].m_direction.m_v[2] * m_velocity;
00471
00472
00473 m_particleArray[i].m_direction.m_v[0] += m_gravity.m_v[0];
00474 m_particleArray[i].m_direction.m_v[1] += m_gravity.m_v[1];
00475 m_particleArray[i].m_direction.m_v[2] += m_gravity.m_v[2];
00476
00477 m_particleArray[i].m_life -= m_lifeDeg;
00478
00479
00480
00481 if(m_loopMode == ParticleLoopForever) {
00482
00483 if(m_particleArray[i].m_life <= 0.0f) {
00484 resetParticle(&m_particleArray[i]);
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 } else if(m_loopMode == ParticlePlayOnce) {
00494 if(m_particleArray[i].m_life > 0.0f) {
00495 allDead = false;
00496 }
00497 }
00498 }
00499
00500
00501
00502 if(m_loopMode == ParticlePlayOnce && allDead) {
00503 m_active = false;
00504 }
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513
00514 void ParticleSystem::resetParticle(Particle *particle) {
00515
00516
00517 particle->m_position.m_v[0] = m_startPoint.m_v[0];
00518 particle->m_position.m_v[1] = m_startPoint.m_v[1];
00519 particle->m_position.m_v[2] = m_startPoint.m_v[2];
00520
00521
00522 particle->m_direction.m_v[0] = m_startDirection.m_v[0] * (float)((rand() % m_distribution) - (m_distribution / 2));
00523 particle->m_direction.m_v[1] = m_startDirection.m_v[1] * (float)((rand() % m_distribution) - (m_distribution / 2));
00524 particle->m_direction.m_v[2] = m_startDirection.m_v[2] * (float)((rand() % m_distribution) - (m_distribution / 2));
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 particle->m_life = 1.0f * (mathutils::random() * 2.0f);
00536 }
00537 };