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_ribbon_base.h"
00029 #include "3d/particle_system.h"
00030
00031 namespace NL3D
00032 {
00033
00035
00037
00038
00040 static inline void BuildHermiteVector(const NLMISC::CVector &P0,
00041 const NLMISC::CVector &P1,
00042 const NLMISC::CVector &T0,
00043 const NLMISC::CVector &T1,
00044 NLMISC::CVector &dest,
00045 float lambda
00046 )
00047 {
00048 const float lambda2 = lambda * lambda;
00049 const float lambda3 = lambda2 * lambda;
00050 const float h1 = 2 * lambda3 - 3 * lambda2 + 1;
00051 const float h2 = - 2 * lambda3 + 3 * lambda2;
00052 const float h3 = lambda3 - 2 * lambda2 + lambda;
00053 const float h4 = lambda3 - lambda2;
00055 dest.set (h1 * P0.x + h2 * P1.x + h3 * T0.x + h4 * T1.x,
00056 h1 * P0.y + h2 * P1.y + h3 * T0.y + h4 * T1.y,
00057 h1 * P0.z + h2 * P1.z + h3 * T0.z + h4 * T1.z);
00058
00059 }
00060
00062 static inline void BuildLinearVector(const NLMISC::CVector &P0,
00063 const NLMISC::CVector &P1,
00064 NLMISC::CVector &dest,
00065 float lambda,
00066 float oneMinusLambda
00067 )
00068 {
00069 dest.set (lambda * P1.x + oneMinusLambda * P0.x,
00070 lambda * P1.y + oneMinusLambda * P0.y,
00071 lambda * P1.z + oneMinusLambda * P0.z);
00072 }
00073
00074
00075 const uint EndRibbonStorage = 1;
00076
00077
00078
00079 CPSRibbonBase::CPSRibbonBase() : _NbSegs(8),
00080 _SegDuration(0.02f),
00081 _Parametric(false),
00082 _RibbonIndex(0),
00083 _LastUpdateDate(0),
00084 _RibbonMode(VariableSize),
00085 _InterpolationMode(Hermitte),
00086 _RibbonLength(1),
00087 _SegLength(_RibbonLength / _NbSegs),
00088 _LODDegradation(1)
00089
00090 {
00091 initDateVect();
00092 }
00093
00094
00095 void CPSRibbonBase::setRibbonLength(float length)
00096 {
00097 nlassert(length > 0.f);
00098 _RibbonLength = length;
00099 _SegLength = length / _NbSegs;
00100 }
00101
00102
00103 void CPSRibbonBase::setRibbonMode(TRibbonMode mode)
00104 {
00105 nlassert(mode < RibbonModeLast);
00106 _RibbonMode = mode;
00107 }
00108
00109
00110
00111 void CPSRibbonBase::setInterpolationMode(TInterpolationMode mode)
00112 {
00113 nlassert(mode < InterpModeLast);
00114 _InterpolationMode = mode;
00115 }
00116
00117
00118 void CPSRibbonBase::setTailNbSeg(uint32 nbSegs)
00119 {
00120 nlassert(nbSegs >= 1);
00121 _NbSegs = nbSegs;
00122 _RibbonIndex = 0;
00123 if (_Owner)
00124 {
00125 resize(_Owner->getMaxSize());
00126 }
00127 initDateVect();
00128 }
00129
00130
00131
00132 void CPSRibbonBase::setSegDuration(TAnimationTime ellapsedTime)
00133 {
00134 _SegDuration = ellapsedTime;
00135
00136 }
00137
00138
00139 void CPSRibbonBase::updateGlobals(float realET)
00140 {
00141 nlassert(!_Parametric);
00142 nlassert(_Owner);
00143 const uint size = _Owner->getSize();
00144 if (!size) return;
00145 const TAnimationTime currDate = _Owner->getOwner()->getSystemDate() + realET;
00146 if (currDate - _LastUpdateDate >= _SegDuration)
00147 {
00148 if (_RibbonIndex == 0) _RibbonIndex = _NbSegs + EndRibbonStorage;
00149 else --_RibbonIndex;
00150
00152 ::memmove(&_SamplingDate[1], &_SamplingDate[0], sizeof(float) * (_NbSegs + EndRibbonStorage));
00153 _LastUpdateDate = currDate;
00154 }
00155
00157 _SamplingDate[0] = currDate;
00158
00160 TPSAttribVector::iterator posIt = _Owner->getPos().begin();
00161 NLMISC::CVector *currIt = &_Ribbons[_RibbonIndex];
00162 uint k = size;
00163 for (;;)
00164 {
00165 *currIt = *posIt;
00166 --k;
00167 if (!k) break;
00168 ++posIt;
00169 currIt += (_NbSegs + 1 + EndRibbonStorage);
00170 }
00171 }
00172
00173
00174
00175 void CPSRibbonBase::computeHermitteRibbon(uint index, NLMISC::CVector *dest, uint stride )
00176 {
00177 nlassert(!_Parametric);
00178 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00179 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
00180 NLMISC::CVector *currIt = startIt + _RibbonIndex;
00181 const NLMISC::CVector *firstIt = currIt;
00182 NLMISC::CVector *nextIt = currIt + 1;
00183 if (nextIt == endIt) nextIt = startIt;
00184 NLMISC::CVector *nextNextIt = nextIt + 1;
00185 if (nextNextIt == endIt) nextNextIt = startIt;
00186 float *date = &_SamplingDate[0];
00187
00188 NLMISC::CVector t0 = (*nextIt - *currIt);
00189 NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
00190
00191 uint leftToDo = _UsedNbSegs + 1;
00192
00193 float lambda = 0.f;
00194 float lambdaStep = 1.f;
00195
00196
00197 for (;;)
00198 {
00199 float dt = date[0] - date[1];
00200
00201 if (dt < 10E-6f)
00202 {
00203
00204 do
00205 {
00206 *dest = *currIt;
00207 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00208 }
00209 while (--leftToDo);
00210 return;
00211 }
00212
00213 float newLambdaStep = _UsedSegDuration / dt;
00214
00215 lambda *= newLambdaStep / lambdaStep;
00216 lambdaStep = newLambdaStep;
00217 for(;;)
00218 {
00219 if (lambda >= 1.f) break;
00221 BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
00222 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00223 -- leftToDo;
00224 if (!leftToDo) return;
00225 lambda += lambdaStep;
00226 }
00227
00228 ++date;
00229 lambda -= 1.f;
00230
00231
00232 t0 = t1;
00233 currIt = nextIt;
00234 nextIt = nextNextIt;
00235 ++nextNextIt;
00236 if (nextNextIt == endIt) nextNextIt = startIt;
00237 if (nextNextIt == firstIt)
00238 {
00239 t1 = *nextIt - *currIt;
00240 }
00241 else
00242 {
00243 t1 = 0.5f * (*nextNextIt - *currIt);
00244 }
00245 }
00246 }
00247
00248
00249 void CPSRibbonBase::computeLinearRibbon(uint index, NLMISC::CVector *dest, uint stride )
00250 {
00252 nlassert(!_Parametric);
00253 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00254 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
00255 NLMISC::CVector *currIt = startIt + _RibbonIndex;
00256 NLMISC::CVector *nextIt = currIt + 1;
00257 if (nextIt == endIt) nextIt = startIt;
00258 NLMISC::CVector *nextNextIt = nextIt + 1;
00259 if (nextNextIt == endIt) nextNextIt = startIt;
00260 float *date = &_SamplingDate[0];
00261
00262 uint leftToDo = _UsedNbSegs + 1;
00263
00264 float lambda = 0.f;
00265 float lambdaStep = 1.f;
00266
00267 for (;;)
00268 {
00269 float dt = date[0] - date[1];
00270
00271 if (dt < 10E-6f)
00272 {
00273 do
00274 {
00275 *dest = *currIt;
00276 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00277 }
00278 while (--leftToDo);
00279 return;
00280 }
00281
00282
00283 float newLambdaStep = _UsedSegDuration / dt;
00284
00285 lambda *= newLambdaStep / lambdaStep;
00286 lambdaStep = newLambdaStep;
00287
00288 float oneMinusLambda = 1.f - lambda;
00289 for(;;)
00290 {
00291 if (lambda >= 1.f) break;
00293 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
00294 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00295 -- leftToDo;
00296 if (!leftToDo) return;
00297 lambda += lambdaStep;
00298 oneMinusLambda -= lambdaStep;
00299 }
00300
00301 ++date;
00302 lambda -= 1.f;
00303
00304 currIt = nextIt;
00305 nextIt = nextNextIt;
00306 ++nextNextIt;
00307 if (nextNextIt == endIt) nextNextIt = startIt;
00308
00309 }
00310 }
00311
00312
00313
00314
00315 void CPSRibbonBase::computeLinearCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride )
00316 {
00317 nlassert(!_Parametric);
00318 CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00319 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
00320 NLMISC::CVector *currIt = startIt + _RibbonIndex;
00321 NLMISC::CVector *firstIt = currIt;
00322 NLMISC::CVector *nextIt = currIt + 1;
00323 if (nextIt == endIt) nextIt = startIt;
00324 NLMISC::CVector *nextNextIt = nextIt + 1;
00325 if (nextNextIt == endIt) nextNextIt = startIt;
00326
00327 uint leftToDo = _UsedNbSegs + 1;
00328
00329 float lambda = 0.f;
00330 float lambdaStep = 1.f;
00331
00332
00334 for (;;)
00335 {
00337 const float sampleLength = (*nextIt - *currIt).norm();
00338 if (sampleLength > 10E-6f)
00339 {
00341 float newLambdaStep = _UsedSegLength / sampleLength;
00342
00343 lambda *= newLambdaStep / lambdaStep;
00344 lambdaStep = newLambdaStep;
00345
00346 float oneMinusLambda = 1.f - lambda;
00347 for(;;)
00348 {
00349 if (lambda >= 1.f) break;
00351 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
00352 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00353 -- leftToDo;
00354 if (!leftToDo) return;
00355 lambda += lambdaStep;
00356 oneMinusLambda -= lambdaStep;
00357 }
00358 lambda -= 1.f;
00359 }
00360
00362 currIt = nextIt;
00363 nextIt = nextNextIt;
00364 ++nextNextIt;
00365 if (nextNextIt == endIt) nextNextIt = startIt;
00366 if (nextNextIt == firstIt)
00367 {
00368
00369
00370 NLMISC::CVector &toDup = *nextIt;
00371 while (leftToDo --)
00372 {
00373 *dest = toDup;
00374 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00375 }
00376 return;
00377 }
00378 }
00379 }
00380
00381
00382 void CPSRibbonBase::computeHermitteCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride )
00383 {
00384 nlassert(!_Parametric);
00385 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
00386 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
00387 NLMISC::CVector *currIt = startIt + _RibbonIndex;
00388 NLMISC::CVector *firstIt = currIt;
00389 NLMISC::CVector *nextIt = currIt + 1;
00390 if (nextIt == endIt) nextIt = startIt;
00391 NLMISC::CVector *nextNextIt = nextIt + 1;
00392 if (nextNextIt == endIt) nextNextIt = startIt;
00393
00394 NLMISC::CVector t0 = (*nextIt - *currIt);
00395 NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
00396
00397 uint leftToDo = _UsedNbSegs + 1;
00398
00399 float lambda = 0.f;
00400 float lambdaStep = 1.f;
00401
00402
00405 for (;;)
00406 {
00408 const float sampleLength = (*nextIt - *currIt).norm();
00409 if (sampleLength > 10E-6f)
00410 {
00412 float newLambdaStep = _UsedSegLength / sampleLength;
00413
00414 lambda *= newLambdaStep / lambdaStep;
00415 lambdaStep = newLambdaStep;
00416
00417 for(;;)
00418 {
00419 if (lambda >= 1.f) break;
00421 BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
00422 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00423 -- leftToDo;
00424 if (!leftToDo) return;
00425 lambda += lambdaStep;
00426 }
00427 lambda -= 1.f;
00428 }
00429
00431 currIt = nextIt;
00432 nextIt = nextNextIt;
00433 ++nextNextIt;
00434 if (nextNextIt == endIt) nextNextIt = startIt;
00435 if (nextNextIt == firstIt)
00436 {
00437
00438
00439 NLMISC::CVector &toDup = *nextIt;
00440 while (leftToDo --)
00441 {
00442 *dest = toDup;
00443 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
00444 }
00445 return;
00446 }
00448 t0 = t1;
00449 t1 = 0.5f * (*nextNextIt - *currIt);
00450 }
00451 }
00452
00453
00454
00455 void CPSRibbonBase::computeRibbon(uint index, NLMISC::CVector *dest, uint stride )
00456 {
00457 switch (_InterpolationMode)
00458 {
00459 case Linear:
00460 if (_RibbonMode == VariableSize)
00461 {
00462 computeLinearRibbon(index, dest, stride);
00463 }
00464 else
00465 {
00466 computeLinearCstSizeRibbon(index, dest, stride);
00467 }
00468 break;
00469 case Hermitte:
00470 if (_RibbonMode == VariableSize)
00471 {
00472 computeHermitteRibbon(index, dest, stride);
00473
00474 }
00475 else
00476 {
00477 computeHermitteCstSizeRibbon(index, dest, stride);
00478 }
00479 break;
00480 default:
00481 nlassert(0);
00482 break;
00483 }
00484
00485 }
00486
00487
00488
00489 void CPSRibbonBase::dupRibbon(uint dest, uint src)
00490 {
00491 nlassert(!_Parametric);
00492 nlassert(_Owner);
00493 const uint size = _Owner->getSize();
00494 nlassert(dest < size && src < size);
00495 ::memcpy(&_Ribbons[dest * (_NbSegs + EndRibbonStorage + 1)], &_Ribbons[src * (_NbSegs + EndRibbonStorage + 1)], sizeof(NLMISC::CVector) * (_NbSegs + 1 + EndRibbonStorage));
00496 }
00497
00498
00499 void CPSRibbonBase::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00500 {
00501 if (_Parametric) return;
00503 const uint index = _Owner->getNewElementIndex();
00504 const NLMISC::CVector &pos = _Owner->getPos()[index];
00505 resetSingleRibbon(index, pos);
00506 }
00507
00508
00509 void CPSRibbonBase::deleteElement(uint32 index)
00510 {
00511 if (_Parametric) return;
00512 const uint32 size = _Owner->getSize();
00513 if(index == (size - 1)) return;
00514 dupRibbon(index, size - 1);
00515 }
00516
00517
00518 void CPSRibbonBase::resize(uint32 size)
00519 {
00520 nlassert(size < (1 << 16));
00521 if (_Parametric) return;
00522 _Ribbons.resize(size * (_NbSegs + 1 + EndRibbonStorage));
00523 resetFromOwner();
00524 }
00525
00526
00527
00528 void CPSRibbonBase::resetSingleRibbon(uint index, const NLMISC::CVector &pos)
00529 {
00530 nlassert(!_Parametric);
00531 NLMISC::CVector *it = &_Ribbons[(index * (_NbSegs + 1 + EndRibbonStorage))];
00532 std::fill(it, it + (_NbSegs + 1 + EndRibbonStorage), pos);
00533 }
00534
00535
00536
00537
00538 void CPSRibbonBase::resetFromOwner()
00539 {
00540 nlassert(!_Parametric);
00541 TPSAttribVector::iterator posIt = _Owner->getPos().begin();
00542 TPSAttribVector::iterator endPosIt = _Owner->getPos().end();
00543 for (uint k = 0; posIt != endPosIt; ++posIt, ++k)
00544 {
00545 resetSingleRibbon(k, *posIt);
00546 }
00547 }
00548
00549
00550 void CPSRibbonBase::motionTypeChanged(bool parametric)
00551 {
00552 _Parametric = parametric;
00553 if (parametric)
00554 {
00555 NLMISC::contReset(_Ribbons);
00556 }
00557 else
00558 {
00559 nlassert(_Owner);
00560 resize(_Owner->getMaxSize());
00561 initDateVect();
00562 resetFromOwner();
00563 }
00564 }
00565
00566
00567
00568 void CPSRibbonBase::initDateVect()
00569 {
00570 _SamplingDate.resize( _NbSegs + 1 + EndRibbonStorage);
00571 std::fill(_SamplingDate.begin(), _SamplingDate.begin() + (_NbSegs + 1 + EndRibbonStorage), 0.f);
00572 }
00573
00574
00575
00576 void CPSRibbonBase::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00577 {
00578 CPSParticle::serial(f);
00579 sint ver = f.serialVersion(1);
00580 f.serialEnum(_RibbonMode);
00581 f.serialEnum(_InterpolationMode);
00582 f.serial(_NbSegs, _SegDuration);
00583 if (_RibbonMode == FixedSize)
00584 {
00585 f.serial(_RibbonLength);
00586 if (f.isReading())
00587 {
00588 _SegLength = _RibbonLength / _NbSegs;
00589 }
00590 }
00591
00592 if (f.isReading())
00593 {
00594 if (_Owner)
00595 {
00596 resize(_Owner->getMaxSize());
00597 initDateVect();
00598 resetFromOwner();
00599 }
00600 }
00601
00602 if (ver >= 1)
00603 {
00604 f.serial(_LODDegradation);
00605 }
00606 }
00607
00608
00609
00610 void CPSRibbonBase::updateLOD()
00611 {
00612 nlassert(_Owner);
00613 float ratio = _Owner->getOwner()->getOneMinusCurrentLODRatio();
00614 float squaredRatio = ratio * ratio;
00615 float lodRatio = _LODDegradation + (1.f - _LODDegradation ) * squaredRatio * squaredRatio * squaredRatio;
00616
00617 _UsedNbSegs = (uint) (_NbSegs * lodRatio);
00618 NLMISC::clamp(_UsedNbSegs, 0u, _NbSegs);
00619 const float epsilon = 10E-4f;
00620 _UsedSegDuration = _SegDuration / std::max(epsilon, lodRatio);
00621 _UsedSegLength = _SegLength / std::max(epsilon, lodRatio);
00622
00623 }
00624
00625
00626 void CPSRibbonBase::systemDateChanged()
00627 {
00628 nlassert(_Owner->getOwner());
00629 _Owner->getOwner()->getSystemDate();
00630 float date = _Owner->getOwner()->getSystemDate();
00631 std::fill(_SamplingDate.begin(), _SamplingDate.end(), date);
00632 _LastUpdateDate = date;
00633 }
00634
00635
00636
00637 }
00638