00001
00002
00003
00004
00005
00006
00007
00009
00010 #include "particle_system.h"
00011 #include "particle_keyframe.h"
00012 #include "video.h"
00013
00014 using namespace std;
00015 using namespace hoa_utils;
00016
00017 namespace hoa_video
00018 {
00019
00020 namespace private_video
00021 {
00022
00023
00024
00025
00026
00027
00028 ParticleSystem::ParticleSystem()
00029 {
00030 _system_def = NULL;
00031 _max_particles = 0;
00032 _num_particles = 0;
00033 _age = 0.0f;
00034 _last_update_time = 0.0f;
00035
00036 _alive = true;
00037 _stopped = false;
00038 }
00039
00040
00041
00042
00043
00044
00045 bool ParticleSystem::Create(const ParticleSystemDef *sys_def)
00046 {
00047 _system_def = sys_def;
00048 _max_particles = sys_def->max_particles;
00049 _num_particles = 0;
00050
00051 _particles.resize(_max_particles);
00052 _particle_vertices.resize(_max_particles * 4);
00053 _particle_texcoords.resize(_max_particles * 4);
00054 _particle_colors.resize(_max_particles * 4);
00055
00056 _alive = true;
00057 _stopped = false;
00058 _age = 0.0f;
00059
00060 size_t num_frames = sys_def->animation_frame_filenames.size();
00061
00062 for(size_t j = 0; j < num_frames; ++j)
00063 {
00064 int32 frame_time;
00065 if(j < sys_def->animation_frame_times.size())
00066 frame_time = sys_def->animation_frame_times[j];
00067 else if(sys_def->animation_frame_times.empty())
00068 frame_time = 0;
00069 else
00070 frame_time = sys_def->animation_frame_times.back();
00071
00072 _animation.AddFrame(sys_def->animation_frame_filenames[j], frame_time);
00073 }
00074
00075 VideoManager->LoadImage(_animation);
00076 return true;
00077 }
00078
00079
00080
00081
00082
00083
00084
00085 bool ParticleSystem::Draw()
00086 {
00087 if(!_system_def->enabled || _age < _system_def->emitter._start_time)
00088 return true;
00089
00090
00091 if(_system_def->blend_mode == VIDEO_NO_BLEND)
00092 {
00093 glDisable(GL_BLEND);
00094 }
00095 else
00096 {
00097 glEnable(GL_BLEND);
00098
00099 if(_system_def->blend_mode == VIDEO_BLEND)
00100 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00101 else
00102 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00103 }
00104
00105
00106 if(_system_def->use_stencil)
00107 {
00108 glEnable(GL_STENCIL_TEST);
00109 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
00110 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00111 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00112 }
00113 else if(_system_def->modify_stencil)
00114 {
00115 glEnable(GL_STENCIL_TEST);
00116
00117 if(_system_def->stencil_op == VIDEO_STENCIL_OP_INCREASE)
00118 glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
00119 else if(_system_def->stencil_op == VIDEO_STENCIL_OP_DECREASE)
00120 glStencilOp(GL_DECR, GL_KEEP, GL_KEEP);
00121 else if(_system_def->stencil_op == VIDEO_STENCIL_OP_ZERO)
00122 glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
00123 else
00124 glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
00125
00126 glStencilFunc(GL_NEVER, 1, 0xFFFFFFFF);
00127 glEnable(GL_ALPHA_TEST);
00128 glAlphaFunc(GL_GREATER, 0.00f);
00129 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00130
00131 }
00132 else
00133 {
00134 glDisable(GL_STENCIL_TEST);
00135 glDisable(GL_ALPHA_TEST);
00136 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00137 }
00138
00139 glEnable(GL_TEXTURE_2D);
00140
00141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00143
00144 StillImage *id = _animation.GetFrame(_animation.GetCurrentFrameIndex());
00145 Image *img = id->_elements[0].image;
00146 VideoManager->_BindTexture(img->texture_sheet->tex_ID);
00147
00148
00149 float frame_progress = _animation.GetPercentProgress();
00150
00151 float u1 = img->u1;
00152 float u2 = img->u2;
00153 float v1 = img->v1;
00154 float v2 = img->v2;
00155
00156 float img_width = static_cast<float>(img->width);
00157 float img_height = static_cast<float>(img->height);
00158
00159 float img_width_half = img_width * 0.5f;
00160 float img_height_half = img_height * 0.5f;
00161
00162 Color scene_light_modifier;
00163
00164 bool use_scene_lighting = false;
00165
00166 if(_system_def->scene_lighting != 0.0f)
00167 {
00168 scene_light_modifier = VideoManager->GetSceneLightingColor();
00169
00170 if(scene_light_modifier[0] != 1.0f ||
00171 scene_light_modifier[1] != 1.0f ||
00172 scene_light_modifier[2] != 1.0f ||
00173 scene_light_modifier[3] != 1.0f )
00174 {
00175 use_scene_lighting = true;
00176
00177 if(_system_def->scene_lighting != 1.0f)
00178 scene_light_modifier = Color::white * (1.0f - _system_def->scene_lighting) + scene_light_modifier * (_system_def->scene_lighting);
00179 }
00180 }
00181
00182
00183
00184
00185 if(_system_def->rotation_used)
00186 {
00187 int32 v = 0;
00188
00189 for(int32 j = 0; j < _num_particles; ++j)
00190 {
00191 float scaled_width_half = img_width_half * _particles[j].size_x;
00192 float scaled_height_half = img_height_half * _particles[j].size_y;
00193
00194 float rotation_angle = _particles[j].rotation_angle;
00195
00196 if(_system_def->rotate_to_velocity)
00197 {
00198
00199 rotation_angle += UTILS_HALF_PI + atan2f(_particles[j].combined_velocity_y, _particles[j].combined_velocity_x);
00200
00201
00202 if(_system_def->speed_scale_used)
00203 {
00204
00205 float speed = sqrtf(_particles[j].combined_velocity_x * _particles[j].combined_velocity_x + _particles[j].combined_velocity_y * _particles[j].combined_velocity_y);
00206 float scale_factor = _system_def->speed_scale * speed;
00207
00208 if(scale_factor < _system_def->min_speed_scale)
00209 scale_factor = _system_def->min_speed_scale;
00210 if(scale_factor > _system_def->max_speed_scale)
00211 scale_factor = _system_def->max_speed_scale;
00212
00213 scaled_height_half *= scale_factor;
00214 }
00215 }
00216
00217
00218 _particle_vertices[v]._x = -scaled_width_half;
00219 _particle_vertices[v]._y = -scaled_height_half;
00220 RotatePoint(_particle_vertices[v]._x, _particle_vertices[v]._y, rotation_angle);
00221 _particle_vertices[v]._x += _particles[j].x;
00222 _particle_vertices[v]._y += _particles[j].y;
00223 ++v;
00224
00225
00226 _particle_vertices[v]._x = scaled_width_half;
00227 _particle_vertices[v]._y = -scaled_height_half;
00228 RotatePoint(_particle_vertices[v]._x, _particle_vertices[v]._y, rotation_angle);
00229 _particle_vertices[v]._x += _particles[j].x;
00230 _particle_vertices[v]._y += _particles[j].y;
00231 ++v;
00232
00233
00234 _particle_vertices[v]._x = scaled_width_half;
00235 _particle_vertices[v]._y = scaled_height_half;
00236 RotatePoint(_particle_vertices[v]._x, _particle_vertices[v]._y, rotation_angle);
00237 _particle_vertices[v]._x += _particles[j].x;
00238 _particle_vertices[v]._y += _particles[j].y;
00239 ++v;
00240
00241
00242 _particle_vertices[v]._x = -scaled_width_half;
00243 _particle_vertices[v]._y = scaled_height_half;
00244 RotatePoint(_particle_vertices[v]._x, _particle_vertices[v]._y, rotation_angle);
00245 _particle_vertices[v]._x += _particles[j].x;
00246 _particle_vertices[v]._y += _particles[j].y;
00247 ++v;
00248
00249
00250 }
00251 }
00252 else
00253 {
00254 int32 v = 0;
00255
00256 for(int32 j = 0; j < _num_particles; ++j)
00257 {
00258 float scaled_width_half = img_width_half * _particles[j].size_x;
00259 float scaled_height_half = img_height_half * _particles[j].size_y;
00260
00261
00262 _particle_vertices[v]._x = _particles[j].x - scaled_width_half;
00263 _particle_vertices[v]._y = _particles[j].y - scaled_height_half;
00264 ++v;
00265
00266
00267 _particle_vertices[v]._x = _particles[j].x + scaled_width_half;
00268 _particle_vertices[v]._y = _particles[j].y - scaled_height_half;
00269 ++v;
00270
00271
00272 _particle_vertices[v]._x = _particles[j].x + scaled_width_half;
00273 _particle_vertices[v]._y = _particles[j].y + scaled_height_half;
00274 ++v;
00275
00276
00277 _particle_vertices[v]._x = _particles[j].x - scaled_width_half;
00278 _particle_vertices[v]._y = _particles[j].y + scaled_height_half;
00279 ++v;
00280 }
00281 }
00282
00283
00284
00285 int32 c = 0;
00286 for(int32 j = 0; j < _num_particles; ++j)
00287 {
00288 Color color = _particles[j].color;
00289
00290 if(_system_def->smooth_animation)
00291 color = color * (1.0f - frame_progress);
00292
00293 if(use_scene_lighting)
00294 color = color * scene_light_modifier;
00295
00296 _particle_colors[c] = color;
00297 ++c;
00298 _particle_colors[c] = color;
00299 ++c;
00300 _particle_colors[c] = color;
00301 ++c;
00302 _particle_colors[c] = color;
00303 ++c;
00304 }
00305
00306
00307
00308 int32 t = 0;
00309 for(int32 j = 0; j < _num_particles; ++j)
00310 {
00311
00312 _particle_texcoords[t]._t0 = u1;
00313 _particle_texcoords[t]._t1 = v1;
00314 ++t;
00315
00316
00317 _particle_texcoords[t]._t0 = u2;
00318 _particle_texcoords[t]._t1 = v1;
00319 ++t;
00320
00321
00322 _particle_texcoords[t]._t0 = u2;
00323 _particle_texcoords[t]._t1 = v2;
00324 ++t;
00325
00326
00327 _particle_texcoords[t]._t0 = u1;
00328 _particle_texcoords[t]._t1 = v2;
00329 ++t;
00330 }
00331
00332 glEnableClientState(GL_VERTEX_ARRAY);
00333 glEnableClientState(GL_COLOR_ARRAY);
00334 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00335 glVertexPointer (2, GL_FLOAT, 0, &_particle_vertices[0]);
00336 glColorPointer (4, GL_FLOAT, 0, &_particle_colors[0]);
00337 glTexCoordPointer (2, GL_FLOAT, 0, &_particle_texcoords[0]);
00338
00339 glDrawArrays(GL_QUADS, 0, _num_particles * 4);
00340
00341 glDisableClientState(GL_VERTEX_ARRAY);
00342
00343 if(_system_def->smooth_animation)
00344 {
00345 glEnableClientState(GL_VERTEX_ARRAY);
00346
00347 int findex = _animation.GetCurrentFrameIndex();
00348 findex = (findex + 1) % _animation.GetNumFrames();
00349
00350 StillImage *id2 = _animation.GetFrame(findex);
00351 Image *img2 = id2->_elements[0].image;
00352 VideoManager->_BindTexture(img2->texture_sheet->tex_ID);
00353
00354
00355 u1 = img2->u1;
00356 u2 = img2->u2;
00357 v1 = img2->v1;
00358 v2 = img2->v2;
00359
00360
00361 t = 0;
00362 for(int32 j = 0; j < _num_particles; ++j)
00363 {
00364
00365 _particle_texcoords[t]._t0 = u1;
00366 _particle_texcoords[t]._t1 = v1;
00367 ++t;
00368
00369
00370 _particle_texcoords[t]._t0 = u2;
00371 _particle_texcoords[t]._t1 = v1;
00372 ++t;
00373
00374
00375 _particle_texcoords[t]._t0 = u2;
00376 _particle_texcoords[t]._t1 = v2;
00377 ++t;
00378
00379
00380 _particle_texcoords[t]._t0 = u1;
00381 _particle_texcoords[t]._t1 = v2;
00382 ++t;
00383 }
00384
00385
00386
00387 c = 0;
00388 for(int32 j = 0; j < _num_particles; ++j)
00389 {
00390 Color color = _particles[j].color;
00391 color = color * frame_progress;
00392 if(use_scene_lighting)
00393 color = color * scene_light_modifier;
00394
00395 _particle_colors[c] = color;
00396 ++c;
00397 _particle_colors[c] = color;
00398 ++c;
00399 _particle_colors[c] = color;
00400 ++c;
00401 _particle_colors[c] = color;
00402 ++c;
00403 }
00404
00405 glVertexPointer (2, GL_FLOAT, 0, &_particle_vertices[0]);
00406 glColorPointer (4, GL_FLOAT, 0, &_particle_colors[0]);
00407 glTexCoordPointer (2, GL_FLOAT, 0, &_particle_texcoords[0]);
00408
00409 glDrawArrays(GL_QUADS, 0, _num_particles * 4);
00410
00411 glDisableClientState(GL_VERTEX_ARRAY);
00412 glDisableClientState(GL_COLOR_ARRAY);
00413 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00414 }
00415
00416 return true;
00417 }
00418
00419
00420
00421
00422
00423
00424 bool ParticleSystem::IsAlive() const
00425 {
00426 return _alive && _system_def->enabled;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435 bool ParticleSystem::IsStopped() const
00436 {
00437 return _stopped;
00438 }
00439
00440
00441
00442
00443
00444
00445 bool ParticleSystem::Update(float frame_time, const EffectParameters ¶ms)
00446 {
00447 if(!_system_def->enabled)
00448 return true;
00449
00450 _age += frame_time;
00451
00452 if(_age < _system_def->emitter._start_time)
00453 {
00454 _last_update_time = _age;
00455 return true;
00456 }
00457
00458 _animation.Update();
00459
00460
00461 _UpdateParticles(frame_time, params);
00462
00463
00464 int32 num_particles_to_emit = 0;
00465 if(!_stopped)
00466 {
00467 if(_system_def->emitter._emitter_mode == EMITTER_MODE_ALWAYS)
00468 {
00469 num_particles_to_emit = _system_def->max_particles - _num_particles;
00470 }
00471 else if(_system_def->emitter._emitter_mode != EMITTER_MODE_BURST)
00472 {
00473 float time_low = _last_update_time * _system_def->emitter._emission_rate;
00474 float time_high = _age * _system_def->emitter._emission_rate;
00475
00476 time_low = floorf(time_low);
00477 time_high = ceilf(time_high);
00478
00479 num_particles_to_emit = static_cast<int32>(time_high - time_low) - 1;
00480
00481 if(num_particles_to_emit + _num_particles > _max_particles)
00482 num_particles_to_emit = _max_particles - _num_particles;
00483 }
00484 else
00485 {
00486 num_particles_to_emit = _system_def->max_particles;
00487 }
00488 }
00489
00490
00491
00492 _KillParticles(num_particles_to_emit, params);
00493
00494
00495 _EmitParticles(num_particles_to_emit, params);
00496
00497
00498 if(_system_def->emitter._emitter_mode == EMITTER_MODE_BURST)
00499 Stop();
00500
00501
00502
00503 if(_system_def->emitter._emitter_mode == EMITTER_MODE_ONE_SHOT)
00504 {
00505 if(_age > _system_def->system_lifetime)
00506 _stopped = true;
00507 }
00508
00509
00510 if(_num_particles == 0 && _stopped)
00511 {
00512 _alive = false;
00513 }
00514
00515 _last_update_time = _age;
00516 return true;
00517 }
00518
00519
00520
00521
00522
00523
00524 int32 ParticleSystem::GetNumParticles() const
00525 {
00526 return _num_particles;
00527 }
00528
00529
00530
00531
00532
00533
00534 void ParticleSystem::Destroy()
00535 {
00536 _particles.clear();
00537 _particle_vertices.clear();
00538 VideoManager->DeleteImage(_animation);
00539 }
00540
00541
00542
00543
00544
00545
00546 void ParticleSystem::Stop()
00547 {
00548 _stopped = true;
00549 }
00550
00551
00552
00553
00554
00555
00556 void ParticleSystem::_UpdateParticles(float t, const EffectParameters ¶ms)
00557 {
00558 for(int j = 0; j < _num_particles; ++j)
00559 {
00560
00561
00562 float scaled_time = _particles[j].time / _particles[j].lifetime;
00563
00564
00565 if(_particles[j].next_keyframe)
00566 {
00567 ParticleKeyframe *old_next = _particles[j].next_keyframe;
00568
00569
00570 if(scaled_time >= _particles[j].next_keyframe->time)
00571 {
00572
00573 size_t num_keyframes = _system_def->keyframes.size();
00574
00575 size_t k;
00576 for(k = 0; k < num_keyframes; ++k)
00577 {
00578 if(_system_def->keyframes[k]->time > scaled_time)
00579 {
00580 _particles[j].current_keyframe = _system_def->keyframes[k - 1];
00581 _particles[j].next_keyframe = _system_def->keyframes[k];
00582 break;
00583 }
00584 }
00585
00586
00587
00588 if(k == num_keyframes)
00589 {
00590 _particles[j].current_keyframe = _system_def->keyframes[k - 1];
00591 _particles[j].next_keyframe = NULL;
00592
00593
00594
00595 _particles[j].color = _particles[j].current_keyframe->color;
00596 _particles[j].rotation_speed = _particles[j].current_keyframe->rotation_speed;
00597 _particles[j].size_x = _particles[j].current_keyframe->size_x;
00598 _particles[j].size_y = _particles[j].current_keyframe->size_y;
00599 }
00600
00601
00602
00603 if(_particles[j].current_keyframe == old_next)
00604 {
00605 _particles[j].current_color_variation = _particles[j].next_color_variation;
00606 _particles[j].current_rotation_speed_variation = _particles[j].current_rotation_speed_variation;
00607 _particles[j].current_size_variation_x = _particles[j].next_size_variation_x;
00608 _particles[j].current_size_variation_y = _particles[j].next_size_variation_y;
00609 }
00610 else
00611 {
00612 _particles[j].current_rotation_speed_variation = RandomFloat(-_particles[j].current_keyframe->rotation_speed_variation, _particles[j].current_keyframe->rotation_speed_variation);
00613 for(int32 c = 0; c < 4; ++c)
00614 _particles[j].current_color_variation[c] = RandomFloat(-_particles[j].current_keyframe->color_variation[c], _particles[j].current_keyframe->color_variation[c]);
00615 _particles[j].current_size_variation_x = RandomFloat(-_particles[j].current_keyframe->size_variation_x, _particles[j].current_keyframe->size_variation_x);
00616 _particles[j].current_size_variation_y = RandomFloat(-_particles[j].current_keyframe->size_variation_y, _particles[j].current_keyframe->size_variation_y);
00617 }
00618
00619
00620 if(_particles[j].next_keyframe)
00621 {
00622 _particles[j].next_rotation_speed_variation = RandomFloat(-_particles[j].next_keyframe->rotation_speed_variation, _particles[j].next_keyframe->rotation_speed_variation);
00623 for(int32 c = 0; c < 4; ++c)
00624 _particles[j].next_color_variation[c] = RandomFloat(-_particles[j].next_keyframe->color_variation[c], _particles[j].next_keyframe->color_variation[c]);
00625 _particles[j].next_size_variation_x = RandomFloat(-_particles[j].next_keyframe->size_variation_x, _particles[j].next_keyframe->size_variation_x);
00626 _particles[j].next_size_variation_y = RandomFloat(-_particles[j].next_keyframe->size_variation_y, _particles[j].next_keyframe->size_variation_y);
00627 }
00628 }
00629 }
00630
00631
00632
00633
00634 if(_particles[j].next_keyframe)
00635 {
00636
00637 float a = (scaled_time - _particles[j].current_keyframe->time) / (_particles[j].next_keyframe->time - _particles[j].current_keyframe->time);
00638
00639 _particles[j].rotation_speed = Lerp(a, _particles[j].current_keyframe->rotation_speed + _particles[j].current_rotation_speed_variation, _particles[j].next_keyframe->rotation_speed + _particles[j].next_rotation_speed_variation);
00640 _particles[j].size_x = Lerp(a, _particles[j].current_keyframe->size_x + _particles[j].current_size_variation_x, _particles[j].next_keyframe->size_x + _particles[j].next_size_variation_x);
00641 _particles[j].size_y = Lerp(a, _particles[j].current_keyframe->size_y + _particles[j].current_size_variation_y, _particles[j].next_keyframe->size_y + _particles[j].next_size_variation_y);
00642 _particles[j].color[0] = Lerp(a, _particles[j].current_keyframe->color[0] + _particles[j].current_color_variation[0], _particles[j].next_keyframe->color[0] + _particles[j].next_color_variation[0]);
00643 _particles[j].color[1] = Lerp(a, _particles[j].current_keyframe->color[1] + _particles[j].current_color_variation[1], _particles[j].next_keyframe->color[1] + _particles[j].next_color_variation[1]);
00644 _particles[j].color[2] = Lerp(a, _particles[j].current_keyframe->color[2] + _particles[j].current_color_variation[2], _particles[j].next_keyframe->color[2] + _particles[j].next_color_variation[2]);
00645 _particles[j].color[3] = Lerp(a, _particles[j].current_keyframe->color[3] + _particles[j].current_color_variation[3], _particles[j].next_keyframe->color[3] + _particles[j].next_color_variation[3]);
00646 }
00647
00648
00649 _particles[j].rotation_angle += _particles[j].rotation_speed * _particles[j].rotation_direction * t;
00650
00651 float wind_velocity_x = _particles[j].wind_velocity_x;
00652 float wind_velocity_y = _particles[j].wind_velocity_y;
00653
00654 _particles[j].combined_velocity_x = _particles[j].velocity_x + wind_velocity_x;
00655 _particles[j].combined_velocity_y = _particles[j].velocity_y + wind_velocity_y;
00656
00657 if(_system_def->wave_motion_used && _particles[j].wave_half_amplitude > 0.0f)
00658 {
00659
00660
00661
00662 float wave_speed = _particles[j].wave_half_amplitude * sinf(_particles[j].wave_length_coefficient * _particles[j].time);
00663
00664
00665 float tangent_x = -_particles[j].combined_velocity_y;
00666 float tangent_y = _particles[j].combined_velocity_x;
00667 float speed = sqrtf(tangent_x * tangent_x + tangent_y * tangent_y);
00668 tangent_x /= speed;
00669 tangent_y /= speed;
00670
00671 float wave_velocity_x = tangent_x * wave_speed;
00672 float wave_velocity_y = tangent_y * wave_speed;
00673
00674 _particles[j].combined_velocity_x += wave_velocity_x;
00675 _particles[j].combined_velocity_y += wave_velocity_y;
00676 }
00677
00678 _particles[j].x += (_particles[j].combined_velocity_x) * t;
00679 _particles[j].y += (_particles[j].combined_velocity_y) * t;
00680
00681
00682
00683 _particles[j].velocity_x += _particles[j].acceleration_x * t;
00684 _particles[j].velocity_y += _particles[j].acceleration_y * t;
00685
00686
00687
00688
00689
00690 bool use_radial = (_particles[j].radial_acceleration != 0.0f);
00691 bool use_tangential = (_particles[j].tangential_acceleration != 0.0f);
00692
00693
00694 if(use_radial || use_tangential)
00695 {
00696
00697 float attractor_to_particle_x;
00698 float attractor_to_particle_y;
00699
00700 if(_system_def->user_defined_attractor)
00701 {
00702 attractor_to_particle_x = _particles[j].x - params.attractor_x;
00703 attractor_to_particle_y = _particles[j].y - params.attractor_y;
00704 }
00705 else
00706 {
00707 attractor_to_particle_x = _particles[j].x - _system_def->emitter._center_x;
00708 attractor_to_particle_y = _particles[j].y - _system_def->emitter._center_y;
00709 }
00710
00711 float distance = sqrtf(attractor_to_particle_x * attractor_to_particle_x + attractor_to_particle_y * attractor_to_particle_y);
00712
00713 if(distance != 0.0f)
00714 {
00715 attractor_to_particle_x /= distance;
00716 attractor_to_particle_y /= distance;
00717 }
00718
00719
00720 if(use_radial)
00721 {
00722 if(_system_def->attractor_falloff != 0.0f)
00723 {
00724 float attraction = 1.0f - _system_def->attractor_falloff * distance;
00725 if(attraction > 0.0f)
00726 {
00727 _particles[j].velocity_x += attractor_to_particle_x * _particles[j].radial_acceleration * t * attraction;
00728 _particles[j].velocity_y += attractor_to_particle_y * _particles[j].radial_acceleration * t * attraction;
00729 }
00730 }
00731 else
00732 {
00733 _particles[j].velocity_x += attractor_to_particle_x * _particles[j].radial_acceleration * t;
00734 _particles[j].velocity_y += attractor_to_particle_y * _particles[j].radial_acceleration * t;
00735 }
00736 }
00737
00738
00739 if(use_tangential)
00740 {
00741
00742 float tangent_x = -attractor_to_particle_y;
00743 float tangent_y = attractor_to_particle_x;
00744
00745 _particles[j].velocity_x += tangent_x * _particles[j].tangential_acceleration * t;
00746 _particles[j].velocity_y += tangent_y * _particles[j].tangential_acceleration * t;
00747 }
00748 }
00749
00750
00751
00752
00753 if(_particles[j].damping != 1.0f)
00754 {
00755 _particles[j].velocity_x *= powf(_particles[j].damping, t);
00756 _particles[j].velocity_y *= powf(_particles[j].damping, t);
00757 }
00758
00759 _particles[j].time += t;
00760 }
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771 void ParticleSystem::_KillParticles(int32 &num, const EffectParameters ¶ms)
00772 {
00773
00774 for(int j = 0; j < _num_particles; ++j)
00775 {
00776 if(_particles[j].time > _particles[j].lifetime)
00777 {
00778 if(num > 0)
00779 {
00780
00781
00782 _RespawnParticle(j, params);
00783 --num;
00784 }
00785 else
00786 {
00787
00788
00789
00790 if(j != _num_particles - 1)
00791 _MoveParticle(_num_particles - 1, j);
00792 --_num_particles;
00793 }
00794 }
00795 }
00796 }
00797
00798
00799
00800
00801
00802
00803 void ParticleSystem::_EmitParticles(int32 num, const EffectParameters ¶ms)
00804 {
00805
00806 for(int32 j = 0; j < num; ++j)
00807 {
00808 _RespawnParticle(_num_particles, params);
00809 ++_num_particles;
00810 }
00811 }
00812
00813
00814
00815
00816
00817
00818
00819 void ParticleSystem::_MoveParticle(int32 src, int32 dest)
00820 {
00821 _particles[dest] = _particles[src];
00822 }
00823
00824
00825
00826
00827
00828
00829
00830 void ParticleSystem::_RespawnParticle(int32 i, const EffectParameters ¶ms)
00831 {
00832 const ParticleEmitter &emitter = _system_def->emitter;
00833
00834 switch(emitter._shape)
00835 {
00836 case EMITTER_SHAPE_POINT:
00837 {
00838 _particles[i].x = emitter._x;
00839 _particles[i].y = emitter._y;
00840 break;
00841 }
00842 case EMITTER_SHAPE_LINE:
00843 {
00844 _particles[i].x = RandomFloat(emitter._x, emitter._x2);
00845 _particles[i].y = RandomFloat(emitter._y, emitter._y2);
00846 break;
00847 }
00848 case EMITTER_SHAPE_CIRCLE:
00849 {
00850 float angle = RandomFloat(0.0f, UTILS_2PI);
00851 _particles[i].x = emitter._radius * cosf(angle);
00852 _particles[i].y = emitter._radius * sinf(angle);
00853 break;
00854 }
00855 case EMITTER_SHAPE_FILLED_CIRCLE:
00856 {
00857 float radius_squared = emitter._radius;
00858 radius_squared *= radius_squared;
00859
00860
00861
00862 do
00863 {
00864 float half_radius = emitter._radius * 0.5f;
00865 _particles[i].x = RandomFloat(-half_radius, half_radius);
00866 _particles[i].y = RandomFloat(-half_radius, half_radius);
00867 } while(_particles[i].x * _particles[i].x +
00868 _particles[i].y * _particles[i].y > radius_squared);
00869
00870
00871 break;
00872 }
00873 case EMITTER_SHAPE_FILLED_RECTANGLE:
00874 {
00875 _particles[i].x = RandomFloat(emitter._x, emitter._x2);
00876 _particles[i].y = RandomFloat(emitter._y, emitter._y2);
00877 break;
00878 }
00879 default:
00880 break;
00881 };
00882
00883
00884 _particles[i].x += RandomFloat(-emitter._x_variation, emitter._x_variation);
00885 _particles[i].y += RandomFloat(-emitter._y_variation, emitter._y_variation);
00886
00887 if(params.orientation != 0.0f)
00888 RotatePoint(_particles[i].x, _particles[i].y, params.orientation);
00889
00890 _particles[i].color = _system_def->keyframes[0]->color;
00891
00892 _particles[i].rotation_speed = _system_def->keyframes[0]->rotation_speed;
00893 _particles[i].time = 0.0f;
00894 _particles[i].size_x = _system_def->keyframes[0]->size_x;
00895 _particles[i].size_y = _system_def->keyframes[0]->size_y;
00896
00897 if(_system_def->random_initial_angle)
00898 _particles[i].rotation_angle = RandomFloat(0.0f, UTILS_2PI);
00899 else
00900 _particles[i].rotation_angle = 0.0f;
00901
00902 _particles[i].current_keyframe = _system_def->keyframes[0];
00903
00904 if(_system_def->keyframes.size() > 1)
00905 _particles[i].next_keyframe = _system_def->keyframes[1];
00906 else
00907 _particles[i].next_keyframe = NULL;
00908
00909 float speed = _system_def->emitter._initial_speed;
00910 speed += RandomFloat(-emitter._initial_speed_variation, emitter._initial_speed_variation);
00911
00912
00913 if(_system_def->emitter._spin == EMITTER_SPIN_CLOCKWISE)
00914 {
00915 _particles[i].rotation_direction = 1.0f;
00916 }
00917 else if(_system_def->emitter._spin == EMITTER_SPIN_COUNTERCLOCKWISE)
00918 {
00919 _particles[i].rotation_direction = -1.0f;
00920 }
00921 else
00922 {
00923 _particles[i].rotation_direction = static_cast<float>(2 * (rand()%2)) - 1.0f;
00924 }
00925
00926
00927
00928 float angle = 0.0f;
00929
00930 if(emitter._omnidirectional)
00931 {
00932 angle = RandomFloat(0.0f, UTILS_2PI);
00933 }
00934 else if(emitter._inner_cone == 0.0f && emitter._outer_cone == 0.0f)
00935 {
00936 angle = emitter._orientation + params.orientation;
00937 }
00938
00939 _particles[i].velocity_x = speed * cosf(angle);
00940 _particles[i].velocity_y = speed * sinf(angle);
00941
00942
00943
00944 _particles[i].current_size_variation_x = RandomFloat(-_system_def->keyframes[0]->size_variation_x, _system_def->keyframes[0]->size_variation_x);
00945 _particles[i].current_size_variation_y = RandomFloat(-_system_def->keyframes[0]->size_variation_y, _system_def->keyframes[0]->size_variation_y);
00946
00947 for(int32 j = 0; j < 4; ++j)
00948 _particles[i].current_color_variation[j] = RandomFloat(-_system_def->keyframes[0]->color_variation[j], _system_def->keyframes[0]->color_variation[j]);
00949
00950 _particles[i].current_rotation_speed_variation = RandomFloat(-_system_def->keyframes[0]->rotation_speed_variation, _system_def->keyframes[0]->rotation_speed_variation);
00951
00952 if(_system_def->keyframes.size() > 1)
00953 {
00954
00955 _particles[i].next_size_variation_x = RandomFloat(-_system_def->keyframes[1]->size_variation_x, _system_def->keyframes[1]->size_variation_x);
00956 _particles[i].next_size_variation_y = RandomFloat(-_system_def->keyframes[1]->size_variation_y, _system_def->keyframes[1]->size_variation_y);
00957
00958 for(int32 j = 0; j < 4; ++j)
00959 _particles[i].next_color_variation[j] = RandomFloat(-_system_def->keyframes[1]->color_variation[j], _system_def->keyframes[1]->color_variation[j]);
00960
00961 _particles[i].next_rotation_speed_variation = RandomFloat(-_system_def->keyframes[1]->rotation_speed_variation, _system_def->keyframes[1]->rotation_speed_variation);
00962 }
00963 else
00964 {
00965
00966 for(int32 j = 0; j < 4; ++j)
00967 _particles[i].color[j] += RandomFloat(-_particles[i].current_color_variation[j], _particles[i].current_color_variation[j]);
00968
00969 _particles[i].size_x += RandomFloat(-_particles[i].current_size_variation_x, _particles[i].current_size_variation_x);
00970 _particles[i].size_y += RandomFloat(-_particles[i].current_size_variation_y, _particles[i].current_size_variation_y);
00971
00972 _particles[i].rotation_speed += RandomFloat(-_particles[i].current_rotation_speed_variation, _particles[i].current_rotation_speed_variation);
00973 }
00974
00975 _particles[i].tangential_acceleration = _system_def->tangential_acceleration;
00976 if(_system_def->tangential_acceleration_variation != 0.0f)
00977 _particles[i].tangential_acceleration += RandomFloat(-_system_def->tangential_acceleration_variation, _system_def->tangential_acceleration_variation);
00978
00979 _particles[i].radial_acceleration = _system_def->radial_acceleration;
00980 if(_system_def->radial_acceleration_variation != 0.0f)
00981 _particles[i].radial_acceleration += RandomFloat(-_system_def->radial_acceleration_variation, _system_def->radial_acceleration_variation);
00982
00983 _particles[i].acceleration_x = _system_def->acceleration_x;
00984 if(_system_def->acceleration_variation_x != 0.0f)
00985 _particles[i].acceleration_x += RandomFloat(-_system_def->acceleration_variation_x, _system_def->acceleration_variation_x);
00986
00987 _particles[i].acceleration_y = _system_def->acceleration_y;
00988 if(_system_def->acceleration_variation_y != 0.0f)
00989 _particles[i].acceleration_y += RandomFloat(-_system_def->acceleration_variation_y, _system_def->acceleration_variation_y);
00990
00991 _particles[i].wind_velocity_x = _system_def->wind_velocity_x;
00992 if(_system_def->wind_velocity_variation_x != 0.0f)
00993 _particles[i].wind_velocity_x += RandomFloat(-_system_def->wind_velocity_variation_x, _system_def->wind_velocity_variation_x);
00994
00995 _particles[i].wind_velocity_y = _system_def->wind_velocity_y;
00996 if(_system_def->wind_velocity_variation_y != 0.0f)
00997 _particles[i].wind_velocity_y += RandomFloat(-_system_def->wind_velocity_variation_y, _system_def->wind_velocity_variation_y);
00998
00999 _particles[i].damping = _system_def->damping;
01000 if(_system_def->damping_variation != 0.0f)
01001 _particles[i].damping += RandomFloat(-_system_def->damping_variation, _system_def->damping_variation);
01002
01003 if(_system_def->wave_motion_used)
01004 {
01005 _particles[i].wave_length_coefficient = _system_def->wave_length;
01006 if(_system_def->wave_length_variation != 0.0f)
01007 _particles[i].wave_length_coefficient += RandomFloat(-_system_def->wave_length_variation, _system_def->wave_length_variation);
01008
01009 _particles[i].wave_length_coefficient = UTILS_2PI / _particles[i].wave_length_coefficient;
01010
01011 _particles[i].wave_half_amplitude = _system_def->wave_amplitude;
01012 if(_system_def->wave_amplitude != 0.0f)
01013 _particles[i].wave_half_amplitude += RandomFloat(-_system_def->wave_amplitude_variation, _system_def->wave_amplitude_variation);
01014 _particles[i].wave_half_amplitude *= 0.5f;
01015 }
01016
01017 _particles[i].lifetime = _system_def->particle_lifetime + RandomFloat(-_system_def->particle_lifetime_variation, _system_def->particle_lifetime_variation);
01018 }
01019
01020
01021
01022
01023
01024
01025 float ParticleSystem::GetAge() const
01026 {
01027 return _age;
01028 }
01029
01030
01031
01032 }
01033 }