00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "actions.h"
00011 #include "ParticleState.h"
00012
00013 #include <algorithm>
00014
00015 #include <sstream>
00016 #include <typeinfo>
00017
00018
00019 static inline void NewBasis(const pVec &u, const pVec &v, pVec &s1, pVec &s2)
00020 {
00021 pVec w = Cross(u, v);
00022
00023 float det = 1.0f / (w.z()*u.x()*v.y() - w.z()*u.y()*v.x() - u.z()*w.x()*v.y() - u.x()*v.z()*w.y() + v.z()*w.x()*u.y() + u.z()*v.x()*w.y());
00024
00025 s1 = pVec((v.y()*w.z() - v.z()*w.y()), (v.z()*w.x() - v.x()*w.z()), (v.x()*w.y() - v.y()*w.x()));
00026 s1 *= det;
00027 s2 = pVec((u.y()*w.z() - u.z()*w.y()), (u.z()*w.x() - u.x()*w.z()), (u.x()*w.y() - u.y()*w.x()));
00028 s2 *= -det;
00029 }
00030
00031 void PAAvoid::Exec(const PDTriangle &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00032 {
00033 float magdt = magnitude * dt;
00034
00035 const pVec &u = dom.u;
00036 const pVec &v = dom.v;
00037
00038
00039 const pVec &un = dom.uNrm;
00040 const pVec &vn = dom.vNrm;
00041
00042
00043 pVec f = v - u;
00044 pVec fn = f;
00045 fn.normalize();
00046
00047
00048 pVec s1, s2;
00049 NewBasis(u, v, s1, s2);
00050
00051 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00052 Particle &m = (*it);
00053
00054
00055
00056 pVec pnext = m.pos + m.vel * dt * look_ahead;
00057
00058
00059
00060 float distold = m.pos * dom.nrm + dom.D;
00061 float distnew = pnext * dom.nrm + dom.D;
00062
00063 if(pSameSign(distold, distnew))
00064 continue;
00065
00066 float nv = dom.nrm * m.vel;
00067 float t = -distold / nv;
00068
00069 pVec phit = m.pos + m.vel * t;
00070 pVec offset = phit - dom.p;
00071
00072
00073
00074 float upos = offset * s1;
00075 float vpos = offset * s2;
00076
00077
00078 if(upos < 0 || vpos < 0 || (upos + vpos) > 1)
00079 continue;
00080
00081
00082
00083 pVec uofs = (un * (un * offset)) - offset;
00084 float udistSqr = uofs.length2();
00085 pVec vofs = (vn * (vn * offset)) - offset;
00086 float vdistSqr = vofs.length2();
00087
00088 pVec foffset = offset - u;
00089 pVec fofs = (fn * (fn * foffset)) - foffset;
00090 float fdistSqr = fofs.length2();
00091
00092
00093 pVec S;
00094 if(udistSqr <= vdistSqr && udistSqr <= fdistSqr) S = uofs;
00095 else if(vdistSqr <= fdistSqr) S = vofs;
00096 else S = fofs;
00097
00098
00099 S.normalize();
00100
00101 float vm = m.vel.length();
00102 pVec Vn = m.vel / vm;
00103
00104 pVec dir = (S * (magdt / (fsqr(t)+epsilon))) + Vn;
00105 m.vel = dir * (vm / dir.length());
00106 }
00107 }
00108
00109 void PAAvoid::Exec(const PDRectangle &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00110 {
00111 float magdt = magnitude * dt;
00112
00113 const pVec &u = dom.u;
00114 const pVec &v = dom.v;
00115
00116
00117 const pVec &un = dom.uNrm;
00118 const pVec &vn = dom.vNrm;
00119
00120
00121 pVec s1, s2;
00122 NewBasis(u, v, s1, s2);
00123
00124 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00125 Particle &m = (*it);
00126
00127
00128
00129 pVec pnext = m.pos + m.vel * dt * look_ahead;
00130
00131
00132
00133 float distold = m.pos * dom.nrm + dom.D;
00134 float distnew = pnext * dom.nrm + dom.D;
00135
00136 if(pSameSign(distold, distnew))
00137 continue;
00138
00139 float nv = dom.nrm * m.vel;
00140 float t = -distold / nv;
00141
00142 pVec phit = m.pos + m.vel * t;
00143 pVec offset = phit - dom.p;
00144
00145
00146
00147 float upos = offset * s1;
00148 float vpos = offset * s2;
00149
00150
00151 if(upos < 0 || vpos < 0 || upos > 1 || vpos > 1)
00152 continue;
00153
00154
00155
00156 pVec uofs = (un * (un * offset)) - offset;
00157 float udistSqr = uofs.length2();
00158 pVec vofs = (vn * (vn * offset)) - offset;
00159 float vdistSqr = vofs.length2();
00160
00161 pVec foffset = (u + v) - offset;
00162 pVec fofs = (un * (un * foffset)) - foffset;
00163 float fdistSqr = fofs.length2();
00164 pVec gofs = (un * (un * foffset)) - foffset;
00165 float gdistSqr = gofs.length2();
00166
00167 pVec S;
00168 if(udistSqr <= vdistSqr && udistSqr <= fdistSqr
00169 && udistSqr <= gdistSqr) S = uofs;
00170 else if(vdistSqr <= fdistSqr && vdistSqr <= gdistSqr) S = vofs;
00171 else if(fdistSqr <= gdistSqr) S = fofs;
00172 else S = gofs;
00173
00174
00175 S.normalize();
00176
00177 float vm = m.vel.length();
00178 pVec Vn = m.vel / vm;
00179
00180 pVec dir = (S * (magdt / (fsqr(t)+epsilon))) + Vn;
00181 m.vel = dir * (vm / dir.length());
00182 }
00183 }
00184
00185 void PAAvoid::Exec(const PDPlane &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00186 {
00187 float magdt = magnitude * dt;
00188
00189 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00190 Particle &m = (*it);
00191
00192
00193
00194 pVec pnext = m.pos + m.vel * dt * look_ahead;
00195
00196
00197
00198 float distold = m.pos * dom.nrm + dom.D;
00199 float distnew = pnext * dom.nrm + dom.D;
00200
00201 if(pSameSign(distold, distnew))
00202 continue;
00203
00204 float nv = dom.nrm * m.vel;
00205 float t = -distold / nv;
00206
00207
00208 const pVec &S = dom.nrm;
00209
00210 float vm = m.vel.length();
00211 pVec Vn = m.vel / vm;
00212
00213 pVec dir = (S * (magdt / (fsqr(t)+epsilon))) + Vn;
00214 m.vel = dir * (vm / dir.length());
00215 }
00216 }
00217
00218
00219 void PAAvoid::Exec(const PDSphere &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00220 {
00221 float magdt = magnitude * dt;
00222
00223 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00224 Particle &m = (*it);
00225
00226
00227
00228 float vm = m.vel.length();
00229 pVec Vn = m.vel / vm;
00230
00231 pVec L = dom.ctr - m.pos;
00232 float v = L * Vn;
00233
00234 float disc = dom.radOutSqr - (L * L) + fsqr(v);
00235 if(disc < 0)
00236 continue;
00237
00238
00239 float t = v - sqrtf(disc);
00240 if(t < 0 || t > (vm * look_ahead))
00241 continue;
00242
00243
00244 pVec C = Cross(Vn, L);
00245 C.normalize();
00246 pVec S = Cross(Vn, C);
00247
00248 pVec dir = (S * (magdt / (fsqr(t)+epsilon))) + Vn;
00249 m.vel = dir * (vm / dir.length());
00250 }
00251 }
00252
00253 void PAAvoid::Exec(const PDDisc &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00254 {
00255 float magdt = magnitude * dt;
00256
00257 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00258 Particle &m = (*it);
00259
00260
00261
00262 pVec pnext = m.pos + m.vel * dt * look_ahead;
00263
00264
00265
00266 float distold = m.pos * dom.nrm + dom.D;
00267 float distnew = pnext * dom.nrm + dom.D;
00268
00269 if(pSameSign(distold, distnew))
00270 continue;
00271
00272 float nv = dom.nrm * m.vel;
00273 float t = -distold / nv;
00274
00275 pVec phit = m.pos + m.vel * t;
00276 pVec offset = phit - dom.p;
00277
00278 float radSqr = offset.length2();
00279
00280
00281 if(radSqr < dom.radInSqr || radSqr > dom.radOutSqr)
00282 continue;
00283
00284
00285 pVec S = offset;
00286
00287 float vm = m.vel.length();
00288 pVec Vn = m.vel / vm;
00289
00290 pVec dir = (S * (magdt / (fsqr(t)+epsilon))) + Vn;
00291 m.vel = dir * (vm / dir.length());
00292 }
00293 }
00294
00295 void PAAvoid::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00296 {
00297 if(typeid(*position) == typeid(PDTriangle)) {
00298 Exec(*dynamic_cast<const PDTriangle *>(position), group, ibegin, iend);
00299 } else if(typeid(*position) == typeid(PDDisc)) {
00300 Exec(*dynamic_cast<const PDDisc *>(position), group, ibegin, iend);
00301 } else if(typeid(*position) == typeid(PDPlane)) {
00302 Exec(*dynamic_cast<const PDPlane *>(position), group, ibegin, iend);
00303 } else if(typeid(*position) == typeid(PDRectangle)) {
00304 Exec(*dynamic_cast<const PDRectangle *>(position), group, ibegin, iend);
00305 } else if(typeid(*position) == typeid(PDSphere)) {
00306 Exec(*dynamic_cast<const PDSphere *>(position), group, ibegin, iend);
00307 } else {
00308 std::string err = std::string("pAvoid not implemented for domain ") + std::string(typeid(*position).name());
00309 _GetPState().SetError(PERR_NOT_IMPLEMENTED, err);
00310 }
00311 }
00312
00313 void PABounce::Exec(const PDTriangle &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00314 {
00315 pVec s1, s2;
00316 NewBasis(dom.u, dom.v, s1, s2);
00317
00318 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00319 Particle &m = (*it);
00320
00321
00322
00323 pVec pnext = m.pos + m.vel * dt;
00324
00325
00326
00327 float distold = m.pos * dom.nrm + dom.D;
00328 float distnew = pnext * dom.nrm + dom.D;
00329
00330 if(pSameSign(distold, distnew))
00331 continue;
00332
00333 float nv = dom.nrm * m.vel;
00334 float t = -distold / nv;
00335
00336 pVec phit = m.pos + m.vel * t;
00337 pVec offset = phit - dom.p;
00338
00339
00340
00341 float upos = offset * s1;
00342 float vpos = offset * s2;
00343
00344
00345 if(upos < 0 || vpos < 0 || (upos + vpos) > 1)
00346 continue;
00347
00348
00349
00350 pVec vn = dom.nrm * nv;
00351 pVec vt = m.vel - vn;
00352
00353
00354
00355 if(vt.length2() <= cutoffSqr)
00356 m.vel = vt - vn * resilience;
00357 else
00358 m.vel = vt * oneMinusFriction - vn * resilience;
00359 }
00360 }
00361
00362 void PABounce::Exec(const PDRectangle &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00363 {
00364 pVec s1, s2;
00365 NewBasis(dom.u, dom.v, s1, s2);
00366
00367 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00368 Particle &m = (*it);
00369
00370
00371
00372 pVec pnext = m.pos + m.vel * dt;
00373
00374
00375
00376 float distold = m.pos * dom.nrm + dom.D;
00377 float distnew = pnext * dom.nrm + dom.D;
00378
00379 if(pSameSign(distold, distnew))
00380 continue;
00381
00382 float nv = dom.nrm * m.vel;
00383 float t = -distold / nv;
00384
00385 pVec phit = m.pos + m.vel * t;
00386 pVec offset = phit - dom.p;
00387
00388
00389
00390 float upos = offset * s1;
00391 float vpos = offset * s2;
00392
00393
00394 if(upos < 0 || upos > 1 || vpos < 0 || vpos > 1)
00395 continue;
00396
00397
00398
00399 pVec vn = dom.nrm * nv;
00400 pVec vt = m.vel - vn;
00401
00402
00403
00404 if(vt.length2() <= cutoffSqr)
00405 m.vel = vt - vn * resilience;
00406 else
00407 m.vel = vt * oneMinusFriction - vn * resilience;
00408 }
00409 }
00410
00411 void PABounce::Exec(const PDPlane &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00412 {
00413 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00414 Particle &m = (*it);
00415
00416
00417
00418 pVec pnext = m.pos + m.vel * dt;
00419
00420
00421
00422 float distold = m.pos * dom.nrm + dom.D;
00423 float distnew = pnext * dom.nrm + dom.D;
00424
00425 if(pSameSign(distold, distnew))
00426 continue;
00427
00428 float nv = dom.nrm * m.vel;
00429
00430
00431
00432
00433 pVec vn = dom.nrm * nv;
00434 pVec vt = m.vel - vn;
00435
00436
00437
00438 if(vt.length2() <= cutoffSqr)
00439 m.vel = vt - vn * resilience;
00440 else
00441 m.vel = vt * oneMinusFriction - vn * resilience;
00442 }
00443 }
00444
00445 void PABounce::Exec(const PDSphere &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00446 {
00447 PASSERT(dom.radIn == 0.0f, "Bouncing doesn't work on thick shells. radIn must be 0.");
00448
00449 float dtinv = 1.0f / dt;
00450
00451
00452 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00453 Particle &m = (*it);
00454
00455
00456 pVec pnext = m.pos + m.vel * dt;
00457
00458 if(dom.Within(m.pos)) {
00459
00460 if(dom.Within(pnext))
00461
00462 continue;
00463
00464
00465
00466
00467
00468 pVec n(dom.ctr - m.pos);
00469 n.normalize();
00470
00471
00472 float nmag = m.vel * n;
00473
00474 pVec vn = n * nmag;
00475 pVec vt = m.vel - vn;
00476
00477
00478 if(nmag < 0) vn = -vn;
00479
00480
00481
00482 float tanscale = (vt.length2() <= cutoffSqr) ? 1.0f : oneMinusFriction;
00483 m.vel = vt * tanscale + vn * resilience;
00484
00485
00486 pVec pthree = m.pos + m.vel * dt;
00487 if(dom.Within(pthree)) {
00488
00489 continue;
00490 } else {
00491
00492 pVec toctr = dom.ctr - pthree;
00493 float dist = toctr.length();
00494 pVec pwish = dom.ctr - toctr * (0.999f * dom.radOut / dist);
00495 m.vel = (pwish - m.pos) * dtinv;
00496 }
00497 } else {
00498
00499 if(!dom.Within(pnext))
00500 continue;
00501
00502
00503
00504
00505
00506 pVec n = m.pos - dom.ctr;
00507 n.normalize();
00508
00509
00510 float nmag = m.vel * n;
00511
00512 pVec vn = n * nmag;
00513 pVec vt = m.vel - vn;
00514
00515
00516 if(nmag < 0)
00517 vn = -vn;
00518
00519
00520
00521 float tanscale = (vt.length2() <= cutoffSqr) ? 1.0f : oneMinusFriction;
00522 m.vel = vt * tanscale + vn * resilience;
00523 }
00524 }
00525 }
00526
00527 void PABounce::Exec(const PDDisc &dom, ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00528 {
00529 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00530 Particle &m = (*it);
00531
00532
00533
00534 pVec pnext = m.pos + m.vel * dt;
00535
00536
00537
00538 float distold = m.pos * dom.nrm + dom.D;
00539 float distnew = pnext * dom.nrm + dom.D;
00540
00541 if(pSameSign(distold, distnew))
00542 continue;
00543
00544 float nv = dom.nrm * m.vel;
00545 float t = -distold / nv;
00546
00547 pVec phit = m.pos + m.vel * t;
00548 pVec offset = phit - dom.p;
00549
00550 float radSqr = offset.length2();
00551
00552
00553 if(radSqr < dom.radInSqr || radSqr > dom.radOutSqr)
00554 continue;
00555
00556
00557
00558 pVec vn = dom.nrm * nv;
00559 pVec vt = m.vel - vn;
00560
00561
00562
00563 if(vt.length2() <= cutoffSqr)
00564 m.vel = vt - vn * resilience;
00565 else
00566 m.vel = vt * oneMinusFriction - vn * resilience;
00567 }
00568 }
00569
00570 void PABounce::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00571 {
00572 if(typeid(*position) == typeid(PDTriangle)) {
00573 Exec(*dynamic_cast<const PDTriangle *>(position), group, ibegin, iend);
00574 } else if(typeid(*position) == typeid(PDDisc)) {
00575 Exec(*dynamic_cast<const PDDisc *>(position), group, ibegin, iend);
00576 } else if(typeid(*position) == typeid(PDPlane)) {
00577 Exec(*dynamic_cast<const PDPlane *>(position), group, ibegin, iend);
00578 } else if(typeid(*position) == typeid(PDRectangle)) {
00579 Exec(*dynamic_cast<const PDRectangle *>(position), group, ibegin, iend);
00580 } else if(typeid(*position) == typeid(PDSphere)) {
00581 Exec(*dynamic_cast<const PDSphere *>(position), group, ibegin, iend);
00582 } else {
00583 std::string err = std::string("pBounce not implemented for domain ") + std::string(typeid(*position).name());
00584 _GetPState().SetError(PERR_NOT_IMPLEMENTED, err);
00585 }
00586 }
00587
00588
00589 void PACallActionList::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00590 {
00591 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00592 pCallActionList(action_list_num);
00593 }
00594
00595
00596 void PACopyVertexB::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00597 {
00598 if(copy_pos && copy_vel) {
00599 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00600 Particle &m = (*it);
00601 m.posB = m.pos;
00602 m.velB = m.vel;
00603 }
00604 } else if(copy_pos) {
00605 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00606 Particle &m = (*it);
00607 m.posB = m.pos;
00608 }
00609 } else if(copy_vel) {
00610 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00611 Particle &m = (*it);
00612 m.velB = m.vel;
00613 m.rvelB = m.rvel;
00614 }
00615 }
00616 }
00617
00618
00619 void PADamping::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00620 {
00621
00622 pVec one(1,1,1);
00623 pVec scale(one - ((one - damping) * dt));
00624
00625 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00626 Particle &m = (*it);
00627 float vSqr = m.vel.length2();
00628
00629 if(vSqr >= vlowSqr && vSqr <= vhighSqr) {
00630 m.vel = CompMult(m.vel, scale);
00631 }
00632 }
00633 }
00634
00635
00636 void PARotDamping::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00637 {
00638
00639 pVec one(1,1,1);
00640 pVec scale(one - ((one - damping) * dt));
00641
00642 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00643 Particle &m = (*it);
00644 float vSqr = m.rvel.length2();
00645
00646 if(vSqr >= vlowSqr && vSqr <= vhighSqr) {
00647 m.rvel = CompMult(m.rvel, scale);
00648 }
00649 }
00650 }
00651
00652
00653 void PAExplosion::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00654 {
00655 float radius = velocity * age;
00656 float magdt = magnitude * dt;
00657 float oneOverSigma = 1.0f / stdev;
00658 float inexp = -0.5f*fsqr(oneOverSigma);
00659 float outexp = P_ONEOVERSQRT2PI * oneOverSigma;
00660
00661 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00662 Particle &m = (*it);
00663
00664
00665 pVec dir(m.pos - center);
00666 float distSqr = dir.length2();
00667 float dist = sqrtf(distSqr);
00668 float DistFromWaveSqr = fsqr(radius - dist);
00669
00670 float Gd = exp(DistFromWaveSqr * inexp) * outexp;
00671 pVec amount = dir * (Gd * magdt / (dist * (distSqr + epsilon)));
00672
00673 m.vel += amount;
00674 }
00675
00676 age += dt;
00677 }
00678
00679
00680 void PAFollow::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00681 {
00682 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00683
00684 float magdt = magnitude * dt;
00685 float max_radiusSqr = fsqr(max_radius);
00686
00687 if (group.size() < 2)
00688 return;
00689
00690 ParticleList::iterator end = iend;
00691 end--;
00692
00693 if(max_radiusSqr < P_MAXFLOAT) {
00694 for (ParticleList::iterator it = ibegin; it != end; it++) {
00695 Particle &m = (*it);
00696 ParticleList::iterator next = it;
00697 next++;
00698
00699
00700 pVec tohim((*next).pos - m.pos);
00701 float tohimlenSqr = tohim.length2();
00702
00703 if(tohimlenSqr < max_radiusSqr) {
00704
00705 m.vel += tohim * (magdt / (sqrtf(tohimlenSqr) * (tohimlenSqr + epsilon)));
00706 }
00707 }
00708 } else {
00709
00710 for (ParticleList::iterator it = ibegin; it != end; it++) {
00711 Particle &m = (*it);
00712 ParticleList::iterator next = it;
00713 next++;
00714
00715
00716 pVec tohim((*next).pos - m.pos);
00717 float tohimlenSqr = tohim.length2();
00718
00719
00720 m.vel += tohim * (magdt / (sqrtf(tohimlenSqr) * (tohimlenSqr + epsilon)));
00721 }
00722 }
00723 }
00724
00725
00726 void PAGravitate::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00727 {
00728 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00729
00730 float magdt = magnitude * dt;
00731 float max_radiusSqr = max_radius * max_radius;
00732
00733 if(max_radiusSqr < P_MAXFLOAT) {
00734 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00735 Particle &m = (*it);
00736
00737 ParticleList::iterator j = it;
00738 j++;
00739
00740
00741 for(; j != iend; ++j) {
00742 Particle &mj = (*j);
00743
00744 pVec tohim(mj.pos - m.pos);
00745 float tohimlenSqr = tohim.length2();
00746
00747 if(tohimlenSqr < max_radiusSqr) {
00748
00749 pVec acc(tohim * (magdt / (sqrtf(tohimlenSqr) * (tohimlenSqr + epsilon))));
00750
00751 m.vel += acc;
00752 mj.vel -= acc;
00753 }
00754 }
00755 }
00756 } else {
00757
00758 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00759 Particle &m = (*it);
00760
00761
00762 ParticleList::iterator j = it;
00763 ++j;
00764
00765 for(; j != iend; ++j) {
00766 Particle &mj = (*j);
00767
00768 pVec tohim(mj.pos - m.pos);
00769 float tohimlenSqr = tohim.length2();
00770
00771
00772 pVec acc(tohim * (magdt / (sqrtf(tohimlenSqr) * (tohimlenSqr + epsilon))));
00773
00774 m.vel += acc;
00775 mj.vel -= acc;
00776 }
00777 }
00778 }
00779 }
00780
00781
00782 void PAGravity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00783 {
00784 pVec ddir(direction * dt);
00785
00786 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00787 Particle &m = (*it);
00788
00789 m.vel += ddir;
00790 }
00791 }
00792
00793
00794 void PAJet::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00795 {
00796 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00797 Particle &m = (*it);
00798
00799 if(dom->Within(m.pos)) {
00800 pVec accel = acc->Generate();
00801
00802
00803 m.vel += accel * dt;
00804 }
00805 }
00806 }
00807
00808
00809 void PAKillOld::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00810 {
00811 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00812
00813
00814 for (ParticleList::iterator it = ibegin; it != group.end(); ) {
00815 Particle &m = (*it);
00816
00817 if(!((m.age < age_limit) ^ kill_less_than))
00818 group.Remove(it);
00819 else
00820 it++;
00821 }
00822 }
00823
00824
00825 void PAMatchVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00826 {
00827 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00828
00829 float magdt = magnitude * dt;
00830 float max_radiusSqr = max_radius * max_radius;
00831
00832 if(max_radiusSqr < P_MAXFLOAT) {
00833 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00834 Particle &m = (*it);
00835
00836
00837 ParticleList::iterator j = it;
00838 j++;
00839
00840
00841 for(; j != iend; ++j) {
00842 Particle &mj = (*j);
00843
00844 pVec tohim(mj.pos - m.pos);
00845 float tohimlenSqr = tohim.length2();
00846
00847 if(tohimlenSqr < max_radiusSqr) {
00848
00849 pVec acc(mj.vel * (magdt / (tohimlenSqr + epsilon)));
00850
00851 m.vel += acc;
00852 mj.vel -= acc;
00853 }
00854 }
00855 }
00856 } else {
00857
00858 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00859 Particle &m = (*it);
00860
00861
00862 ParticleList::iterator j = it;
00863 j++;
00864
00865
00866 for(; j != iend; ++j) {
00867 Particle &mj = (*j);
00868
00869 pVec tohim(mj.pos - m.pos);
00870 float tohimlenSqr = tohim.length2();
00871
00872
00873 pVec acc(mj.vel * (magdt / (tohimlenSqr + epsilon)));
00874
00875 m.vel += acc;
00876 mj.vel -= acc;
00877 }
00878 }
00879 }
00880 }
00881
00882
00883 void PAMatchRotVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00884 {
00885 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
00886
00887 float magdt = magnitude * dt;
00888 float max_radiusSqr = max_radius * max_radius;
00889
00890 if(max_radiusSqr < P_MAXFLOAT) {
00891 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00892 Particle &m = (*it);
00893
00894
00895 ParticleList::iterator j = it;
00896 j++;
00897
00898
00899 for(; j != iend; ++j) {
00900 Particle &mj = (*j);
00901
00902 pVec tohim(mj.pos - m.pos);
00903 float tohimlenSqr = tohim.length2();
00904
00905 if(tohimlenSqr < max_radiusSqr) {
00906
00907 pVec acc(mj.rvel * (magdt / (tohimlenSqr + epsilon)));
00908
00909 m.rvel += acc;
00910 mj.rvel -= acc;
00911 }
00912 }
00913 }
00914 } else {
00915
00916 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00917 Particle &m = (*it);
00918
00919
00920 ParticleList::iterator j = it;
00921 j++;
00922
00923
00924 for(; j != iend; ++j) {
00925 Particle &mj = (*j);
00926
00927 pVec tohim(mj.pos - m.pos);
00928 float tohimlenSqr = tohim.length2();
00929
00930
00931 pVec acc(mj.rvel * (magdt / (tohimlenSqr + epsilon)));
00932
00933 m.rvel += acc;
00934 mj.rvel -= acc;
00935 }
00936 }
00937 }
00938 }
00939
00940 void PAMove::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00941 {
00942
00943 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00944 Particle &m = (*it);
00945
00946 m.age += dt;
00947 m.pos += m.vel * dt;
00948 m.up += m.rvel * dt;
00949 }
00950 }
00951
00952
00953 void PAOrbitLine::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
00954 {
00955 float magdt = magnitude * dt;
00956 float max_radiusSqr = fsqr(max_radius);
00957
00958 if(max_radiusSqr < P_MAXFLOAT) {
00959 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00960 Particle &m = (*it);
00961
00962
00963 pVec f = m.pos - p;
00964
00965
00966 pVec w = axis * (f * axis);
00967
00968
00969 pVec into = w - f;
00970
00971
00972
00973 float rSqr = into.length2();
00974
00975 if(rSqr < max_radiusSqr)
00976
00977 m.vel += into * (magdt / (sqrtf(rSqr) * (rSqr + epsilon)));
00978 }
00979 } else {
00980
00981 for (ParticleList::iterator it = ibegin; it != iend; it++) {
00982 Particle &m = (*it);
00983
00984
00985 pVec f = m.pos - p;
00986
00987
00988 pVec w = axis * (f * axis);
00989
00990
00991 pVec into = w - f;
00992
00993
00994
00995 float rSqr = into.length2();
00996
00997
00998 m.vel += into * (magdt / (sqrtf(rSqr) * (rSqr + epsilon)));
00999 }
01000 }
01001 }
01002
01003
01004 void PAOrbitPoint::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01005 {
01006 float magdt = magnitude * dt;
01007 float max_radiusSqr = max_radius * max_radius;
01008
01009 if(max_radiusSqr < P_MAXFLOAT) {
01010 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01011 Particle &m = (*it);
01012
01013
01014 pVec dir(center - m.pos);
01015
01016
01017
01018 float rSqr = dir.length2();
01019
01020
01021 if(rSqr < max_radiusSqr)
01022 m.vel += dir * (magdt / (sqrtf(rSqr) * (rSqr + epsilon)));
01023 }
01024 } else {
01025
01026 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01027 Particle &m = (*it);
01028
01029
01030 pVec dir(center - m.pos);
01031
01032
01033
01034 float rSqr = dir.length2();
01035
01036
01037 m.vel += dir * (magdt / (sqrtf(rSqr) * (rSqr + epsilon)));
01038 }
01039 }
01040 }
01041
01042
01043 void PARandomAccel::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01044 {
01045 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01046 Particle &m = (*it);
01047
01048 pVec accel = gen_acc->Generate();
01049
01050
01051
01052
01053 m.vel += accel * dt;
01054 }
01055 }
01056
01057
01058 void PARandomDisplace::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01059 {
01060 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01061 Particle &m = (*it);
01062
01063 pVec disp = gen_disp->Generate();
01064
01065
01066
01067
01068 m.pos += disp * dt;
01069 }
01070 }
01071
01072
01073 void PARandomVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01074 {
01075 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01076 Particle &m = (*it);
01077
01078 pVec velocity = gen_vel->Generate();
01079
01080
01081
01082 m.vel = velocity;
01083 }
01084 }
01085
01086
01087 void PARandomRotVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01088 {
01089 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01090 Particle &m = (*it);
01091
01092 pVec velocity = gen_vel->Generate();
01093
01094
01095
01096 m.rvel = velocity;
01097 }
01098 }
01099
01100 #if 0
01101
01102
01103
01104 static inline void _pconstrain(float x0, float v0, float x1, float v1,
01105 float t, float *a, float *b, float *c)
01106 {
01107 *c = v0;
01108 *b = 2 * (-t*v1 - 2*t*v0 + 3*x1 - 3*x0) / (t * t);
01109 *a = 3 * (t*v1 + t*v0 - 2*x1 + 2*x0) / (t * t * t);
01110 }
01111
01112
01113
01114
01115
01116
01117 #endif
01118
01119
01120 static inline void Restore(pVec &vel, const pVec &posB, const pVec &pos, const float t,
01121 const float dtSqr, const float ttInv6dt, const float tttInv3dtSqr)
01122 {
01123 pVec b = (vel*-0.6667f*t + posB - pos) * ttInv6dt;
01124 pVec a = (vel*t - posB - posB + pos + pos) * tttInv3dtSqr;
01125 vel += a + b;
01126 }
01127
01128
01129 void PARestore::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01130 {
01131 if(time_left <= 0) {
01132 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01133 Particle &m = (*it);
01134
01135
01136 m.pos = m.posB;
01137 m.vel = pVec(0.0f,0.0f,0.0f);
01138 m.rvel = pVec(0.0f,0.0f,0.0f);
01139 m.up = m.upB;
01140 }
01141 } else {
01142 float t = time_left;
01143 float dtSqr = fsqr(dt);
01144 float ttInv6dt = dt * 6.0f / fsqr(t);
01145 float tttInv3dtSqr = dtSqr * 3.0f / (t * t * t);
01146
01147 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01148 Particle &m = (*it);
01149
01150 if (restore_velocity)
01151 Restore(m.vel, m.posB, m.pos, t, dtSqr, ttInv6dt, tttInv3dtSqr);
01152 if (restore_rvelocity)
01153 Restore(m.rvel, m.upB, m.up, t, dtSqr, ttInv6dt, tttInv3dtSqr);
01154 }
01155 }
01156
01157 time_left -= dt;
01158 }
01159
01160
01161 void PASink::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01162 {
01163 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
01164
01165
01166 for (ParticleList::iterator it = ibegin; it != group.end(); ) {
01167 Particle &m = (*it);
01168
01169
01170 if(!(position->Within(m.pos) ^ kill_inside))
01171 group.Remove(it);
01172 else
01173 it++;
01174 }
01175 }
01176
01177
01178 void PASinkVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01179 {
01180 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
01181
01182
01183 for (ParticleList::iterator it = ibegin; it != group.end(); ) {
01184 Particle &m = (*it);
01185
01186
01187 if(!(velocity->Within(m.vel) ^ kill_inside))
01188 group.Remove(it);
01189 else
01190 it++;
01191 }
01192 }
01193
01194
01195 void PASort::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01196 {
01197 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
01198
01199
01200 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01201 Particle &m = (*it);
01202 pVec ToP = m.pos - Eye;
01203 m.tmp0 = ToP * Look;
01204 }
01205
01206
01207 std::sort<Particle *>(&*ibegin, &*iend);
01208 }
01209
01210
01211 void PASource::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01212 {
01213 PASSERT(ibegin == group.begin() && iend == group.end(), "Can only be done on whole list");
01214
01215 size_t rate = size_t(floor(particle_rate * dt));
01216
01217
01218 if(pRandf() < particle_rate * dt - float(rate))
01219 rate++;
01220
01221
01222 if(group.size() + rate > group.GetMaxParticles())
01223 rate = group.GetMaxParticles() - group.size();
01224
01225 if(vertexB_tracks) {
01226 for(size_t i = 0; i < rate; i++) {
01227 pVec pos, up, vel, rvel, siz, col, al;
01228
01229 pos = position->Generate();
01230 up = upVec->Generate();
01231 vel = velocity->Generate();
01232 rvel = rvelocity->Generate();
01233 siz = size->Generate();
01234 col = color->Generate();
01235 al = alpha->Generate();
01236 float ag = age + pNRandf(age_sigma);
01237
01238 group.Add(pos, pos, up, vel, rvel, siz, col, al.x(), ag);
01239 }
01240 } else {
01241 for(size_t i = 0; i < rate; i++) {
01242 pVec pos, posB, up, vel, rvel, siz, col, al;
01243
01244 pos = position->Generate();
01245 posB = positionB->Generate();
01246 up = upVec->Generate();
01247 vel = velocity->Generate();
01248 rvel = rvelocity->Generate();
01249 siz = size->Generate();
01250 col = color->Generate();
01251 al = alpha->Generate();
01252 float ag = age + pNRandf(age_sigma);
01253
01254 group.Add(pos, posB, up, vel, rvel, siz, col, al.x(), ag);
01255 }
01256 }
01257 }
01258
01259 void PASpeedLimit::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01260 {
01261 float min_sqr = fsqr(min_speed);
01262 float max_sqr = fsqr(max_speed);
01263
01264 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01265 Particle &m = (*it);
01266 float sSqr = m.vel.length2();
01267 if(sSqr<min_sqr && sSqr) {
01268 float s = sqrtf(sSqr);
01269 m.vel *= (min_speed/s);
01270 } else if(sSqr>max_sqr) {
01271 float s = sqrtf(sSqr);
01272 m.vel *= (max_speed/s);
01273 }
01274 }
01275 }
01276
01277
01278 void PATargetColor::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01279 {
01280 float scaleFac = scale * dt;
01281
01282 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01283 Particle &m = (*it);
01284 m.color += (color - m.color) * scaleFac;
01285 m.alpha += (alpha - m.alpha) * scaleFac;
01286 }
01287 }
01288
01289
01290 void PATargetSize::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01291 {
01292 pVec scaleFac = scale * dt;
01293
01294 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01295 Particle &m = (*it);
01296 pVec dif = size - m.size;
01297 m.size += CompMult(dif, scaleFac);
01298 }
01299 }
01300
01301
01302 void PATargetVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01303 {
01304 float scaleFac = scale * dt;
01305
01306 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01307 Particle &m = (*it);
01308 m.vel += (velocity - m.vel) * scaleFac;
01309 }
01310 }
01311
01312
01313 void PATargetRotVelocity::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01314 {
01315 float scaleFac = scale * dt;
01316
01317 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01318 Particle &m = (*it);
01319 m.rvel += (velocity - m.rvel) * scaleFac;
01320 }
01321 }
01322
01323
01324
01325
01326
01327 void PAVortex::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01328 {
01329 float magdt = magnitude * dt;
01330 float max_radiusSqr = fsqr(max_radius);
01331 float axisLength = axis.length();
01332 float axisLengthInv = 1.0f / axisLength;
01333 pVec axisN = axis;
01334 axisN.normalize();
01335
01336
01337 for (ParticleList::iterator it = ibegin; it != iend; it++) {
01338 Particle &m = (*it);
01339
01340
01341 pVec tipToPar = m.pos - tip;
01342
01343
01344 float axisScale = tipToPar * axisN;
01345 pVec parOnAxis = axisN * axisScale;
01346
01347
01348 pVec parToAxis = parOnAxis - tipToPar;
01349
01350
01351 float rSqr = parToAxis.length2();
01352 float alongAxis = axisScale * axisLengthInv;
01353
01354
01355 float alongAxisPow = powf(alongAxis, tightnessExponent);
01356 float silhouetteSqr = fsqr(alongAxisPow * max_radius);
01357
01358 if(rSqr >= max_radiusSqr || axisScale < 0.0f || alongAxis > 1.0f) {
01359
01360 continue;
01361 }
01362 pVec AccelUp = axisN * 0.011f * dt;
01363 m.vel += AccelUp;
01364
01365 if(rSqr >= silhouetteSqr) {
01366
01367 continue;
01368 }
01369
01370
01371 AccelUp = axisN * -0.001f * dt;
01372 m.vel += AccelUp;
01373
01374
01375 float r = sqrtf(rSqr);
01376
01377
01378
01379 pVec AccelIn = parToAxis * ((1.0f - alongAxisPow) * magdt / (m.mass * (r * (rSqr + epsilon))));
01380 m.vel += AccelIn;
01381
01382
01383 pVec RotAccel = Cross(axisN, parToAxis);
01384 float RA = RotAccel.length();
01385 float scale = rotSpeed / RA;
01386 RotAccel *= scale;
01387
01388 pVec dst = RotAccel - parToAxis;
01389 float DA = dst.length();
01390 dst *= (r / DA);
01391 pVec travel = dst + parToAxis;
01392
01393 pVec AccelAround = travel * (dt / m.mass);
01394 m.vel += AccelAround;
01395 }
01396 }
01397
01398
01399
01400
01401
01402 void PAFountain::Execute(ParticleGroup &group, ParticleList::iterator ibegin, ParticleList::iterator iend)
01403 {
01404 #if 0
01405 assert(ibegin == group.begin() && iend == group.end());
01406
01407
01408
01409
01410
01411
01412
01413
01414 PAGravity *PGr = (PAGravity *)(AL+0);
01415 pVec ddir(PGr->direction * dt);
01416
01417 PASinkVelocity *PSV = (PASinkVelocity *)(AL+1);
01418
01419
01420 PABounce *PB = (PABounce *)(AL+2);
01421 float r1Sqr = fsqr(PB->position.radius1);
01422 float r2Sqr = fsqr(PB->position.radius2);
01423
01424
01425 PASink*PS = (PASink*)(AL+3);
01426
01427
01428 for (ParticleList::iterator it = ibegin; it != group.end(); ) {
01429 Particle &m = (*it);
01430
01431
01432
01433 m.vel += ddir;
01434
01435
01436
01437 if(!(PSV->velocity.Within(m.vel) ^ PSV->kill_inside)) {
01438 group.Remove(it);
01439 continue;
01440 }
01441
01442
01443
01444
01445
01446 pVec pnext(m.pos + m.vel * dt);
01447
01448
01449
01450
01451 float distold = m.pos * PB->position.nrm + PB->position.radius1Sqr;
01452 float distnew = pnext * PB->position.nrm + PB->position.radius1Sqr;
01453
01454 if(!pSameSign(distold, distnew)) {
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465 float nv = PB->position.nrm * m.vel;
01466 float t = -distold / nv;
01467
01468
01469 pVec phit(m.pos + m.vel * t);
01470
01471
01472 pVec offset(phit - PB->position.p1);
01473
01474 float rad = offset.length2();
01475
01476 if(!(rad > r1Sqr || rad < r2Sqr)) {
01477
01478
01479
01480 pVec vn(PB->position.nrm * nv);
01481 pVec vt(m.vel - vn);
01482
01483
01484
01485 if(vt.length2() <= PB->cutoffSqr)
01486 m.vel = vt - vn * PB->resilience;
01487 else
01488 m.vel = vt * PB->oneMinusFriction - vn * PB->resilience;
01489 }
01490 }
01491
01492
01493
01494 if(!(PS->position.Within(m.pos) ^ PS->kill_inside)) {
01495 group.Remove(it);
01496 continue;
01497 } else
01498 it++;
01499
01500
01501 m.age += dt;
01502 m.pos += m.vel * dt;
01503 }
01504 #endif
01505 }