00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026 #include "nel/3d/ps_zone.h"
00027 #include "nel/3d/vertex_buffer.h"
00028 #include "nel/3d/index_buffer.h"
00029 #include "nel/3d/material.h"
00030 #include "nel/3d/ps_util.h"
00031 #include "nel/3d/dru.h"
00032 #include "nel/3d/particle_system.h"
00033 #include "nel/misc/plane.h"
00034
00035
00036
00037 #include "nel/3d/particle_system_model.h"
00038
00039 #include <cmath>
00040 #include <limits>
00041
00042 namespace NL3D {
00043
00044
00045
00046
00047
00048 CPSZone::CPSZone() : _BounceFactor(1.f), _CollisionBehaviour(bounce)
00049 {
00050 NL_PS_FUNC(CPSZone_CPSZone)
00051 }
00052
00053 void CPSZone::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00054 {
00055 NL_PS_FUNC(CPSZone_serial)
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 NL_PS_FUNC(CPSZone_attachTarget)
00076 CPSTargetLocatedBindable::attachTarget(ptr);
00077 ptr->queryCollisionInfo();
00078 ptr->addNonIntegrableForceRef();
00079 }
00080
00081
00082
00083
00084
00086 void CPSZone::releaseTargetRsc(CPSLocated *target)
00087 {
00088 NL_PS_FUNC(CPSZone_releaseTargetRsc)
00089
00090 target->releaseCollisionInfo();
00091 target->releaseNonIntegrableForceRef();
00092 }
00093
00094
00095
00096 void CPSZone::step(TPSProcessPass pass)
00097 {
00098 NL_PS_FUNC(CPSZone_step)
00099
00100 switch(pass)
00101 {
00102 case PSToolRender:
00103 show();
00104 break;
00105 default: break;
00106 }
00107 }
00108
00109
00110
00111 CMatrix CPSZonePlane::buildBasis(uint32 index) const
00112 {
00113 NL_PS_FUNC(CPSZonePlane_buildBasis)
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()
00141 {
00142 NL_PS_FUNC(CPSZonePlane_show)
00143 const float planeSize = 2.0f;
00144 setupDriverModelMatrix();
00145 IDriver *driver = getDriver();
00146 uint k = 0;
00147 setupDriverModelMatrix();
00148 CPSLocated *loc;
00149 uint32 index;
00150 CPSLocatedBindable *lb;
00151 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00152 for (TPSAttribVector::const_iterator it = _Owner->getPos().begin(); it != _Owner->getPos().end(); ++it, ++k)
00153 {
00154 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00155 CMatrix mat = buildBasis(k);
00156 CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00157 setupDriverModelMatrix();
00158 CDRU::drawLine(*it + (planeSize + 3) * mat.getI() + planeSize * mat.getJ(),
00159 *it - (planeSize + 3) * mat.getI() + planeSize * mat.getJ(),
00160 col,
00161 *driver);
00162
00163 CDRU::drawLine(*it + (planeSize + 3) * mat.getI() - planeSize * mat.getJ(),
00164 *it - (planeSize + 3) * mat.getI() - planeSize * mat.getJ(),
00165 col,
00166 *driver);
00167
00168 CDRU::drawLine(*it + planeSize * mat.getI() + (planeSize + 3) * mat.getJ(),
00169 *it + planeSize * mat.getI() - (planeSize + 3) * mat.getJ(),
00170 col,
00171 *driver);
00172 CDRU::drawLine(*it - planeSize * mat.getI() + (planeSize + 3) * mat.getJ(),
00173 *it - planeSize * mat.getI() - (planeSize + 3) * mat.getJ(),
00174 col,
00175 *driver);
00176 }
00177 }
00178
00179
00180
00181 void CPSZonePlane::resize(uint32 size)
00182 {
00183 NL_PS_FUNC(CPSZonePlane_resize)
00184 nlassert(size < (1 << 16));
00185 _Normal.resize(size);
00186 }
00187
00188
00189 void CPSZonePlane::newElement(const CPSEmitterInfo &info)
00190 {
00191 NL_PS_FUNC(CPSZonePlane_newElement)
00192 nlassert(_Normal.getSize() != _Normal.getMaxSize());
00193 _Normal.insert(CVector(0, 0, 1));
00194 }
00195
00196
00197 void CPSZonePlane::deleteElement(uint32 index)
00198 {
00199 NL_PS_FUNC(CPSZonePlane_deleteElement)
00200 _Normal.remove(index);
00201 }
00202
00203
00204 void CPSZonePlane::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00205 {
00206 NL_PS_FUNC(CPSZonePlane_computeCollisions)
00207 MINI_TIMER(PSStatsZonePlane)
00208
00209
00210 TPSAttribVector::const_iterator planePosIt, planePosEnd, normalIt;
00211 CPSCollisionInfo ci;
00212
00213 planePosEnd = _Owner->getPos().end();
00214 for (planePosIt = _Owner->getPos().begin(), normalIt = _Normal.begin(); planePosIt != planePosEnd; ++planePosIt, ++normalIt)
00215 {
00216
00217
00218 const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00219 const float epsilon = 0.5f * PSCollideEpsilon;
00220 NLMISC::CPlane p;
00221 p.make(m.mulVector(*normalIt), m * (*planePosIt));
00222
00223 const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00224 const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00225 const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00226 while (itPosBefore != itPosBeforeEnd)
00227 {
00228 float posSide = p * *itPosBefore;
00229 float negSide = p * *itPosAfter;
00230 if (posSide >= - epsilon && negSide <= epsilon)
00231 {
00232 float alpha;
00233 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00234 {
00235 alpha = posSide / (posSide - negSide);
00236 }
00237 else
00238 {
00239 alpha = 0.f;
00240 }
00241 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
00242 ci.Dist = startEnd.norm();
00243
00244 ci.NewPos = *itPosBefore + startEnd + PSCollideEpsilon * p.getNormal();
00245 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00246 ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00247 ci.CollisionZone = this;
00248 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00249 }
00250 ++ itPosBefore;
00251 ++ itPosAfter;
00252 }
00253 }
00254
00255 }
00256
00257 void CPSZonePlane::setMatrix(uint32 index, const CMatrix &m)
00258 {
00259 NL_PS_FUNC(CPSZonePlane_setMatrix)
00260 nlassert(index < _Normal.getSize());
00261 _Normal[index] = m.getK();
00262 _Owner->getPos()[index] = m.getPos();
00263 }
00264
00265 CMatrix CPSZonePlane::getMatrix(uint32 index) const
00266 {
00267 NL_PS_FUNC(CPSZonePlane_getMatrix)
00268 return buildBasis(index);
00269 }
00270
00271
00272 CVector CPSZonePlane::getNormal(uint32 index)
00273 {
00274 NL_PS_FUNC(CPSZonePlane_getNormal)
00275 return _Normal[index];
00276 }
00277 void CPSZonePlane::setNormal(uint32 index, CVector n)
00278 {
00279 NL_PS_FUNC(CPSZonePlane_setNormal)
00280 _Normal[index] = n;
00281 }
00282
00283
00284
00285
00286 void CPSZonePlane::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00287 {
00288 NL_PS_FUNC(CPSZonePlane_serial)
00289 f.serialVersion(1);
00290 CPSZone::serial(f);
00291 f.serial(_Normal);
00292 }
00293
00294
00295
00297
00299
00300 void CPSZoneSphere::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00301 {
00302 NL_PS_FUNC(CPSZoneSphere_computeCollisions)
00303 MINI_TIMER(PSStatsZoneSphere)
00304
00305
00306 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00307 TPSAttribVector::const_iterator spherePosIt, spherePosEnd;
00308 CPSCollisionInfo ci;
00309 float rOut, rIn;
00310
00311 spherePosEnd = _Owner->getPos().end();
00312 for (spherePosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(); spherePosIt != spherePosEnd; ++spherePosIt, ++radiusIt)
00313 {
00314
00315 const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00316 CVector center = m * *spherePosIt;
00317
00318 const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00319 const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00320 const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00321 while (itPosBefore != itPosBeforeEnd)
00322 {
00323
00324
00325 rOut = (*itPosBefore - center) * (*itPosBefore - center);
00326
00327 if (rOut > radiusIt->R2)
00328 {
00329 rIn = (*itPosAfter - center) * (*itPosAfter - center);
00330 const CVector &pos = *itPosBefore;
00331 const CVector &dest = *itPosAfter;
00332 const CVector D = dest - pos;
00333
00334 if ( rIn <= radiusIt->R2)
00335 {
00336
00337 const float b = 2.f * (pos * D - D * center), a = D * D
00338 , c = (pos * pos) + (center * center) - 2.f * (pos * center) - radiusIt->R2;
00339 float d = b * b - 4 * a * c;
00340 if (d > 0.f)
00341 {
00342 d = sqrtf(d);
00343
00344 const float r1 = .5f * (-b + 2.f * d) * a,
00345 r2 = .5f * (-b - 2.f * d) * a;
00346 const float r = std::min(r1, r2);
00347
00348 const CVector C = pos + r * D;
00349 const float alpha = ((C - pos) * D) * a;
00350 const CVector startEnd = alpha * (dest - pos);
00351 CVector normal = C - center;
00352 normal = normal * (1.f / radiusIt->R);
00353 ci.Dist = startEnd.norm();
00354
00355 ci.NewPos = pos + startEnd + PSCollideEpsilon * normal;
00356 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00357 ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * normal) * normal);
00358 ci.CollisionZone = this;
00359 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00360 }
00361 }
00362 }
00363 ++ itPosBefore;
00364 ++ itPosAfter;
00365 }
00366 }
00367
00368 }
00369
00370
00371
00372 void CPSZoneSphere::show()
00373 {
00374 NL_PS_FUNC(CPSZoneSphere_show)
00375
00376 CPSLocated *loc;
00377 uint32 index;
00378 CPSLocatedBindable *lb;
00379 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00380
00381
00382 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00383 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end();
00384 setupDriverModelMatrix();
00385 for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++k)
00386 {
00387 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00388 CPSUtil::displaySphere(*getDriver(), radiusIt->R, *posIt, 5, col);
00389 }
00390 }
00391
00392 void CPSZoneSphere::setMatrix(uint32 index, const CMatrix &m)
00393 {
00394 NL_PS_FUNC(CPSZoneSphere_setMatrix)
00395 nlassert(index < _Radius.getSize());
00396
00397
00398 _Owner->getPos()[index] = m.getPos();
00399
00400 }
00401
00402
00403 CMatrix CPSZoneSphere::getMatrix(uint32 index) const
00404 {
00405 NL_PS_FUNC(CPSZoneSphere_getMatrix)
00406 nlassert(index < _Radius.getSize());
00407 CMatrix m;
00408 m.identity();
00409 m.translate(_Owner->getPos()[index]);
00410 return m;
00411 }
00412
00413 void CPSZoneSphere::setScale(uint32 k, float scale)
00414 {
00415 NL_PS_FUNC(CPSZoneSphere_setScale)
00416 _Radius[k].R = scale;
00417 _Radius[k].R2 = scale * scale;
00418 }
00419 CVector CPSZoneSphere::getScale(uint32 k) const
00420 {
00421 NL_PS_FUNC(CPSZoneSphere_getScale)
00422 return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00423 }
00424
00425
00426 void CPSZoneSphere::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00427 {
00428 NL_PS_FUNC(CPSZoneSphere_serial)
00429 f.serialVersion(1);
00430 CPSZone::serial(f);
00431 f.serial(_Radius);
00432 }
00433
00434 void CPSZoneSphere::resize(uint32 size)
00435 {
00436 NL_PS_FUNC(CPSZoneSphere_resize)
00437 nlassert(size < (1 << 16));
00438 _Radius.resize(size);
00439 }
00440
00441 void CPSZoneSphere::newElement(const CPSEmitterInfo &info)
00442 {
00443 NL_PS_FUNC(CPSZoneSphere_newElement)
00444 CRadiusPair rp;
00445 rp.R = rp.R2 = 1.f;
00446 nlassert(_Radius.getSize() != _Radius.getMaxSize());
00447 _Radius.insert(rp);
00448 }
00449
00450 void CPSZoneSphere::deleteElement(uint32 index)
00451 {
00452 NL_PS_FUNC(CPSZoneSphere_deleteElement)
00453 _Radius.remove(index);
00454 }
00455
00456
00458
00460 void CPSZoneDisc::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00461 {
00462 NL_PS_FUNC(CPSZoneDisc_computeCollisions)
00463 MINI_TIMER(PSStatsZoneDisc)
00464
00465
00466 TPSAttribVector::const_iterator discPosIt, discPosEnd, normalIt;
00467 TPSAttribRadiusPair::const_iterator radiusIt;
00468 CPSCollisionInfo ci;
00469
00470 float hitRadius2;
00471
00472 CVector center;
00473
00474 discPosEnd = _Owner->getPos().end();
00475 for (discPosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(), normalIt = _Normal.begin(); discPosIt != discPosEnd; ++discPosIt, ++normalIt, ++radiusIt)
00476 {
00477
00478 const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00479 NLMISC::CPlane p;
00480 center = m * (*discPosIt);
00481 p.make(m.mulVector(*normalIt), center);
00482
00483
00484 const float epsilon = 0.5f * PSCollideEpsilon;
00485
00486
00487 const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00488 const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00489 const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00490 while (itPosBefore != itPosBeforeEnd)
00491 {
00492 float posSide = p * *itPosBefore;
00493 float negSide = p * *itPosAfter;
00494 if (posSide >= - epsilon && negSide <= epsilon)
00495 {
00496 float alpha;
00497 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00498 {
00499 alpha = posSide / (posSide - negSide);
00500 }
00501 else
00502 {
00503 alpha = 0.f;
00504 }
00505 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
00506 ci.Dist = startEnd.norm();
00507
00508 ci.NewPos = *itPosBefore + startEnd + PSCollideEpsilon * p.getNormal();
00509
00510 hitRadius2 = (ci.NewPos - center) * (ci.NewPos - center);
00511 if (hitRadius2 < radiusIt->R2)
00512 {
00513 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00514 ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00515 ci.CollisionZone = this;
00516 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00517 }
00518
00519 }
00520 ++ itPosBefore;
00521 ++ itPosAfter;
00522 }
00523 }
00524 }
00525
00526 void CPSZoneDisc::show()
00527 {
00528 NL_PS_FUNC(CPSZoneDisc_show)
00529 TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00530 TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end()
00531 , normalIt = _Normal.begin();
00532 setupDriverModelMatrix();
00533 CMatrix mat;
00534
00535
00536
00537 CPSLocated *loc;
00538 uint32 index;
00539 CPSLocatedBindable *lb;
00540 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00541
00542
00543
00544 for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++normalIt, ++k)
00545 {
00546 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00547 CPSUtil::buildSchmidtBasis(*normalIt, mat);
00548 CPSUtil::displayDisc(*getDriver(), radiusIt->R, *posIt, mat, 32, col);
00549
00550 mat.setPos(*posIt);
00551 CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00552 setupDriverModelMatrix();
00553 }
00554 }
00555
00556
00557
00558
00559
00560
00561 void CPSZoneDisc::setMatrix(uint32 index, const CMatrix &m)
00562 {
00563 NL_PS_FUNC(CPSZoneDisc_setMatrix)
00564 nlassert(index < _Radius.getSize());
00565
00566 _Owner->getPos()[index] = m.getPos();
00567
00568 _Normal[index] = m.getK();
00569 }
00570
00571 CMatrix CPSZoneDisc::getMatrix(uint32 index) const
00572 {
00573 NL_PS_FUNC(CPSZoneDisc_getMatrix)
00574 CMatrix m, b;
00575 m.translate(_Owner->getPos()[index]);
00576 CPSUtil::buildSchmidtBasis(_Normal[index], b);
00577 m = m * b;
00578 return m;
00579 }
00580
00581 CVector CPSZoneDisc::getNormal(uint32 index)
00582 {
00583 NL_PS_FUNC(CPSZoneDisc_getNormal)
00584 return _Normal[index];
00585 }
00586 void CPSZoneDisc::setNormal(uint32 index, CVector n)
00587 {
00588 NL_PS_FUNC(CPSZoneDisc_setNormal)
00589 _Normal[index] = n;
00590 }
00591
00592 void CPSZoneDisc::setScale(uint32 k, float scale)
00593 {
00594 NL_PS_FUNC(CPSZoneDisc_setScale)
00595 _Radius[k].R = scale;
00596 _Radius[k].R2 = scale * scale;
00597 }
00598
00599 CVector CPSZoneDisc::getScale(uint32 k) const
00600 {
00601 NL_PS_FUNC(CPSZoneDisc_getScale)
00602 return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00603 }
00604
00605
00606 void CPSZoneDisc::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00607 {
00608 NL_PS_FUNC(CPSZoneDisc_serial)
00609 f.serialVersion(1);
00610 CPSZone::serial(f);
00611 f.serial(_Normal);
00612 f.serial(_Radius);
00613 }
00614
00615 void CPSZoneDisc::resize(uint32 size)
00616 {
00617 NL_PS_FUNC(CPSZoneDisc_resize)
00618 nlassert(size < (1 << 16));
00619 _Radius.resize(size);
00620 _Normal.resize(size);
00621 }
00622
00623 void CPSZoneDisc::newElement(const CPSEmitterInfo &info)
00624 {
00625 NL_PS_FUNC(CPSZoneDisc_newElement)
00626 CRadiusPair rp;
00627 rp.R = rp.R2 = 1.f;
00628 nlassert(_Radius.getSize() != _Radius.getMaxSize());
00629 _Radius.insert(rp);
00630 _Normal.insert(CVector::K);
00631 }
00632
00633 void CPSZoneDisc::deleteElement(uint32 index)
00634 {
00635 NL_PS_FUNC(CPSZoneDisc_deleteElement)
00636 _Radius.remove(index);
00637 _Normal.remove(index);
00638 }
00639
00640
00642
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
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 void CPSZoneCylinder::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00858 {
00859 NL_PS_FUNC(CPSZoneCylinder_computeCollisions)
00860 MINI_TIMER(PSStatsZoneCylinder)
00861 TPSAttribVector::const_iterator dimIt;
00862 CPSAttrib<CPlaneBasis>::const_iterator basisIt;
00863 TPSAttribVector::const_iterator cylinderPosIt, cylinderPosEnd;
00864 CPSCollisionInfo ci;
00865
00866 cylinderPosEnd = _Owner->getPos().end();
00867 for (cylinderPosIt = _Owner->getPos().begin(), basisIt = _Basis.begin(), dimIt = _Dim.begin(); cylinderPosIt != cylinderPosEnd; ++cylinderPosIt, ++dimIt, ++basisIt)
00868 {
00869
00870 const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00871
00872 CVector center = m * *cylinderPosIt;
00873
00874 CVector I = m.mulVector(basisIt->X);
00875 CVector J = m.mulVector(basisIt->Y);
00876 CVector K = m.mulVector(basisIt->X ^ basisIt->Y);
00877
00878 CVector projectedPos, tPos;
00879
00880 CVector destProjectedPos, destTPos;
00881
00882
00883 const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00884 const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00885 const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00886 while (itPosBefore != itPosBeforeEnd)
00887 {
00888 const CVector &pos = *itPosBefore;
00889
00890 tPos = pos - center;
00891 projectedPos = (1 / dimIt->x) * (I * tPos) * I + (1 / dimIt->y) * (J * tPos) * J;
00892 if (!
00893 (
00894 ((tPos * K) < dimIt->z)
00895 && ((tPos * K) > -dimIt->z)
00896 && (projectedPos * projectedPos < 1.f)
00897 )
00898 )
00899 {
00900 const CVector &dest = *itPosAfter;
00901 destTPos = dest - center;
00902 destProjectedPos = (1.f / dimIt->x) * (I * destTPos) * I + (1.f / dimIt->y) * (J * destTPos) * J;
00903
00904 if (
00905 ((destTPos * K) < dimIt->z)
00906 && ((destTPos * K) > -dimIt->z)
00907 && (destProjectedPos * destProjectedPos < 1.f)
00908 )
00909 {
00910
00911
00912 const float epsilon = 10E-3f;
00913 float alphaTop, alphaBottom, alphaCyl;
00914 const float denum = (dest - pos) * K;
00915
00916 if (fabs(denum) < epsilon)
00917 {
00918 alphaTop = (dimIt->z - (tPos * K)) / denum;
00919 if (alphaTop < 0.f) alphaTop = 1.f;
00920 }
00921 else
00922 {
00923 alphaTop = 1.f;
00924 }
00925
00926 if (fabs(denum) < epsilon)
00927 {
00928 alphaBottom = (- dimIt->z - (tPos * K)) / denum;
00929 if (alphaBottom < 0.f) alphaBottom = 1.f;
00930 }
00931 else
00932 {
00933 alphaBottom = 1.f;
00934 }
00935
00936
00937 const float ox = tPos * I, oy = tPos * J, dx = (destTPos - tPos) * I, dy = (destTPos - tPos) * J;
00938
00939 const float a = (dx * dx) / (dimIt->x * dimIt->x)
00940 + (dy * dy) / (dimIt->y * dimIt->y);
00941 const float b = 2.f * ((ox * dx) / (dimIt->x * dimIt->x)
00942 + (oy * dy) / (dimIt->y * dimIt->y));
00943 const float c = (ox * ox) / (dimIt->x * dimIt->x) + (oy * oy) / (dimIt->y * dimIt->y) - 1;
00944
00945 const float delta = b * b - 4.f * a * c;
00946
00947 if (delta < epsilon)
00948 {
00949 alphaCyl = 1.f;
00950 }
00951 else
00952 {
00953 const float deltaRoot = sqrtf(delta);
00954 const float r1 = (- b + 2.f * deltaRoot) / (2.f * a);
00955 const float r2 = (- b - 2.f * deltaRoot) / (2.f * a);
00956
00957 if (r1 < 0.f) alphaCyl = r2;
00958 else if (r2 < 0.f) alphaCyl = r1;
00959 else alphaCyl = r1 < r2 ? r1 : r2;
00960
00961 if (alphaCyl < 0.f) alphaCyl = 1.f;
00962 }
00963 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00964
00965 if (alphaTop < alphaBottom && alphaTop < alphaCyl)
00966 {
00967
00968 CVector startEnd = alphaTop * (dest - pos);
00969 ci.NewPos = pos + startEnd + PSCollideEpsilon * K;
00970 ci.Dist = startEnd.norm();
00971 ci.NewSpeed = (-2.f * (speed * K)) * K + speed;
00972 ci.CollisionZone = this;
00973 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00974 }
00975 else
00976 if (alphaBottom < alphaCyl)
00977 {
00978
00979 CVector startEnd = alphaBottom * (dest - pos);
00980 ci.NewPos = pos + startEnd - PSCollideEpsilon * K;
00981 ci.Dist = startEnd.norm();
00982 ci.NewSpeed = (-2.f * (speed * K)) * K + speed;
00983 ci.CollisionZone = this;
00984 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00985 }
00986 else
00987 {
00988
00989 CVector startEnd = alphaCyl * (dest - pos);
00990
00991
00992
00993 float px = ox + alphaCyl * dx;
00994 float py = oy + alphaCyl * dy;
00995 CVector normal = px / (dimIt->x * dimIt->x) * I + py / (dimIt->y * dimIt->y) * J;
00996 normal.normalize();
00997 ci.NewPos = pos + startEnd + PSCollideEpsilon * normal;
00998 ci.Dist = startEnd.norm();
00999 ci.NewSpeed = (-2.f * (speed * normal)) * normal + speed;
01000 ci.CollisionZone = this;
01001 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
01002 }
01003
01004 }
01005 }
01006 ++ itPosBefore;
01007 ++ itPosAfter;
01008 }
01009 }
01010 }
01011
01012 void CPSZoneCylinder::show()
01013 {
01014 NL_PS_FUNC(CPSZoneCylinder_show)
01015 TPSAttribVector::const_iterator dimIt = _Dim.begin()
01016 ,posIt = _Owner->getPos().begin()
01017 , endPosIt = _Owner->getPos().end();
01018
01019 CPSAttrib<CPlaneBasis>::const_iterator basisIt = _Basis.begin();
01020
01021 setupDriverModelMatrix();
01022 CMatrix mat;
01023
01024
01025
01026 CPSLocated *loc;
01027 uint32 index;
01028 CPSLocatedBindable *lb;
01029 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01030
01031
01032 for (uint32 k = 0; posIt != endPosIt; ++posIt, ++dimIt, ++basisIt, ++k)
01033 {
01034 mat.setRot(basisIt->X, basisIt->Y, basisIt->X ^ basisIt->Y);
01035 mat.setPos(CVector::Null);
01036
01037 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01038
01039
01040 CPSUtil::displayCylinder(*getDriver(), *posIt, mat, *dimIt, 32, col);
01041
01042 mat.setPos(*posIt);
01043 CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01044 setupDriverModelMatrix();
01045
01046 }
01047 }
01048
01049
01050
01051 void CPSZoneCylinder::setMatrix(uint32 index, const CMatrix &m)
01052 {
01053 NL_PS_FUNC(CPSZoneCylinder_setMatrix)
01054
01055 _Basis[index].X = m.getI();
01056 _Basis[index].Y = m.getJ();
01057
01058
01059 _Owner->getPos()[index] = m.getPos();
01060
01061
01062 }
01063
01064
01065
01066 CMatrix CPSZoneCylinder::getMatrix(uint32 index) const
01067 {
01068 NL_PS_FUNC(CPSZoneCylinder_getMatrix)
01069 CMatrix m;
01070 m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^_Basis[index].Y);
01071 m.setPos(_Owner->getPos()[index]);
01072 return m;
01073 }
01074
01075
01076 void CPSZoneCylinder::setScale(uint32 k, float scale)
01077 {
01078 NL_PS_FUNC(CPSZoneCylinder_setScale)
01079 _Dim[k] = CVector(scale, scale, scale);
01080 }
01081
01082 CVector CPSZoneCylinder::getScale(uint32 k) const
01083 {
01084 NL_PS_FUNC(CPSZoneCylinder_getScale)
01085 return _Dim[k];
01086 }
01087
01088 void CPSZoneCylinder::setScale(uint32 index, const CVector &s)
01089 {
01090 NL_PS_FUNC(CPSZoneCylinder_setScale)
01091 _Dim[index] = s;
01092 }
01093
01094
01095 void CPSZoneCylinder::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01096 {
01097 NL_PS_FUNC(CPSZoneCylinder_serial)
01098 f.serialVersion(1);
01099 CPSZone::serial(f);
01100 f.serial(_Basis);
01101 f.serial(_Dim);
01102 }
01103
01104
01105
01106 void CPSZoneCylinder::resize(uint32 size)
01107 {
01108 NL_PS_FUNC(CPSZoneCylinder_resize)
01109 nlassert(size < (1 << 16));
01110 _Basis.resize(size);
01111 _Dim.resize(size);
01112 }
01113
01114 void CPSZoneCylinder::newElement(const CPSEmitterInfo &info)
01115 {
01116 NL_PS_FUNC(CPSZoneCylinder_newElement)
01117 _Basis.insert(CPlaneBasis(CVector::K));
01118 _Dim.insert(CVector(1, 1, 1));
01119 }
01120
01121 void CPSZoneCylinder::deleteElement(uint32 index)
01122 {
01123 NL_PS_FUNC(CPSZoneCylinder_deleteElement)
01124 _Basis.remove(index);
01125 _Dim.remove(index);
01126 }
01127
01128
01130
01132
01133 void CPSZoneRectangle::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
01134 {
01135 NL_PS_FUNC(CPSZoneRectangle_computeCollisions)
01136 MINI_TIMER(PSStatsZoneRectangle)
01137
01138
01139 TPSAttribVector::const_iterator rectanglePosIt, rectanglePosEnd;
01140 CPSAttrib<CPlaneBasis>::const_iterator basisIt;
01141 TPSAttribFloat::const_iterator widthIt, heightIt;
01142 CPSCollisionInfo ci;
01143
01144 basisIt = _Basis.begin();
01145 heightIt = _Height.begin();
01146 widthIt = _Width.begin();
01147 rectanglePosEnd = _Owner->getPos().end();
01148 for (rectanglePosIt = _Owner->getPos().begin(); rectanglePosIt != rectanglePosEnd; ++rectanglePosIt, ++basisIt, ++widthIt, ++heightIt)
01149 {
01150
01151 const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
01152 NLMISC::CPlane p;
01153 CVector center = m * (*rectanglePosIt);
01154 const CVector X = m.mulVector(basisIt->X);
01155 const CVector Y = m.mulVector(basisIt->Y);
01156 p.make(X ^ Y, center);
01157
01158 const float epsilon = 0.5f * PSCollideEpsilon;
01159 const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
01160 const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
01161 const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
01162 while (itPosBefore != itPosBeforeEnd)
01163 {
01164 float posSide = p * *itPosBefore;
01165 float negSide = p * *itPosAfter;
01166 if (posSide >= - epsilon && negSide <= epsilon)
01167 {
01168 float alpha;
01169 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
01170 {
01171 alpha = posSide / (posSide - negSide);
01172 }
01173 else
01174 {
01175 alpha = 0.f;
01176 }
01177 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
01178 ci.Dist = startEnd.norm();
01179
01180 ci.NewPos = *itPosBefore + startEnd;
01181
01182 if ( fabs( (ci.NewPos - center) * X ) < *widthIt && fabs( (ci.NewPos - center) * Y ) < *heightIt)
01183 {
01184 ci.NewPos += PSCollideEpsilon * p.getNormal();
01185 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
01186 ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
01187 ci.CollisionZone = this;
01188 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
01189 }
01190 }
01191 ++ itPosBefore;
01192 ++ itPosAfter;
01193 }
01194 }
01195
01196 }
01197
01198
01199 void CPSZoneRectangle::show()
01200 {
01201 NL_PS_FUNC(CPSZoneRectangle_show)
01202 nlassert(_Owner);
01203 const uint size = _Owner->getSize();
01204 if (!size) return;
01205 setupDriverModelMatrix();
01206 CMatrix mat;
01207
01208 CPSLocated *loc;
01209 uint32 index;
01210 CPSLocatedBindable *lb;
01211 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01212
01213 for (uint k = 0; k < size; ++k)
01214 {
01215 const CVector &I = _Basis[k].X;
01216 const CVector &J = _Basis[k].Y;
01217 mat.setRot(I, J , I ^J);
01218 mat.setPos(_Owner->getPos()[k]);
01219 CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01220 setupDriverModelMatrix();
01221
01222 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
01223
01224
01225
01226 const CVector &pos = _Owner->getPos()[k];
01227 CPSUtil::display3DQuad(*getDriver(), pos + I * _Width[k] + J * _Height[k]
01228 , pos + I * _Width[k] - J * _Height[k]
01229 , pos - I * _Width[k] - J * _Height[k]
01230 , pos - I * _Width[k] + J * _Height[k], col);
01231 }
01232 }
01233
01234 void CPSZoneRectangle::setMatrix(uint32 index, const CMatrix &m)
01235 {
01236 NL_PS_FUNC(CPSZoneRectangle_setMatrix)
01237 nlassert(_Owner);
01238
01239 _Owner->getPos()[index] = m.getPos();
01240 _Basis[index].X = m.getI();
01241 _Basis[index].Y = m.getJ();
01242 }
01243
01244
01245 CMatrix CPSZoneRectangle::getMatrix(uint32 index) const
01246 {
01247 NL_PS_FUNC(CPSZoneRectangle_getMatrix)
01248 nlassert(_Owner);
01249 CMatrix m;
01250 m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^ _Basis[index].Y);
01251 m.setPos(_Owner->getPos()[index]);
01252 return m;
01253 }
01254
01255 void CPSZoneRectangle::setScale(uint32 index, float scale)
01256 {
01257 NL_PS_FUNC(CPSZoneRectangle_setScale)
01258 _Width[index] = scale;
01259 _Height[index] = scale;
01260 }
01261 void CPSZoneRectangle::setScale(uint32 index, const CVector &s)
01262 {
01263 NL_PS_FUNC(CPSZoneRectangle_setScale)
01264 _Width[index] = s.x;
01265 _Height[index] = s.y;
01266 }
01267 CVector CPSZoneRectangle::getScale(uint32 index) const
01268 {
01269 NL_PS_FUNC(CPSZoneRectangle_getScale)
01270 return CVector(_Width[index], _Height[index], 1.f);
01271 }
01272
01273
01274
01275 void CPSZoneRectangle::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01276 {
01277 NL_PS_FUNC(CPSZoneRectangle_IStream )
01278 f.serialVersion(1);
01279 CPSZone::serial(f);
01280 f.serial(_Basis);
01281 f.serial(_Width);
01282 f.serial(_Height);
01283 }
01284
01285
01286 void CPSZoneRectangle::resize(uint32 size)
01287 {
01288 NL_PS_FUNC(CPSZoneRectangle_resize)
01289 nlassert(size < (1 << 16));
01290 _Basis.resize(size);
01291 _Width.resize(size);
01292 _Height.resize(size);
01293 }
01294
01295 void CPSZoneRectangle::newElement(const CPSEmitterInfo &info)
01296 {
01297 NL_PS_FUNC(CPSZoneRectangle_newElement)
01298 _Basis.insert(CPlaneBasis(CVector::K));
01299 _Width.insert(1.f);
01300 _Height.insert(1.f);
01301 }
01302
01303 void CPSZoneRectangle::deleteElement(uint32 index)
01304 {
01305 NL_PS_FUNC(CPSZoneRectangle_deleteElement)
01306 _Basis.remove(index);
01307 _Width.remove(index);
01308 _Height.remove(index);
01309 }
01310
01311
01312
01313 }