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_force.h"
00029 #include "3d/driver.h"
00030 #include "3d/primitive_block.h"
00031 #include "3d/material.h"
00032 #include "3d/vertex_buffer.h"
00033 #include "3d/computed_string.h"
00034 #include "3d/font_manager.h"
00035 #include "3d/particle_system.h"
00036 #include "nel/misc/common.h"
00037 #include "3d/ps_util.h"
00038 #include "3d/ps_misc.h"
00039
00040 namespace NL3D {
00041
00042
00043
00044
00045
00046 CPSForce::CPSForce()
00047 {
00048 }
00049
00050
00051
00052 void CPSForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00053 {
00054
00055 f.serialVersion(1);
00056 CPSTargetLocatedBindable::serial(f);
00057 CPSLocatedBindable::serial(f);
00058
00059 }
00060
00061
00062 void CPSForce::registerToTargets(void)
00063 {
00064 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00065 {
00066 if (this->isIntegrable())
00067 {
00068 (*it)->registerIntegrableForce(this);
00069 }
00070 else
00071 {
00072 (*it)->addNonIntegrableForceRef();
00073 }
00074 }
00075 }
00076
00077
00078 void CPSForce::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEllapsedTime)
00079 {
00080 switch(pass)
00081 {
00082 case PSMotion:
00083 performDynamic(ellapsedTime);
00084 break;
00085 case PSToolRender:
00086 show(ellapsedTime);
00087 break;
00088 default: break;
00089 }
00090 }
00091
00092
00093
00094 void CPSForce::attachTarget(CPSLocated *ptr)
00095 {
00096 nlassert(_Owner);
00097 CPSTargetLocatedBindable::attachTarget(ptr);
00098
00099 if (this->isIntegrable())
00100 {
00101 ptr->registerIntegrableForce(this);
00102 }
00103 else
00104 {
00105 ptr->addNonIntegrableForceRef();
00106 }
00107 }
00108
00109 void CPSForce::releaseTargetRsc(CPSLocated *target)
00110 {
00111 if (this->isIntegrable())
00112 {
00113 target->unregisterIntegrableForce(this);
00114 }
00115 else
00116 {
00117 target->releaseNonIntegrableForceRef();
00118 }
00119 }
00120
00121
00122
00123 void CPSForce::basisChanged(bool systemBasis)
00124 {
00125 if (!this->isIntegrable()) return;
00126 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00127 {
00128 (*it)->integrableForceBasisChanged(systemBasis);
00129 }
00130 }
00131
00132
00133 void CPSForce::cancelIntegrable(void)
00134 {
00135 nlassert(_Owner);
00136 bool useSystemBasis = _Owner->isInSystemBasis();
00137 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00138 {
00139 if ((*it)->isInSystemBasis() == useSystemBasis)
00140 {
00141 (*it)->unregisterIntegrableForce(this);
00142 (*it)->addNonIntegrableForceRef();
00143 }
00144 }
00145 }
00146
00147
00148 void CPSForce::renewIntegrable(void)
00149 {
00150 nlassert(_Owner);
00151 bool useSystemBasis = _Owner->isInSystemBasis();
00152 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00153 {
00154 if ((*it)->isInSystemBasis() == useSystemBasis)
00155 {
00156 (*it)->registerIntegrableForce(this);
00157 (*it)->releaseNonIntegrableForceRef();
00158 }
00159 }
00160 }
00161
00162
00163
00165
00167
00168 void CPSForceIntensity::setIntensity(float value)
00169 {
00170 if (_IntensityScheme)
00171 {
00172 delete _IntensityScheme;
00173 _IntensityScheme = NULL;
00174 }
00175 _K = value;
00176
00177 }
00178
00179 CPSForceIntensity::~CPSForceIntensity()
00180 {
00181 delete _IntensityScheme;
00182 }
00183
00184 void CPSForceIntensity::setIntensityScheme(CPSAttribMaker<float> *scheme)
00185 {
00186 nlassert(scheme);
00187 delete _IntensityScheme;
00188 _IntensityScheme = scheme;
00189 if (getForceIntensityOwner() && scheme->hasMemory()) scheme->resize(getForceIntensityOwner()->getMaxSize(), getForceIntensityOwner()->getSize());
00190 }
00191
00192 void CPSForceIntensity::serialForceIntensity(NLMISC::IStream &f) throw(NLMISC::EStream)
00193 {
00194 f.serialVersion(1);
00195 if (!f.isReading())
00196 {
00197 if (_IntensityScheme)
00198 {
00199 bool bFalse = false;
00200 f.serial(bFalse);
00201 f.serialPolyPtr(_IntensityScheme);
00202 }
00203 else
00204 {
00205 bool bTrue = true;
00206 f.serial(bTrue);
00207 f.serial(_K);
00208 }
00209 }
00210 else
00211 {
00212 bool constantIntensity;
00213 f.serial(constantIntensity);
00214 if (constantIntensity)
00215 {
00216 f.serial(_K);
00217 }
00218 else
00219 {
00220 f.serialPolyPtr(_IntensityScheme);
00221 }
00222 }
00223 }
00224
00225
00227
00229
00230
00231 void CPSForceIntensityHelper::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00232 {
00233 f.serialVersion(1);
00234 CPSForce::serial(f);
00235 serialForceIntensity(f);
00236 if (f.isReading())
00237 {
00238 registerToTargets();
00239 }
00240 }
00241
00242
00243
00245
00247
00248
00249 void CPSDirectionnalForce::performDynamic(TAnimationTime ellapsedTime)
00250 {
00251
00252 CVector toAdd;
00253 for (uint32 k = 0; k < _Owner->getSize(); ++k)
00254 {
00255 CVector toAddLocal;
00256 CVector dir;
00257
00258 if (_GlobalValueHandle.isValid())
00259 {
00260 dir = _GlobalValueHandle.get();
00261 }
00262 else
00263 {
00264 dir = _Dir;
00265 }
00266
00267 toAddLocal = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K ) * dir;
00268 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00269 {
00270
00271 toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(toAddLocal);
00272 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
00273
00274 if ((*it)->getMassScheme())
00275 {
00276 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00277 for (; it2 != it2end; ++it2, ++invMassIt)
00278 {
00279 (*it2) += *invMassIt * toAdd;
00280
00281 }
00282 }
00283 else
00284 {
00285
00286 toAdd /= (*it)->getInitialMass();
00287 for (; it2 != it2end; ++it2)
00288 {
00289 (*it2) += toAdd;
00290 }
00291 }
00292 }
00293 }
00294 }
00295
00296
00297 void CPSDirectionnalForce::show(TAnimationTime ellapsedTime)
00298 {
00299 CPSLocated *loc;
00300 uint32 index;
00301 CPSLocatedBindable *lb;
00302 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00303
00304 setupDriverModelMatrix();
00305
00306 CVector dir;
00307 if (_GlobalValueHandle.isValid())
00308 {
00309 dir = _GlobalValueHandle.get();
00310 }
00311 else
00312 {
00313 dir = _Dir;
00314 }
00315
00316
00317 for (uint k = 0; k < _Owner->getSize(); ++k)
00318 {
00319 const CRGBA col = (((lb == NULL || this == lb) && loc == _Owner && index == k) ? CRGBA::Red : CRGBA(127, 127, 127));
00320 CPSUtil::displayArrow(getDriver(), _Owner->getPos()[k], dir, 1.f, col, CRGBA(80, 80, 0));
00321 }
00322 }
00323
00324 void CPSDirectionnalForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00325 {
00326
00327
00328 sint ver = f.serialVersion(2);
00329 CPSForceIntensityHelper::serial(f);
00330 if (ver == 1)
00331 {
00332 f.serial(_Dir);
00333 _GlobalValueHandle.reset();
00334 }
00335 else
00336 {
00337 bool useHandle = _GlobalValueHandle.isValid();
00338 f.serial(useHandle);
00339 if (useHandle)
00340 {
00341
00342 if (f.isReading())
00343 {
00344 std::string handleName;
00345 f.serial(handleName);
00346
00347 _GlobalValueHandle = CParticleSystem::getGlobalVectorValueHandle(handleName);
00348 }
00349 else
00350 {
00351 std::string handleName = _GlobalValueHandle.getName();
00352 f.serial(handleName);
00353 }
00354 }
00355 else
00356 {
00357 f.serial(_Dir);
00358 }
00359 }
00360 }
00361
00362 void CPSDirectionnalForce::enableGlobalVectorValue(const std::string &name)
00363 {
00364 if (name.empty())
00365 {
00366 _GlobalValueHandle.reset();
00367 return;
00368 }
00369 _GlobalValueHandle = CParticleSystem::getGlobalVectorValueHandle(name);
00370 }
00371
00372 std::string CPSDirectionnalForce::getGlobalVectorValueName() const
00373 {
00374 return _GlobalValueHandle.isValid() ? _GlobalValueHandle.getName() : "";
00375 }
00376
00378
00380
00381
00382 void CPSGravity::performDynamic(TAnimationTime ellapsedTime)
00383 {
00384
00385
00386 CVector toAdd;
00387 for (uint32 k = 0; k < _Owner->getSize(); ++k)
00388 {
00389 CVector toAddLocal = ellapsedTime * CVector(0, 0, _IntensityScheme ? - _IntensityScheme->get(_Owner, k) : - _K);
00390 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00391 {
00392 toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(toAddLocal);
00393 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
00394
00395 if (toAdd.x && toAdd.y)
00396 {
00397 for (; it2 != it2end; ++it2)
00398 {
00399 (*it2) += toAdd;
00400
00401 }
00402 }
00403 else
00404 {
00405 for (; it2 != it2end; ++it2)
00406 {
00407 it2->z += toAdd.z;
00408
00409 }
00410 }
00411 }
00412 }
00413 }
00414
00415 void CPSGravity::show(TAnimationTime ellapsedTime)
00416 {
00417 CVector I = computeI();
00418 CVector K = CVector(0,0,1);
00419
00420
00421 CPrimitiveBlock pb;
00422 CVertexBuffer vb;
00423 CMaterial material;
00424 IDriver *driver = getDriver();
00425 const float toolSize = 0.2f;
00426
00427 vb.setVertexFormat(CVertexBuffer::PositionFlag);
00428 vb.setNumVertices(6);
00429 vb.setVertexCoord(0, -toolSize * I);
00430 vb.setVertexCoord(1, toolSize * I);
00431 vb.setVertexCoord(2, CVector(0, 0, 0));
00432 vb.setVertexCoord(3, -6.0f * toolSize * K);
00433 vb.setVertexCoord(4, -toolSize * I - 5.0f * toolSize * K);
00434 vb.setVertexCoord(5, toolSize * I - 5.0f * toolSize * K);
00435
00436 pb.reserveLine(4);
00437 pb.addLine(0, 1);
00438 pb.addLine(2, 3);
00439 pb.addLine(4, 3);
00440 pb.addLine(3, 5);
00441
00442 material.setColor(CRGBA(127, 127, 127));
00443 material.setLighting(false);
00444 material.setBlendFunc(CMaterial::one, CMaterial::one);
00445 material.setZWrite(false);
00446 material.setBlend(true);
00447
00448
00449 CMatrix mat;
00450
00451 for (TPSAttribVector::const_iterator it = _Owner->getPos().begin(); it != _Owner->getPos().end(); ++it)
00452 {
00453 mat.identity();
00454 mat.translate(*it);
00455 if (_Owner->isInSystemBasis())
00456 {
00457 mat = getSysMat() * mat;
00458 }
00459
00460 driver->setupModelMatrix(mat);
00461 driver->activeVertexBuffer(vb);
00462 driver->render(pb, material);
00463
00464
00465
00466
00467
00468 CVector pos = *it + CVector(1.5f * toolSize, 0, -1.2f * toolSize);
00469
00470 if (_Owner->isInSystemBasis())
00471 {
00472 pos = getSysMat() * pos;
00473 }
00474
00475
00476 nlassert(getFontGenerator() && getFontGenerator());
00477
00478 CPSUtil::print(driver, std::string("G")
00479 , *getFontGenerator()
00480 , *getFontManager()
00481 , pos
00482 , 80.0f * toolSize );
00483 }
00484
00485
00486 }
00487
00488 void CPSGravity::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00489 {
00490 f.serialVersion(1);
00491 CPSForceIntensityHelper::serial(f);
00492 }
00493
00494
00495 bool CPSGravity::isIntegrable(void) const
00496 {
00497 return _IntensityScheme == NULL;
00498 }
00499
00500 void CPSGravity::integrate(float date, CPSLocated *src, uint32 startIndex, uint32 numObjects, NLMISC::CVector *destPos, NLMISC::CVector *destSpeed,
00501 bool accumulate,
00502 uint posStride, uint speedStride
00503 )
00504 {
00505 #define NEXT_SPEED destSpeed = (NLMISC::CVector *) ((uint8 *) destSpeed + speedStride);
00506 #define NEXT_POS destPos = (NLMISC::CVector *) ((uint8 *) destPos + posStride);
00507
00508 float deltaT;
00509
00510 if (!destPos && !destSpeed) return;
00511
00512 CPSLocated::TPSAttribParametricInfo::const_iterator it = src->_PInfo.begin() + startIndex,
00513 endIt = src->_PInfo.begin() + startIndex + numObjects;
00514 if (!accumulate)
00515 {
00516 if (destPos && !destSpeed)
00517 {
00518 while (it != endIt)
00519 {
00520 deltaT = date - it->Date;
00521 destPos->x = it->Pos.x + deltaT * it->Speed.x;
00522 destPos->y = it->Pos.y + deltaT * it->Speed.y;
00523 destPos->z = it->Pos.z + deltaT * it->Speed.z - 0.5f * deltaT * deltaT * _K;
00524 ++it;
00525 NEXT_POS;
00526 }
00527 }
00528 else if (!destPos && destSpeed)
00529 {
00530 while (it != endIt)
00531 {
00532 deltaT = date - it->Date;
00533 destSpeed->x = it->Speed.x;
00534 destSpeed->y = it->Speed.y;
00535 destSpeed->z = it->Speed.z - deltaT * _K;
00536 ++it;
00537 NEXT_SPEED;
00538 }
00539 }
00540 else
00541 {
00542 while (it != endIt)
00543 {
00544 deltaT = date - it->Date;
00545 destPos->x = it->Pos.x + deltaT * it->Speed.x;
00546 destPos->y = it->Pos.y + deltaT * it->Speed.y;
00547 destPos->z = it->Pos.z + deltaT * it->Speed.z - 0.5f * deltaT * deltaT * _K;
00548
00549 destSpeed->x = it->Speed.x;
00550 destSpeed->y = it->Speed.y;
00551 destSpeed->z = it->Speed.z - deltaT * _K;
00552
00553 ++it;
00554 NEXT_POS;
00555 NEXT_SPEED;
00556 }
00557 }
00558 }
00559 else
00560 {
00561 if (destPos && !destSpeed)
00562 {
00563 while (it != endIt)
00564 {
00565 deltaT = date - it->Date;
00566 destPos->z -= 0.5f * deltaT * deltaT * _K;
00567 ++it;
00568 NEXT_POS;
00569 }
00570 }
00571 else if (!destPos && destSpeed)
00572 {
00573 while (it != endIt)
00574 {
00575 deltaT = date - it->Date;
00576 destSpeed->z -= deltaT * _K;
00577 ++it;
00578 NEXT_SPEED;
00579 }
00580 }
00581 else
00582 {
00583 while (it != endIt)
00584 {
00585 deltaT = date - it->Date;
00586 destPos->z -= 0.5f * deltaT * deltaT * _K;
00587 destSpeed->z -= deltaT * _K;
00588 ++it;
00589 NEXT_POS;
00590 NEXT_SPEED;
00591 }
00592 }
00593 }
00594
00595 }
00596
00597
00598
00599 void CPSGravity::integrateSingle(float startDate, float deltaT, uint numStep,
00600 CPSLocated *src, uint32 indexInLocated,
00601 NLMISC::CVector *destPos,
00602 bool accumulate ,
00603 uint stride)
00604 {
00605 nlassert(src->isParametricMotionEnabled());
00606 nlassert(deltaT > 0);
00607 nlassert(numStep > 0);
00608 #ifdef NL_DEBUG
00609 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
00610 #endif
00611 const CPSLocated::CParametricInfo &pi = src->_PInfo[indexInLocated];
00612 const NLMISC::CVector &startPos = pi.Pos;
00613 if (numStep != 0)
00614 {
00615 if (!accumulate)
00616 {
00617 destPos = FillBufUsingSubdiv(startPos, pi.Date, startDate, deltaT, numStep, destPos, stride);
00618 if (numStep != 0)
00619 {
00620 float currDate = startDate - pi.Date;
00621 nlassert(currDate >= 0);
00622 const NLMISC::CVector &startSpeed = pi.Speed;
00623 do
00624 {
00625 #ifdef NL_DEBUG
00626 nlassert(destPos < endPos);
00627 #endif
00628 float halfTimeSquare = 0.5f * currDate * currDate;
00629 destPos->x = startPos.x + currDate * startSpeed.x;
00630 destPos->y = startPos.y + currDate * startSpeed.y;
00631 destPos->z = startPos.z + currDate * startSpeed.z - _K * halfTimeSquare;
00632 currDate += deltaT;
00633 destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00634 }
00635 while (--numStep);
00636 }
00637 }
00638 else
00639 {
00640 uint numToSkip = ScaleFloatGE(startDate, deltaT, pi.Date, numStep);
00641 if (numToSkip < numStep)
00642 {
00643 numStep -= numToSkip;
00644 float currDate = startDate + deltaT * numToSkip - pi.Date;
00645 do
00646 {
00647 #ifdef NL_DEBUG
00648 nlassert(destPos < endPos);
00649 #endif
00650 float halfTimeSquare = 0.5f * currDate * currDate;
00651 destPos->z -= _K * halfTimeSquare;
00652 currDate += deltaT;
00653 destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
00654 }
00655 while (--numStep);
00656 }
00657 }
00658 }
00659 }
00660
00661
00662 void CPSGravity::setIntensity(float value)
00663 {
00664 if (_IntensityScheme)
00665 {
00666 CPSForceIntensityHelper::setIntensity(value);
00667 renewIntegrable();
00668 }
00669 else
00670 {
00671 CPSForceIntensityHelper::setIntensity(value);
00672 }
00673 }
00674
00675 void CPSGravity::setIntensityScheme(CPSAttribMaker<float> *scheme)
00676 {
00677 if (!_IntensityScheme)
00678 {
00679 cancelIntegrable();
00680 }
00681 CPSForceIntensityHelper::setIntensityScheme(scheme);
00682 }
00683
00684
00686
00688
00689
00690 void CPSCentralGravity::performDynamic(TAnimationTime ellapsedTime)
00691 {
00692
00693
00694
00695
00696 uint32 size = _Owner->getSize();
00697
00698
00699 CVector centerToObj;
00700 float dist;
00701
00702 for (uint32 k = 0; k < size; ++k)
00703 {
00704 const float ellapsedTimexK = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00705
00706 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00707 {
00708 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00709 const CVector center = m * (_Owner->getPos()[k]);
00710
00711 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End = (*it)->getSpeed().end();
00712 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00713 TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00714
00715 for (; it2 != it2End; ++it2, ++invMassIt, ++posIt)
00716 {
00717
00718 centerToObj = center - *posIt;
00719
00720 dist = centerToObj * centerToObj;
00721 if (dist > 10E-6f)
00722 {
00723 (*it2) += (*invMassIt) * ellapsedTimexK * (1.f / dist) * centerToObj;
00724 }
00725 }
00726 }
00727 }
00728
00729 }
00730
00731 void CPSCentralGravity::show(TAnimationTime ellapsedTime)
00732 {
00733 CVector I = CVector::I;
00734 CVector J = CVector::J;
00735
00736 const CVector tab[] = { -I - J, I - J
00737 ,-I + J, I + J
00738 , I - J, I + J
00739 , -I - J, -I + J
00740 , I + J, -I - J
00741 , I - J, J - I
00742 };
00743 const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
00744
00745 const float sSize = 0.08f;
00746 displayIcon2d(tab, tabSize, sSize);
00747 }
00748
00749 void CPSCentralGravity::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00750 {
00751 f.serialVersion(1);
00752 CPSForceIntensityHelper::serial(f);
00753 }
00754
00755
00757
00759
00760
00761
00762 void CPSSpring::performDynamic(TAnimationTime ellapsedTime)
00763 {
00764
00765
00766
00767
00768 uint32 size = _Owner->getSize();
00769
00770
00771 for (uint32 k = 0; k < size; ++k)
00772 {
00773 const float ellapsedTimexK = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00774
00775 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00776 {
00777 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00778 const CVector center = m * (_Owner->getPos()[k]);
00779
00780 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End = (*it)->getSpeed().end();
00781 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00782 TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00783
00784 for (; it2 != it2End; ++it2, ++invMassIt, ++posIt)
00785 {
00786
00787 (*it2) += (*invMassIt) * ellapsedTimexK * (center - *posIt);
00788 }
00789 }
00790 }
00791 }
00792
00793
00794 void CPSSpring::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00795 {
00796 f.serialVersion(1);
00797 CPSForceIntensityHelper::serial(f);
00798 }
00799
00800
00801
00802 void CPSSpring::show(TAnimationTime ellapsedTime)
00803 {
00804 CVector I = CVector::I;
00805 CVector J = CVector::J;
00806 static const CVector tab[] =
00807 {
00808 -I + 2 * J,
00809 I + 2 * J,
00810 I + 2 * J, -I + J,
00811 -I + J, I + J,
00812 I + J, -I,
00813 -I, I,
00814 I, -I - J,
00815 -I - J, I - J,
00816 I - J,
00817 - I - 2 * J,
00818 - I - 2 * J,
00819 I - 2 * J
00820 };
00821 const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
00822 const float sSize = 0.08f;
00823 displayIcon2d(tab, tabSize, sSize);
00824 }
00825
00826
00828
00830
00831 void CPSCylindricVortex::performDynamic(TAnimationTime ellapsedTime)
00832 {
00833 uint32 size = _Owner->getSize();
00834
00835 for (uint32 k = 0; k < size; ++k)
00836 {
00837
00838 const float invR = 1.f / _Radius[k];
00839 const float radius2 = _Radius[k] * _Radius[k];
00840
00841
00842 nlassert(_Owner);
00843 float intensity = (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00844
00845 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00846 {
00847
00848 const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00849 const CVector center = m * (_Owner->getPos()[k]);
00850 const CVector n = m.mulVector(_Normal[k]);
00851
00852 TPSAttribVector::iterator speedIt = (*it)->getSpeed().begin(), speedItEnd = (*it)->getSpeed().end();
00853 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
00854 TPSAttribVector::const_iterator posIt = (*it)->getPos().begin();
00855
00856
00857
00858 CVector p;
00859
00860 CVector v2p;
00861
00862
00863 float d2 , d;
00864
00865 CVector realTangentialSpeed;
00866 CVector tangentialSpeed;
00867
00868
00869 CVector radialSpeed;
00870
00871
00872 for (; speedIt != speedItEnd; ++speedIt, ++invMassIt, ++posIt)
00873 {
00874 v2p = *posIt - center;
00875 p = v2p - (v2p * n) * n;
00876
00877 d2 = p * p;
00878
00879
00880
00881 if (d2 < radius2)
00882 {
00883 if (d2 > 10E-6)
00884 {
00885 d = sqrtf(d2);
00886
00887 p *= 1.f / d;
00888
00889 realTangentialSpeed = n ^ p;
00890
00891 tangentialSpeed = (*speedIt * realTangentialSpeed) * realTangentialSpeed;
00892 radialSpeed = (p * *speedIt) * p;
00893
00894
00895 *speedIt -= _RadialViscosity * ellapsedTime * radialSpeed;
00896
00897
00898 *speedIt -= _TangentialViscosity * intensity * ellapsedTime * (tangentialSpeed - (1.f - d * invR) * realTangentialSpeed);
00899 }
00900 }
00901 }
00902 }
00903 }
00904 }
00905
00906
00907 void CPSCylindricVortex::show(TAnimationTime ellapsedTime)
00908 {
00909
00910 CPSLocated *loc;
00911 uint32 index;
00912 CPSLocatedBindable *lb;
00913 _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00914
00915
00916
00917 nlassert(getFontGenerator() && getFontGenerator());
00918 setupDriverModelMatrix();
00919
00920 for (uint k = 0; k < _Owner->getSize(); ++k)
00921 {
00922 const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k ? CRGBA::Red : CRGBA(127, 127, 127));
00923 CMatrix m;
00924 CPSUtil::buildSchmidtBasis(_Normal[k], m);
00925 CPSUtil::displayDisc(*getDriver(), _Radius[k], _Owner->getPos()[k], m, 32, col);
00926 CPSUtil::displayArrow(getDriver(), _Owner->getPos()[k], _Normal[k], 1.f, col, CRGBA(200, 0, 200));
00927
00928 CPSUtil::print(getDriver(), std::string("v"), *getFontGenerator(), *getFontManager(), _Owner->getPos()[k], 80.f);
00929 }
00930
00931 }
00932
00933 void CPSCylindricVortex::setMatrix(uint32 index, const CMatrix &m)
00934 {
00935 nlassert(index < _Normal.getSize());
00936 _Normal[index] = m.getK();
00937 _Owner->getPos()[index] = m.getPos();
00938 }
00939
00940 CMatrix CPSCylindricVortex::getMatrix(uint32 index) const
00941 {
00942 CMatrix m;
00943 CPSUtil::buildSchmidtBasis(_Normal[index], m);
00944 m.setPos(_Owner->getPos()[index] );
00945 return m;
00946 }
00947
00948
00949 void CPSCylindricVortex::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00950 {
00951 f.serialVersion(1);
00952 CPSForceIntensityHelper::serial(f);
00953 f.serial(_Normal);
00954 f.serial(_Radius);
00955 f.serial(_RadialViscosity);
00956 f.serial(_TangentialViscosity);
00957 }
00958
00959 void CPSCylindricVortex::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00960 {
00961 CPSForceIntensityHelper::newElement(emitterLocated, emitterIndex);
00962 _Normal.insert(CVector::K);
00963 _Radius.insert(1.f);
00964 }
00965 void CPSCylindricVortex::deleteElement(uint32 index)
00966 {
00967 CPSForceIntensityHelper::deleteElement(index);
00968 _Normal.remove(index);
00969 _Radius.remove(index);
00970 }
00971 void CPSCylindricVortex::resize(uint32 size)
00972 {
00973 nlassert(size < (1 << 16));
00974 CPSForceIntensityHelper::resize(size);
00975 _Normal.resize(size);
00976 _Radius.resize(size);
00977 }
00978
00979
00984 void CPSMagneticForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00985 {
00986 f.serialVersion(1);
00987 CPSDirectionnalForce::serial(f);
00988 }
00989
00990 void CPSMagneticForce::performDynamic(TAnimationTime ellapsedTime)
00991 {
00992
00993 for (uint32 k = 0; k < _Owner->getSize(); ++k)
00994 {
00995 float intensity = ellapsedTime * (_IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K);
00996 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00997 {
00998
00999 NLMISC::CVector toAdd = CPSLocated::getConversionMatrix(*it, this->_Owner).mulVector(_Dir);
01000
01001 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2end = (*it)->getSpeed().end();
01002
01003
01004 if ((*it)->getMassScheme())
01005 {
01006 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
01007 for (; it2 != it2end; ++it2, ++invMassIt)
01008 {
01009 (*it2) += intensity * *invMassIt * (*it2 ^ toAdd);
01010
01011 }
01012 }
01013 else
01014 {
01015 float i = intensity / (*it)->getInitialMass();
01016 for (; it2 != it2end; ++it2)
01017 {
01018 (*it2) += i * (*it2 ^ toAdd);
01019 }
01020 }
01021 }
01022 }
01023 }
01024
01025
01030 const uint BFNumPredefinedPos = 8192;
01031 const uint BFPredefinedNumInterp = 256;
01035 const uint BFNumPrecomputedImpulsions = 1024;
01036
01037 NLMISC::CVector CPSBrownianForce::PrecomputedPos[BFNumPredefinedPos];
01038 NLMISC::CVector CPSBrownianForce::PrecomputedSpeed[BFNumPredefinedPos];
01039 NLMISC::CVector CPSBrownianForce::PrecomputedImpulsions[BFNumPrecomputedImpulsions];
01040
01042 CPSBrownianForce::CPSBrownianForce(float intensity ) : _ParametricFactor(1.f)
01043 {
01044 setIntensity(intensity);
01045 _Name = std::string("BrownianForce");
01046
01047 }
01048
01050 bool CPSBrownianForce::isIntegrable(void) const
01051 {
01052 return _IntensityScheme == NULL;
01053 }
01054
01055
01057 void CPSBrownianForce::integrate(float date, CPSLocated *src,
01058 uint32 startIndex,
01059 uint32 numObjects,
01060 NLMISC::CVector *destPos,
01061 NLMISC::CVector *destSpeed,
01062 bool accumulate,
01063 uint posStride, uint speedStride
01064 )
01065 {
01067 float deltaT;
01068 if (!destPos && !destSpeed) return;
01069 CPSLocated::TPSAttribParametricInfo::const_iterator it = src->_PInfo.begin() + startIndex,
01070 endIt = src->_PInfo.begin() + startIndex + numObjects;
01071 float lookUpFactor = _ParametricFactor * BFNumPredefinedPos;
01072 float speedFactor = _ParametricFactor * _K;
01073 if (!accumulate)
01074 {
01075 if (destPos && !destSpeed)
01076 {
01077 while (it != endIt)
01078 {
01079 float deltaT = date - it->Date;
01080 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01081 destPos->set(it->Pos.x + deltaT * it->Speed.x + _K * PrecomputedPos[index].x,
01082 it->Pos.y + deltaT * it->Speed.y + _K * PrecomputedPos[index].y,
01083 it->Pos.z + deltaT * it->Speed.z + _K * PrecomputedPos[index].z );
01084 ++it;
01085 NEXT_POS;
01086 }
01087 }
01088 else if (!destPos && destSpeed)
01089 {
01090 while (it != endIt)
01091 {
01092 deltaT = date - it->Date;
01093 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01094 destSpeed->x = it->Speed.x + speedFactor * PrecomputedSpeed[index].x;
01095 destSpeed->y = it->Speed.y + speedFactor * PrecomputedSpeed[index].y;
01096 destSpeed->z = it->Speed.z + speedFactor * PrecomputedSpeed[index].z;
01097 ++it;
01098 NEXT_SPEED;
01099 }
01100 }
01101 else
01102 {
01103 while (it != endIt)
01104 {
01105 deltaT = date - it->Date;
01106 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01107 destPos->x = it->Pos.x + deltaT * it->Speed.x + _K * PrecomputedPos[index].x;
01108 destPos->y = it->Pos.y + deltaT * it->Speed.y + _K * PrecomputedPos[index].y;
01109 destPos->z = it->Pos.z + deltaT * it->Speed.z + _K * PrecomputedPos[index].z;
01110
01111 destSpeed->x = it->Speed.x + speedFactor * PrecomputedSpeed[index].x;
01112 destSpeed->y = it->Speed.y + speedFactor * PrecomputedSpeed[index].y;
01113 destSpeed->z = it->Speed.z + speedFactor * PrecomputedSpeed[index].z;
01114
01115 ++it;
01116 NEXT_POS;
01117 NEXT_SPEED;
01118 }
01119 }
01120 }
01121 else
01122 {
01123 if (destPos && !destSpeed)
01124 {
01125 while (it != endIt)
01126 {
01127 deltaT = date - it->Date;
01128 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01129 destPos->set(destPos->x + _K * PrecomputedPos[index].x,
01130 destPos->y + _K * PrecomputedPos[index].y,
01131 destPos->z + _K * PrecomputedPos[index].z);
01132 ++it;
01133 NEXT_POS;
01134 }
01135 }
01136 else if (!destPos && destSpeed)
01137 {
01138 while (it != endIt)
01139 {
01140 deltaT = date - it->Date;
01141 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01142 destSpeed->set(destSpeed->x + speedFactor * PrecomputedSpeed[index].x,
01143 destSpeed->y + speedFactor * PrecomputedSpeed[index].y,
01144 destSpeed->z + speedFactor * PrecomputedSpeed[index].z);
01145 ++it;
01146 NEXT_SPEED;
01147 }
01148 }
01149 else
01150 {
01151 while (it != endIt)
01152 {
01153 deltaT = date - it->Date;
01154 uint index = (uint) (lookUpFactor * deltaT) & (BFNumPredefinedPos - 1);
01155 destPos->set(destPos->x + _K * PrecomputedPos[index].x,
01156 destPos->y + _K * PrecomputedPos[index].y,
01157 destPos->z + _K * PrecomputedPos[index].z);
01158 destSpeed->set(destSpeed->x + speedFactor * PrecomputedSpeed[index].x,
01159 destSpeed->y + speedFactor * PrecomputedSpeed[index].y,
01160 destSpeed->z + speedFactor * PrecomputedSpeed[index].z);
01161 ++it;
01162 NEXT_POS;
01163 NEXT_SPEED;
01164 }
01165 }
01166 }
01167 }
01168
01169
01171 void CPSBrownianForce::integrateSingle(float startDate, float deltaT, uint numStep,
01172 CPSLocated *src, uint32 indexInLocated,
01173 NLMISC::CVector *destPos,
01174 bool accumulate,
01175 uint stride)
01176 {
01177 nlassert(src->isParametricMotionEnabled());
01178 nlassert(deltaT > 0);
01179 nlassert(numStep > 0);
01180 #ifdef NL_DEBUG
01181 NLMISC::CVector *endPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride * numStep);
01182 #endif
01183 const CPSLocated::CParametricInfo &pi = src->_PInfo[indexInLocated];
01184 const NLMISC::CVector &startPos = pi.Pos;
01185 if (numStep != 0)
01186 {
01187 float lookUpFactor = _ParametricFactor * BFPredefinedNumInterp;
01188 if (!accumulate)
01189 {
01191 destPos = FillBufUsingSubdiv(startPos, pi.Date, startDate, deltaT, numStep, destPos, stride);
01192 if (numStep != 0)
01193 {
01194 float currDate = startDate - pi.Date;
01195 nlassert(currDate >= 0);
01196 const NLMISC::CVector &startSpeed = pi.Speed;
01197 do
01198 {
01199 #ifdef NL_DEBUG
01200 nlassert(destPos < endPos);
01201 #endif
01202 uint index = (uint) (lookUpFactor * currDate) & (BFNumPredefinedPos - 1);
01203 destPos->x = startPos.x + currDate * startSpeed.x + _K * PrecomputedPos[index].x;
01204 destPos->y = startPos.y + currDate * startSpeed.y + _K * PrecomputedPos[index].y;
01205 destPos->z = startPos.z + currDate * startSpeed.z + _K * PrecomputedPos[index].z;
01206 currDate += deltaT;
01207 destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
01208 }
01209 while (--numStep);
01210 }
01211 }
01212 else
01213 {
01214 uint numToSkip = ScaleFloatGE(startDate, deltaT, pi.Date, numStep);
01215 if (numToSkip < numStep)
01216 {
01217 numStep -= numToSkip;
01218 float currDate = startDate + deltaT * numToSkip - pi.Date;
01219 do
01220 {
01221 #ifdef NL_DEBUG
01222 nlassert(destPos < endPos);
01223 #endif
01224 uint index = (uint) (lookUpFactor * currDate) & (BFNumPredefinedPos - 1);
01225 destPos->x += _K * PrecomputedPos[index].x;
01226 destPos->y += _K * PrecomputedPos[index].y;
01227 destPos->z += _K * PrecomputedPos[index].z;
01228 currDate += deltaT;
01229 destPos = (NLMISC::CVector *) ( (uint8 *) destPos + stride);
01230 }
01231 while (--numStep);
01232 }
01233 }
01234 }
01235 }
01236
01237
01239 void CPSBrownianForce::initPrecalc()
01240 {
01242 nlassert(BFNumPredefinedPos % BFPredefinedNumInterp == 0);
01243
01244 NLMISC::CVector p0(0, 0, 0), p1;
01245 const uint numStep = BFNumPredefinedPos / BFPredefinedNumInterp;
01246 NLMISC::CVector *dest = PrecomputedPos;
01247 uint k, l;
01248 for (k = 0; k < numStep; ++k)
01249 {
01250 if (k != numStep - 1)
01251 {
01252 p1.set(2.f * (NLMISC::frand(1.f) - 0.5f),
01253 2.f * (NLMISC::frand(1.f) - 0.5f),
01254 2.f * (NLMISC::frand(1.f) - 0.5f));
01255 }
01256 else
01257 {
01258 p1.set(0, 0, 0);
01259 }
01260 float lambda = 0.f;
01261 float lambdaStep = 1.f / BFPredefinedNumInterp;
01262 for (l = 0; l < BFPredefinedNumInterp; ++l)
01263 {
01264 *dest++ = lambda * p1 + (1.f - lambda) * p0;
01265 lambda += lambdaStep;
01266 }
01267 p0 = p1;
01268 }
01269
01270
01271 for (k = 0; k < (BFPredefinedNumInterp << 2) ; ++k)
01272 {
01273 for (l = 1; l < (BFNumPredefinedPos - 1); ++l)
01274 {
01275 PrecomputedPos[l] = 0.5f * (PrecomputedPos[l - 1] + PrecomputedPos[l + 1]);
01276 }
01277 }
01278
01279
01280
01281 for (l = 1; l < (BFNumPredefinedPos - 1); ++l)
01282 {
01283 PrecomputedSpeed[l] = 0.5f * (PrecomputedPos[l + 1] - PrecomputedPos[l - 1]);
01284 }
01285 PrecomputedSpeed[BFNumPredefinedPos - 1] = NLMISC::CVector::Null;
01286
01287
01288 for (k = 0; k < BFNumPrecomputedImpulsions; ++k)
01289 {
01290 static double divRand = (2.f / RAND_MAX);
01291 PrecomputedImpulsions[k].set( (float) (rand() * divRand - 1),
01292 (float) (rand() * divRand - 1),
01293 (float) (rand() * divRand - 1)
01294 );
01295 }
01296 }
01297
01299 void CPSBrownianForce::setIntensity(float value)
01300 {
01301 if (_IntensityScheme)
01302 {
01303 CPSForceIntensity::setIntensity(value);
01304 renewIntegrable();
01305 }
01306 else
01307 {
01308 CPSForceIntensity::setIntensity(value);
01309 }
01310 }
01311
01312
01314 void CPSBrownianForce::setIntensityScheme(CPSAttribMaker<float> *scheme)
01315 {
01316 if (!_IntensityScheme)
01317 {
01318 cancelIntegrable();
01319 }
01320 CPSForceIntensity::setIntensityScheme(scheme);
01321 }
01322
01324 void CPSBrownianForce::performDynamic(TAnimationTime ellapsedTime)
01325 {
01326
01327 for (uint32 k = 0; k < _Owner->getSize(); ++k)
01328 {
01329 float intensity = _IntensityScheme ? _IntensityScheme->get(_Owner, k) : _K;
01330 for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
01331 {
01332 uint32 size = (*it)->getSize();
01333
01334 if (!size) continue;
01335
01336 TPSAttribVector::iterator it2 = (*it)->getSpeed().begin(), it2End;
01338 uint startPos = (uint) ::rand() % BFNumPrecomputedImpulsions;
01339 NLMISC::CVector *imp = PrecomputedImpulsions + startPos;
01340
01341 if ((*it)->getMassScheme())
01342 {
01343 float intensityXtime = intensity * ellapsedTime;
01344 TPSAttribFloat::const_iterator invMassIt = (*it)->getInvMass().begin();
01345 do
01346 {
01347 uint toProcess = std::min((uint) (BFNumPrecomputedImpulsions - startPos), (uint) size);
01348 it2End = it2 + toProcess;
01349 do
01350 {
01351 float factor = intensityXtime * *invMassIt;
01352 it2->set(it2->x + factor * imp->x,
01353 it2->y + factor * imp->y,
01354 it2->z + factor * imp->x);
01355 ++invMassIt;
01356 ++imp;
01357 ++it2;
01358 }
01359 while (it2 != it2End);
01360 startPos = 0;
01361 imp = PrecomputedImpulsions;
01362 size -= toProcess;
01363 }
01364 while (size != 0);
01365 }
01366 else
01367 {
01368 do
01369 {
01370 uint toProcess = std::min((uint) (BFNumPrecomputedImpulsions - startPos) , (uint) size);
01371 it2End = it2 + toProcess;
01372 float factor = intensity * ellapsedTime / (*it)->getInitialMass();
01373 do
01374 {
01375 it2->set(it2->x + factor * imp->x,
01376 it2->y + factor * imp->y,
01377 it2->z + factor * imp->x);
01378 ++imp;
01379 ++it2;
01380 }
01381 while (it2 != it2End);
01382 startPos = 0;
01383 imp = PrecomputedImpulsions;
01384 size -= toProcess;
01385 }
01386 while (size != 0);
01387 }
01388 }
01389 }
01390 }
01391
01393 void CPSBrownianForce::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01394 {
01395 sint ver = f.serialVersion(3);
01396 if (ver <= 2)
01397 {
01398 uint8 dummy;
01399 f.serial(dummy);
01400 CPSForce::serial(f);
01401 f.serial(dummy);
01402 serialForceIntensity(f);
01403 if (f.isReading())
01404 {
01405 registerToTargets();
01406 }
01407 }
01408
01409 if (ver >= 2)
01410 {
01411 CPSForceIntensityHelper::serial(f);
01412 f.serial(_ParametricFactor);
01413 }
01414 }
01415
01416
01417 }