00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/ps_zone.h"
00029 #include "3d/vertex_buffer.h"
00030 #include "3d/primitive_block.h"
00031 #include "3d/material.h"
00032 #include "3d/ps_util.h"
00033 #include "3d/dru.h"
00034 #include "3d/particle_system.h"
00035 #include "nel/misc/plane.h"
00036
00037
00038
00039 #include "3d/particle_system_model.h"
00040
00041 #include <math.h>
00042 #include <limits>
00043
00044 namespace NL3D {
00045
00046
00047
00048
00049
00050 CPSZone::CPSZone() : _BounceFactor(1.f), _CollisionBehaviour(bounce)
00051 {
00052 }
00053
00054 void CPSZone::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00055 {
00056 f.serialVersion(1);
00057 CPSTargetLocatedBindable::serial(f);
00058 f.serialEnum(_CollisionBehaviour);
00059 f.serial(_BounceFactor);
00060 if (f.isReading())
00061 {
00062 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00063 {
00064
00065 (*it)->addNonIntegrableForceRef();
00066 }
00067 }
00068 }
00069
00073 void CPSZone::attachTarget(CPSLocated *ptr)
00074 {
00075
00076 CPSTargetLocatedBindable::attachTarget(ptr);
00077 ptr->queryCollisionInfo();
00078 ptr->addNonIntegrableForceRef();
00079 }
00080
00081
00082
00083
00084
00086 void CPSZone::releaseTargetRsc(CPSLocated *target)
00087 {
00088
00089 target->releaseCollisionInfo();
00090 target->releaseNonIntegrableForceRef();
00091 }
00092
00093
00094
00095 void CPSZone::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00096 {
00097
00098 switch(pass)
00099 {
00100 case PSCollision:
00101 performMotion(ellapsedTime);
00102 break;
00103 case PSToolRender:
00104 show(ellapsedTime);
00105 break;
00106 default: break;
00107 }
00108 }
00109
00110
00111
00112 CMatrix CPSZonePlane::buildBasis(uint32 index) const
00113 {
00114 CMatrix m;
00115 m.setPos(_Owner->getPos()[index]);
00116 CPSUtil::buildSchmidtBasis(_Normal[index], m);
00117 return m;
00118 }
00119
00120
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 void CPSZonePlane::show(TAnimationTime)
00141 {
00142 const float planeSize = 2.0f;
00143 setupDriverModelMatrix();
00144
00145 IDriver *driver = getDriver();
00146 uint k = 0;
00147
00148 setupDriverModelMatrix();
00149
00150 CPSLocated *loc;
00151 uint32 index;
00152 CPSLocatedBindable *lb;
00153 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00154
00155
00156
00157
00158
00159 for (TPSAttribVector::const_iterator it = _Owner->getPos().begin(); it != _Owner->getPos().end(); ++it, ++k)
00160 {
00161 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00162 CMatrix mat = buildBasis(k);
00163
00164 CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00165
00166
00167 setupDriverModelMatrix();
00168
00169 CDRU::drawLine(*it + (planeSize + 3) * mat.getI() + planeSize * mat.getJ()
00170 , *it - (planeSize + 3) * mat.getI() + planeSize * mat.getJ()
00171 , col
00172 , *driver);
00173
00174 CDRU::drawLine(*it + (planeSize + 3) * mat.getI() - planeSize * mat.getJ()
00175 , *it - (planeSize + 3) * mat.getI() - planeSize * mat.getJ()
00176 , col
00177 , *driver);
00178
00179 CDRU::drawLine(*it + planeSize * mat.getI() + (planeSize + 3) * mat.getJ()
00180 , *it + planeSize * mat.getI() - (planeSize + 3) * mat.getJ()
00181 , col
00182 , *driver);
00183 CDRU::drawLine(*it - planeSize * mat.getI() + (planeSize + 3) * mat.getJ()
00184 , *it - planeSize * mat.getI() - (planeSize + 3) * mat.getJ()
00185 , col
00186 , *driver);
00187 }
00188
00189
00190 }
00191
00192
00193
00194 void CPSZonePlane::resize(uint32 size)
00195 {
00196 nlassert(size < (1 << 16));
00197 _Normal.resize(size);
00198 }
00199
00200
00201 void CPSZonePlane::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00202 {
00203 nlassert(_Normal.getSize() != _Normal.getMaxSize());
00204 _Normal.insert(CVector(0, 0, 1));
00205 }
00206
00207
00208 void CPSZonePlane::deleteElement(uint32 index)
00209 {
00210 _Normal.remove(index);
00211 }
00212
00213
00214
00215 void CPSZonePlane::performMotion(TAnimationTime ellapsedTime)
00216 {
00217 MINI_TIMER(PSStatsZonePlane)
00218
00219
00220 TPSAttribVector::const_iterator planePosIt, planePosEnd, normalIt, targetPosIt, targetPosEnd;
00221 CVector dest;
00222 CPSCollisionInfo ci;
00223 CVector startEnd;
00224 uint32 k;
00225 const TPSAttribVector *speedAttr;
00226 float posSide, negSide;
00227
00228
00229 float alpha;
00230
00231 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00232 {
00233
00234 speedAttr = &((*it)->getSpeed());
00235
00236
00237 planePosEnd = _Owner->getPos().end();
00238 for (planePosIt = _Owner->getPos().begin(), normalIt = _Normal.begin(); planePosIt != planePosEnd
00239 ; ++planePosIt, ++normalIt)
00240 {
00241
00242
00243
00244 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00245 const float epsilon = 0.5f * PSCollideEpsilon;
00246
00247
00248 NLMISC::CPlane p;
00249 p.make(m.mulVector(*normalIt), m * (*planePosIt));
00250
00251
00252
00253 targetPosEnd = (*it)->getPos().end();
00254 TPSAttribCollisionInfo::const_iterator ciIt = (*it)->getCollisionInfo().begin();
00255 for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k, ++ciIt)
00256 {
00257 const CVector &speed = (*speedAttr)[k];
00258
00259 dest = *targetPosIt + ellapsedTime * speed * ciIt->TimeSliceRatio;
00260
00261
00262 posSide = p * *targetPosIt;
00263 negSide = p * dest;
00264
00265 if (posSide >= - epsilon && negSide <= epsilon)
00266 {
00267 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00268 {
00269 alpha = posSide / (posSide - negSide);
00270 }
00271 else
00272 {
00273 alpha = 0.f;
00274 }
00275 startEnd = alpha * (dest - *targetPosIt);
00276 ci.dist = startEnd.norm();
00277
00278 ci.newPos = *targetPosIt + startEnd + PSCollideEpsilon * p.getNormal();
00279 ci.newSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00280 ci.collisionZone = this;
00281 (*it)->collisionUpdate(ci, k);
00282 }
00283 }
00284 }
00285 }
00286 }
00287
00288 void CPSZonePlane::setMatrix(uint32 index, const CMatrix &m)
00289 {
00290 nlassert(index < _Normal.getSize());
00291 _Normal[index] = m.getK();
00292 _Owner->getPos()[index] = m.getPos();
00293 }
00294
00295 CMatrix CPSZonePlane::getMatrix(uint32 index) const
00296 {
00297 return buildBasis(index);
00298 }
00299
00300
00301 CVector CPSZonePlane::getNormal(uint32 index)
00302 {
00303 return _Normal[index];
00304 }
00305 void CPSZonePlane::setNormal(uint32 index, CVector n)
00306 {
00307 _Normal[index] = n;
00308 }
00309
00310
00311
00312
00313 void CPSZonePlane::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00314 {
00315 f.serialVersion(1);
00316 CPSZone::serial(f);
00317 f.serial(_Normal);
00318 }
00319
00320
00321
00323
00325
00326
00327
00328
00329 void CPSZoneSphere::performMotion(TAnimationTime ellapsedTime)
00330 {
00331 MINI_TIMER(PSStatsZoneSphere)
00332
00333
00334
00335 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00336 TPSAttribVector::const_iterator spherePosIt, spherePosEnd, targetPosIt, targetPosEnd;
00337 CVector dest;
00338 CPSCollisionInfo ci;
00339 uint32 k;
00340 const TPSAttribVector *speedAttr;
00341
00342
00343 float rOut, rIn;
00344
00345
00346 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00347 {
00348
00349 speedAttr = &((*it)->getSpeed());
00350
00351
00352
00353
00354 spherePosEnd = _Owner->getPos().end();
00355 for (spherePosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(); spherePosIt != spherePosEnd
00356 ; ++spherePosIt, ++radiusIt)
00357 {
00358
00359
00360
00361 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00362
00363
00364
00365 CVector center = m * *spherePosIt;
00366
00367
00368
00369
00370 targetPosEnd = (*it)->getPos().end();
00371 TPSAttribCollisionInfo::const_iterator ciIt = (*it)->getCollisionInfo().begin();
00372 for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k, ++ciIt)
00373 {
00374 const CVector &speed = (*speedAttr)[k];
00375 const CVector &pos = *targetPosIt;
00376
00377
00378
00379
00380
00381 rOut = (pos - center) * (pos - center);
00382
00383
00384 if (rOut > radiusIt->R2)
00385 {
00386 dest = pos + ellapsedTime * speed * ciIt->TimeSliceRatio;
00387 rIn = (dest - center) * (dest - center);
00388
00389 const CVector D = dest - pos;
00390
00391
00392
00393 if ( rIn <= radiusIt->R2)
00394 {
00395
00396 const float b = 2.f * (pos * D - D * center), a = D * D
00397 , c = (pos * pos) + (center * center) - 2.f * (pos * center) - radiusIt->R2;
00398 float d = b * b - 4 * a * c;
00399
00400
00401 if (d <= 0.f) continue;
00402
00403
00404 d = sqrtf(d);
00405
00406
00407
00408
00409 const float r1 = .5f * (-b + 2.f * d) * a
00410 , r2 = .5f * (-b - 2.f * d) * a;
00411
00412 const float r = std::min(r1, r2);
00413
00414
00415
00416 const CVector C = pos + r * D;
00417
00418
00419
00420
00421
00422
00423 const float alpha = ((C - pos) * D) * a;
00424
00425 const CVector startEnd = alpha * (dest - pos);
00426
00427 CVector normal = C - center;
00428 normal = normal * (1.f / radiusIt->R);
00429
00430
00431 ci.dist = startEnd.norm();
00432
00433 ci.newPos = pos + startEnd + PSCollideEpsilon * normal;
00434 ci.newSpeed = _BounceFactor * (speed - 2.0f * (speed * normal) * normal);
00435
00436 ci.collisionZone = this;
00437 (*it)->collisionUpdate(ci, k);
00438
00439 }
00440 }
00441 }
00442 }
00443 }
00444 }
00445
00446
00447
00448 void CPSZoneSphere::show(TAnimationTime ellapsedTime)
00449 {
00450
00451 CPSLocated *loc;
00452 uint32 index;
00453 CPSLocatedBindable *lb;
00454 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00455
00456
00457 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00458 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end();
00459 setupDriverModelMatrix();
00460 for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++k)
00461 {
00462 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00463 CPSUtil::displaySphere(*getDriver(), radiusIt->R, *posIt, 5, col);
00464 }
00465 }
00466
00467 void CPSZoneSphere::setMatrix(uint32 index, const CMatrix &m)
00468 {
00469 nlassert(index < _Radius.getSize());
00470
00471
00472 _Owner->getPos()[index] = m.getPos();
00473
00474 }
00475
00476
00477 CMatrix CPSZoneSphere::getMatrix(uint32 index) const
00478 {
00479 nlassert(index < _Radius.getSize());
00480 CMatrix m;
00481 m.identity();
00482 m.translate(_Owner->getPos()[index]);
00483 return m;
00484 }
00485
00486 void CPSZoneSphere::setScale(uint32 k, float scale)
00487 {
00488 _Radius[k].R = scale;
00489 _Radius[k].R2 = scale * scale;
00490 }
00491 CVector CPSZoneSphere::getScale(uint32 k) const
00492 {
00493 return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00494 }
00495
00496
00497 void CPSZoneSphere::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00498 {
00499 f.serialVersion(1);
00500 CPSZone::serial(f);
00501 f.serial(_Radius);
00502 }
00503
00504
00505
00506
00507
00508
00509 void CPSZoneSphere::resize(uint32 size)
00510 {
00511 nlassert(size < (1 << 16));
00512 _Radius.resize(size);
00513 }
00514
00515 void CPSZoneSphere::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00516 {
00517 CRadiusPair rp;
00518 rp.R = rp.R2 = 1.f;
00519 nlassert(_Radius.getSize() != _Radius.getMaxSize());
00520 _Radius.insert(rp);
00521 }
00522
00523 void CPSZoneSphere::deleteElement(uint32 index)
00524 {
00525 _Radius.remove(index);
00526 }
00527
00528
00530
00532
00533 void CPSZoneDisc::performMotion(TAnimationTime ellapsedTime)
00534 {
00535 MINI_TIMER(PSStatsZoneDisc)
00536
00537
00538 TPSAttribVector::const_iterator discPosIt, discPosEnd, normalIt, targetPosIt, targetPosEnd;
00539 TPSAttribRadiusPair::const_iterator radiusIt;
00540 CVector dest;
00541 CPSCollisionInfo ci;
00542 CVector startEnd;
00543 uint32 k;
00544 const TPSAttribVector *speedAttr;
00545 float posSide, negSide;
00546
00547
00548 float hitRadius2;
00549
00550
00551 float alpha;
00552
00553 CVector center;
00554
00555 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00556 {
00557
00558 speedAttr = &((*it)->getSpeed());
00559
00560
00561 discPosEnd = _Owner->getPos().end();
00562 for (discPosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(), normalIt = _Normal.begin(); discPosIt != discPosEnd
00563 ; ++discPosIt, ++normalIt, ++radiusIt)
00564 {
00565
00566
00567
00568 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00569
00570
00571
00572 NLMISC::CPlane p;
00573 center = m * (*discPosIt);
00574 p.make(m.mulVector(*normalIt), center);
00575
00576
00577
00578 const float epsilon = 0.5f * PSCollideEpsilon;
00579
00580 targetPosEnd = (*it)->getPos().end();
00581 TPSAttribCollisionInfo::const_iterator ciIt = (*it)->getCollisionInfo().begin();
00582 for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k, ++ciIt)
00583 {
00584 const CVector &speed = (*speedAttr)[k];
00585
00586 dest = *targetPosIt + ellapsedTime * speed * ciIt->TimeSliceRatio;
00587
00588
00589 posSide = p * *targetPosIt;
00590 negSide = p * dest;
00591
00592 if (posSide >= - epsilon && negSide <= epsilon)
00593 {
00594 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00595 {
00596 alpha = posSide / (posSide - negSide);
00597 }
00598 else
00599 {
00600 alpha = 0.f;
00601 }
00602 startEnd = alpha * (dest - *targetPosIt);
00603 ci.dist = startEnd.norm();
00604
00605 ci.newPos = *targetPosIt + startEnd + PSCollideEpsilon * p.getNormal();
00606
00607
00608
00609
00610 hitRadius2 = (ci.newPos - center) * (ci.newPos - center);
00611
00612 if (hitRadius2 < radiusIt->R2)
00613 {
00614 ci.newSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00615 ci.collisionZone = this;
00616 (*it)->collisionUpdate(ci, k);
00617 }
00618
00619 }
00620 }
00621 }
00622 }
00623 }
00624
00625 void CPSZoneDisc::show(TAnimationTime ellapsedTime)
00626 {
00627 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00628 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end()
00629 , normalIt = _Normal.begin();
00630 setupDriverModelMatrix();
00631 CMatrix mat;
00632
00633
00634
00635 CPSLocated *loc;
00636 uint32 index;
00637 CPSLocatedBindable *lb;
00638 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00639
00640
00641
00642 for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++normalIt, ++k)
00643 {
00644 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00645 CPSUtil::buildSchmidtBasis(*normalIt, mat);
00646 CPSUtil::displayDisc(*getDriver(), radiusIt->R, *posIt, mat, 32, col);
00647
00648 mat.setPos(*posIt);
00649 CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00650 setupDriverModelMatrix();
00651 }
00652 }
00653
00654
00655
00656
00657
00658
00659 void CPSZoneDisc::setMatrix(uint32 index, const CMatrix &m)
00660 {
00661 nlassert(index < _Radius.getSize());
00662
00663 _Owner->getPos()[index] = m.getPos();
00664
00665 _Normal[index] = m.getK();
00666 }
00667
00668 CMatrix CPSZoneDisc::getMatrix(uint32 index) const
00669 {
00670 CMatrix m, b;
00671 m.translate(_Owner->getPos()[index]);
00672 CPSUtil::buildSchmidtBasis(_Normal[index], b);
00673 m = m * b;
00674 return m;
00675 }
00676
00677 CVector CPSZoneDisc::getNormal(uint32 index)
00678 {
00679 return _Normal[index];
00680 }
00681 void CPSZoneDisc::setNormal(uint32 index, CVector n)
00682 {
00683 _Normal[index] = n;
00684 }
00685
00686 void CPSZoneDisc::setScale(uint32 k, float scale)
00687 {
00688 _Radius[k].R = scale;
00689 _Radius[k].R2 = scale * scale;
00690 }
00691
00692 CVector CPSZoneDisc::getScale(uint32 k) const
00693 {
00694 return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00695 }
00696
00697
00698 void CPSZoneDisc::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00699 {
00700 f.serialVersion(1);
00701 CPSZone::serial(f);
00702 f.serial(_Normal);
00703 f.serial(_Radius);
00704 }
00705
00706 void CPSZoneDisc::resize(uint32 size)
00707 {
00708 nlassert(size < (1 << 16));
00709 _Radius.resize(size);
00710 _Normal.resize(size);
00711 }
00712
00713 void CPSZoneDisc::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00714 {
00715 CRadiusPair rp;
00716 rp.R = rp.R2 = 1.f;
00717 nlassert(_Radius.getSize() != _Radius.getMaxSize());
00718 _Radius.insert(rp);
00719 _Normal.insert(CVector::K);
00720 }
00721
00722 void CPSZoneDisc::deleteElement(uint32 index)
00723 {
00724 _Radius.remove(index);
00725 _Normal.remove(index);
00726 }
00727
00728
00730
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 void CPSZoneCylinder::performMotion(TAnimationTime ellapsedTime)
00947 {
00948 MINI_TIMER(PSStatsZoneCylinder)
00949 TPSAttribVector::const_iterator dimIt;
00950 CPSAttrib<CPlaneBasis>::const_iterator basisIt;
00951 TPSAttribVector::const_iterator cylinderPosIt, cylinderPosEnd, targetPosIt, targetPosEnd;
00952 CVector dest;
00953 CPSCollisionInfo ci;
00954 uint32 k;
00955 const TPSAttribVector *speedAttr;
00956
00957
00958
00959 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00960 {
00961
00962 speedAttr = &((*it)->getSpeed());
00963
00964
00965
00966
00967 cylinderPosEnd = _Owner->getPos().end();
00968 for (cylinderPosIt = _Owner->getPos().begin(), basisIt = _Basis.begin(), dimIt = _Dim.begin()
00969 ; cylinderPosIt != cylinderPosEnd
00970 ; ++cylinderPosIt, ++dimIt, ++basisIt)
00971 {
00972
00973
00974
00975 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00976
00977
00978
00979
00980 CVector center = m * *cylinderPosIt;
00981
00982
00983 CVector I = m.mulVector(basisIt->X);
00984 CVector J = m.mulVector(basisIt->Y);
00985 CVector K = m.mulVector(basisIt->X ^ basisIt->Y);
00986
00987
00988
00989 CVector projectedPos, tPos;
00990
00991
00992 CVector destProjectedPos, destTPos;
00993
00994
00995
00996 targetPosEnd = (*it)->getPos().end();
00997 TPSAttribCollisionInfo::const_iterator ciIt = (*it)->getCollisionInfo().begin();
00998 for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k, ++ciIt)
00999 {
01000 const CVector &speed = (*speedAttr)[k];
01001 const CVector &pos = *targetPosIt;
01002
01003
01004
01005
01006
01007
01008 tPos = pos - center;
01009 projectedPos = (1 / dimIt->x) * (I * tPos) * I + (1 / dimIt->y) * (J * tPos) * J;
01010
01011 if (!
01012 (
01013 ((tPos * K) < dimIt->z)
01014 && ((tPos * K) > -dimIt->z)
01015 && (projectedPos * projectedPos < 1.f)
01016 )
01017 )
01018 {
01019 dest = pos + ellapsedTime * speed * ciIt->TimeSliceRatio;
01020 destTPos = dest - center;
01021 destProjectedPos = (1.f / dimIt->x) * (I * destTPos) * I + (1.f / dimIt->y) * (J * destTPos) * J;
01022
01023
01024
01025
01026 if (
01027 (
01028 ((destTPos * K) < dimIt->z)
01029 && ((destTPos * K) > -dimIt->z)
01030 && (destProjectedPos * destProjectedPos < 1.f)
01031 )
01032 )
01033 {
01034
01035
01036
01037 const float epsilon = 10E-3f;
01038
01039 float alphaTop, alphaBottom, alphaCyl;
01040
01041 const float denum = (dest - pos) * K;
01042
01043
01044
01045 if (fabs(denum) < epsilon)
01046 {
01047 alphaTop = (dimIt->z - (tPos * K)) / denum;
01048 if (alphaTop < 0.f) alphaTop = 1.f;
01049 }
01050 else
01051 {
01052 alphaTop = 1.f;
01053 }
01054
01055
01056
01057 if (fabs(denum) < epsilon)
01058 {
01059 alphaBottom = (- dimIt->z - (tPos * K)) / denum;
01060 if (alphaBottom < 0.f) alphaBottom = 1.f;
01061 }
01062 else
01063 {
01064 alphaBottom = 1.f;
01065 }
01066
01067
01068
01069
01070
01071 const float ox = tPos * I, oy = tPos * J, dx = (destTPos - tPos) * I, dy = (destTPos - tPos) * J;
01072
01073
01074 const float a = (dx * dx) / (dimIt->x * dimIt->x)
01075 + (dy * dy) / (dimIt->y * dimIt->y);
01076 const float b = 2.f * ((ox * dx) / (dimIt->x * dimIt->x)
01077 + (oy * dy) / (dimIt->y * dimIt->y));
01078 const float c = (ox * ox) / (dimIt->x * dimIt->x) + (oy * oy) / (dimIt->y * dimIt->y) - 1;
01079
01080
01081 const float delta = b * b - 4.f * a * c;
01082
01083 if (delta < epsilon)
01084 {
01085 alphaCyl = 1.f;
01086 }
01087 else
01088 {
01089 const float deltaRoot = sqrtf(delta);
01090 const float r1 = (- b + 2.f * deltaRoot) / (2.f * a);
01091 const float r2 = (- b - 2.f * deltaRoot) / (2.f * a);
01092
01093 if (r1 < 0.f) alphaCyl = r2;
01094 else if (r2 < 0.f) alphaCyl = r1;
01095 else alphaCyl = r1 < r2 ? r1 : r2;
01096
01097 if (alphaCyl < 0.f) alphaCyl = 1.f;
01098 }
01099
01100
01101
01102
01103
01104
01105 if (alphaTop < alphaBottom && alphaTop < alphaCyl)
01106 {
01107
01108 CVector startEnd = alphaTop * (dest - pos);
01109 ci.newPos = pos + startEnd + PSCollideEpsilon * K;
01110 ci.dist = startEnd.norm();
01111 ci.newSpeed = (-2.f * (speed * K)) * K + speed;
01112 ci.collisionZone = this;
01113
01114 (*it)->collisionUpdate(ci, k);
01115 }
01116 else
01117 if (alphaBottom < alphaCyl)
01118 {
01119
01120 CVector startEnd = alphaBottom * (dest - pos);
01121 ci.newPos = pos + startEnd - PSCollideEpsilon * K;
01122 ci.dist = startEnd.norm();
01123 ci.newSpeed = (-2.f * (speed * K)) * K + speed;
01124 ci.collisionZone = this;
01125
01126
01127 (*it)->collisionUpdate(ci, k);
01128 }
01129 else
01130 {
01131
01132
01133 CVector startEnd = alphaCyl * (dest - pos);
01134
01135
01136
01137
01138
01139 float px = ox + alphaCyl * dx;
01140 float py = oy + alphaCyl * dy;
01141
01142 CVector normal = px / (dimIt->x * dimIt->x) * I + py / (dimIt->y * dimIt->y) * J;
01143 normal.normalize();
01144
01145 ci.newPos = pos + startEnd + PSCollideEpsilon * normal;
01146 ci.dist = startEnd.norm();
01147 ci.newSpeed = (-2.f * (speed * normal)) * normal + speed;
01148 ci.collisionZone = this;
01149
01150 (*it)->collisionUpdate(ci, k);
01151 }
01152
01153 }
01154 }
01155 }
01156 }
01157 }
01158 }
01159
01160 void CPSZoneCylinder::show(TAnimationTime ellapsedTime)
01161 {
01162 TPSAttribVector::const_iterator dimIt = _Dim.begin()
01163 ,posIt = _Owner->getPos().begin()
01164 , endPosIt = _Owner->getPos().end();
01165
01166 CPSAttrib<CPlaneBasis>::const_iterator basisIt = _Basis.begin();
01167
01168 setupDriverModelMatrix();
01169 CMatrix mat;
01170
01171
01172
01173 CPSLocated *loc;
01174 uint32 index;
01175 CPSLocatedBindable *lb;
01176 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01177
01178
01179 for (uint32 k = 0; posIt != endPosIt; ++posIt, ++dimIt, ++basisIt, ++k)
01180 {
01181 mat.setRot(basisIt->X, basisIt->Y, basisIt->X ^ basisIt->Y);
01182 mat.setPos(CVector::Null);
01183
01184 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01185
01186
01187 CPSUtil::displayCylinder(*getDriver(), *posIt, mat, *dimIt, 32, col);
01188
01189 mat.setPos(*posIt);
01190 CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01191 setupDriverModelMatrix();
01192
01193 }
01194 }
01195
01196
01197
01198 void CPSZoneCylinder::setMatrix(uint32 index, const CMatrix &m)
01199 {
01200
01201 _Basis[index].X = m.getI();
01202 _Basis[index].Y = m.getJ();
01203
01204
01205 _Owner->getPos()[index] = m.getPos();
01206
01207
01208 }
01209
01210
01211
01212 CMatrix CPSZoneCylinder::getMatrix(uint32 index) const
01213 {
01214 CMatrix m;
01215 m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^_Basis[index].Y);
01216 m.setPos(_Owner->getPos()[index]);
01217 return m;
01218 }
01219
01220
01221 void CPSZoneCylinder::setScale(uint32 k, float scale)
01222 {
01223 _Dim[k] = CVector(scale, scale, scale);
01224 }
01225
01226 CVector CPSZoneCylinder::getScale(uint32 k) const
01227 {
01228 return _Dim[k];
01229 }
01230
01231 void CPSZoneCylinder::setScale(uint32 index, const CVector &s)
01232 {
01233 _Dim[index] = s;
01234 }
01235
01236
01237 void CPSZoneCylinder::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01238 {
01239 f.serialVersion(1);
01240 CPSZone::serial(f);
01241 f.serial(_Basis);
01242 f.serial(_Dim);
01243 }
01244
01245
01246
01247 void CPSZoneCylinder::resize(uint32 size)
01248 {
01249 nlassert(size < (1 << 16));
01250 _Basis.resize(size);
01251 _Dim.resize(size);
01252 }
01253
01254 void CPSZoneCylinder::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01255 {
01256 _Basis.insert(CPlaneBasis(CVector::K));
01257 _Dim.insert(CVector(1, 1, 1));
01258 }
01259
01260 void CPSZoneCylinder::deleteElement(uint32 index)
01261 {
01262 _Basis.remove(index);
01263 _Dim.remove(index);
01264 }
01265
01266
01268
01270
01271
01272
01273
01274
01275 void CPSZoneRectangle::performMotion(TAnimationTime ellapsedTime)
01276 {
01277 MINI_TIMER(PSStatsZoneRectangle)
01278
01279
01280 TPSAttribVector::const_iterator rectanglePosIt, rectanglePosEnd, targetPosIt, targetPosEnd;
01281 CPSAttrib<CPlaneBasis>::const_iterator basisIt;
01282 TPSAttribFloat::const_iterator widthIt, heightIt;
01283
01284 CVector dest;
01285 CPSCollisionInfo ci;
01286 CVector startEnd;
01287 uint32 k;
01288 const TPSAttribVector *speedAttr;
01289 float posSide, negSide;
01290
01291
01292 float alpha;
01293
01294 CVector center;
01295
01296 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01297 {
01298
01299 basisIt = _Basis.begin();
01300 heightIt = _Height.begin();
01301 widthIt = _Width.begin();
01302
01303 speedAttr = &((*it)->getSpeed());
01304
01305
01306 rectanglePosEnd = _Owner->getPos().end();
01307 for (rectanglePosIt = _Owner->getPos().begin(); rectanglePosIt != rectanglePosEnd
01308 ; ++rectanglePosIt, ++basisIt, ++widthIt, ++heightIt)
01309 {
01310
01311
01312
01313 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
01314
01315
01316
01317 NLMISC::CPlane p;
01318 center = m * (*rectanglePosIt);
01319
01320 const CVector X = m.mulVector(basisIt->X);
01321 const CVector Y = m.mulVector(basisIt->Y);
01322
01323 p.make(X ^ Y, center);
01324
01325
01326
01327 const float epsilon = 0.5f * PSCollideEpsilon;
01328
01329 targetPosEnd = (*it)->getPos().end();
01330 TPSAttribCollisionInfo::const_iterator ciIt = (*it)->getCollisionInfo().begin();
01331 for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k, ++ciIt)
01332 {
01333 const CVector &pos = *targetPosIt;
01334 const CVector &speed = (*speedAttr)[k];
01335
01336 dest = pos + ellapsedTime * speed * ciIt->TimeSliceRatio;
01337
01338
01339 posSide = p * pos;
01340 negSide = p * dest;
01341
01342 if (posSide >= - epsilon && negSide <= epsilon)
01343 {
01344 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
01345 {
01346 alpha = posSide / (posSide - negSide);
01347 }
01348 else
01349 {
01350 alpha = 0.f;
01351 }
01352 startEnd = alpha * (dest - pos);
01353 ci.dist = startEnd.norm();
01354
01355 ci.newPos = pos + startEnd;
01356
01357
01358
01359
01360 if ( fabs( (pos - center) * X ) < *widthIt && fabs( (pos - center) * Y ) < *heightIt)
01361 {
01362 ci.newPos += PSCollideEpsilon * p.getNormal();
01363 ci.newSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
01364 ci.collisionZone = this;
01365 (*it)->collisionUpdate(ci, k);
01366 }
01367
01368 }
01369 }
01370 }
01371 }
01372 }
01373
01374
01375 void CPSZoneRectangle::show(TAnimationTime ellapsedTime)
01376 {
01377 nlassert(_Owner);
01378 const uint size = _Owner->getSize();
01379 if (!size) return;
01380 setupDriverModelMatrix();
01381 CMatrix mat;
01382
01383 CPSLocated *loc;
01384 uint32 index;
01385 CPSLocatedBindable *lb;
01386 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01387
01388 for (uint k = 0; k < size; ++k)
01389 {
01390 const CVector &I = _Basis[k].X;
01391 const CVector &J = _Basis[k].Y;
01392 mat.setRot(I, J , I ^J);
01393 mat.setPos(_Owner->getPos()[k]);
01394 CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01395 setupDriverModelMatrix();
01396
01397 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01398
01399
01400
01401 const CVector &pos = _Owner->getPos()[k];
01402 CPSUtil::display3DQuad(*getDriver(), pos + I * _Width[k] + J * _Height[k]
01403 , pos + I * _Width[k] - J * _Height[k]
01404 , pos - I * _Width[k] - J * _Height[k]
01405 , pos - I * _Width[k] + J * _Height[k], col);
01406 }
01407 }
01408
01409 void CPSZoneRectangle::setMatrix(uint32 index, const CMatrix &m)
01410 {
01411 nlassert(_Owner);
01412
01413 _Owner->getPos()[index] = m.getPos();
01414 _Basis[index].X = m.getI();
01415 _Basis[index].Y = m.getJ();
01416 }
01417
01418
01419 CMatrix CPSZoneRectangle::getMatrix(uint32 index) const
01420 {
01421 nlassert(_Owner);
01422 CMatrix m;
01423 m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^ _Basis[index].Y);
01424 m.setPos(_Owner->getPos()[index]);
01425 return m;
01426 }
01427
01428 void CPSZoneRectangle::setScale(uint32 index, float scale)
01429 {
01430 _Width[index] = scale;
01431 _Height[index] = scale;
01432 }
01433 void CPSZoneRectangle::setScale(uint32 index, const CVector &s)
01434 {
01435 _Width[index] = s.x;
01436 _Height[index] = s.y;
01437 }
01438 CVector CPSZoneRectangle::getScale(uint32 index) const
01439 {
01440 return CVector(_Width[index], _Height[index], 1.f);
01441 }
01442
01443
01444
01445 void CPSZoneRectangle::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01446 {
01447 f.serialVersion(1);
01448 CPSZone::serial(f);
01449 f.serial(_Basis);
01450 f.serial(_Width);
01451 f.serial(_Height);
01452 }
01453
01454
01455 void CPSZoneRectangle::resize(uint32 size)
01456 {
01457 nlassert(size < (1 << 16));
01458 _Basis.resize(size);
01459 _Width.resize(size);
01460 _Height.resize(size);
01461 }
01462
01463 void CPSZoneRectangle::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
01464 {
01465 _Basis.insert(CPlaneBasis(CVector::K));
01466 _Width.insert(1.f);
01467 _Height.insert(1.f);
01468 }
01469
01470 void CPSZoneRectangle::deleteElement(uint32 index)
01471 {
01472 _Basis.remove(index);
01473 _Width.remove(index);
01474 _Height.remove(index);
01475 }
01476
01477
01478
01479 }