Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / ps_ribbon_base.cpp
blobe56ebc4d4a8024d0e5866a559f5c1375ba047774
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/misc/common.h"
20 #include "nel/3d/ps_ribbon_base.h"
21 #include "nel/3d/particle_system.h"
23 using namespace NLMISC;
25 #ifdef DEBUG_NEW
26 #define new DEBUG_NEW
27 #endif
29 namespace NL3D
32 ////////////////////////////////////
33 // CPSRibbonBase implementation //
34 ////////////////////////////////////
37 /// build some hermite spline value, with the given points and tangents
38 static inline void BuildHermiteVector(const NLMISC::CVector &P0,
39 const NLMISC::CVector &P1,
40 const NLMISC::CVector &T0,
41 const NLMISC::CVector &T1,
42 NLMISC::CVector &dest,
43 float lambda
46 NL_PS_FUNC(BuildHermiteVector)
47 const float lambda2 = lambda * lambda;
48 const float lambda3 = lambda2 * lambda;
49 const float h1 = 2 * lambda3 - 3 * lambda2 + 1;
50 const float h2 = - 2 * lambda3 + 3 * lambda2;
51 const float h3 = lambda3 - 2 * lambda2 + lambda;
52 const float h4 = lambda3 - lambda2;
53 /// just avoid some ctor calls here...
54 dest.set (h1 * P0.x + h2 * P1.x + h3 * T0.x + h4 * T1.x,
55 h1 * P0.y + h2 * P1.y + h3 * T0.y + h4 * T1.y,
56 h1 * P0.z + h2 * P1.z + h3 * T0.z + h4 * T1.z);
60 /// for test
61 static inline void BuildLinearVector(const NLMISC::CVector &P0,
62 const NLMISC::CVector &P1,
63 NLMISC::CVector &dest,
64 float lambda,
65 float oneMinusLambda
68 NL_PS_FUNC(BuildLinearVector)
69 dest.set (lambda * P1.x + oneMinusLambda * P0.x,
70 lambda * P1.y + oneMinusLambda * P0.y,
71 lambda * P1.z + oneMinusLambda * P0.z);
75 const uint EndRibbonStorage = 1;
78 //=======================================================
79 CPSRibbonBase::CPSRibbonBase() : _NbSegs(8),
80 _SegDuration(0.02f),
81 _Parametric(false),
82 _RibbonIndex(0),
83 _MatrixMode(FatherMatrix),
84 _LastUpdateDate(0),
85 _RibbonMode(VariableSize),
86 _InterpolationMode(Hermitte),
87 _RibbonLength(1),
88 _SegLength(_RibbonLength / _NbSegs),
89 _LODDegradation(1)
92 NL_PS_FUNC(CPSRibbonBase_CPSRibbonBase)
93 initDateVect();
96 //=======================================================
97 void CPSRibbonBase::setMatrixMode(TMatrixMode matrixMode)
99 NL_PS_FUNC(CPSRibbonBase_setMatrixMode)
100 if (matrixMode == _MatrixMode) return;
101 if (_Owner) resetFromOwner();
102 _MatrixMode = matrixMode;
105 //=======================================================
106 void CPSRibbonBase::setRibbonLength(float length)
108 NL_PS_FUNC(CPSRibbonBase_setRibbonLength)
109 nlassert(length > 0.f);
110 _RibbonLength = length;
111 _SegLength = length / _NbSegs;
114 //=======================================================
115 void CPSRibbonBase::setRibbonMode(TRibbonMode mode)
117 NL_PS_FUNC(CPSRibbonBase_setRibbonMode)
118 nlassert(mode < RibbonModeLast);
119 _RibbonMode = mode;
123 //=======================================================
124 void CPSRibbonBase::setInterpolationMode(TInterpolationMode mode)
126 NL_PS_FUNC(CPSRibbonBase_setInterpolationMode)
127 nlassert(mode < InterpModeLast);
128 _InterpolationMode = mode;
131 //=======================================================
132 void CPSRibbonBase::setTailNbSeg(uint32 nbSegs)
134 NL_PS_FUNC(CPSRibbonBase_setTailNbSeg)
135 nlassert(nbSegs >= 1);
136 _NbSegs = nbSegs;
137 _RibbonIndex = 0;
138 if (_Owner)
140 resize(_Owner->getMaxSize());
142 initDateVect();
146 //=======================================================
147 void CPSRibbonBase::setSegDuration(TAnimationTime ellapsedTime)
149 NL_PS_FUNC(CPSRibbonBase_setSegDuration)
150 _SegDuration = ellapsedTime;
154 //=======================================================
155 void CPSRibbonBase::updateGlobals()
157 NL_PS_FUNC(CPSRibbonBase_updateGlobals)
158 nlassert(!_Parametric);
159 nlassert(_Owner);
160 const uint size = _Owner->getSize();
161 if (!size) return;
162 const TAnimationTime currDate = _Owner->getOwner()->getSystemDate() + CParticleSystem::RealEllapsedTime;
163 if (currDate - _LastUpdateDate >= _SegDuration)
165 if (_RibbonIndex == 0) _RibbonIndex = _NbSegs + EndRibbonStorage;
166 else --_RibbonIndex;
168 /// decal date
169 ::memmove(&_SamplingDate[1], &_SamplingDate[0], sizeof(float) * (_NbSegs + EndRibbonStorage));
170 _LastUpdateDate = currDate;
173 /// save current date
174 _SamplingDate[0] = currDate;
176 /// updating ribbons positions
177 TPSMatrixMode mm = convertMatrixMode();
178 if (mm == _Owner->getMatrixMode())
180 // trail reside in the same coord system -> no conversion needed
181 TPSAttribVector::iterator posIt = _Owner->getPos().begin();
182 NLMISC::CVector *currIt = &_Ribbons[_RibbonIndex];
183 uint k = size;
184 for (;;)
186 *currIt = *posIt;
187 --k;
188 if (!k) break;
189 ++posIt;
190 currIt += (_NbSegs + 1 + EndRibbonStorage);
193 else
195 nlassert(_Owner->getOwner());
196 const CMatrix &mat = CPSLocated::getConversionMatrix(*_Owner->getOwner(), mm, _Owner->getMatrixMode());
197 TPSAttribVector::iterator posIt = _Owner->getPos().begin();
198 NLMISC::CVector *currIt = &_Ribbons[_RibbonIndex];
199 uint k = size;
200 for (;;)
202 *currIt = mat * *posIt;
203 --k;
204 if (!k) break;
205 ++posIt;
206 currIt += (_NbSegs + 1 + EndRibbonStorage);
212 //=======================================================
213 void CPSRibbonBase::computeHermitteRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
215 NL_PS_FUNC(CPSRibbonBase_CVector )
216 nlassert(!_Parametric);
217 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
218 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
219 NLMISC::CVector *currIt = startIt + _RibbonIndex;
220 const NLMISC::CVector *firstIt = currIt;
221 NLMISC::CVector *nextIt = currIt + 1;
222 if (nextIt == endIt) nextIt = startIt;
223 NLMISC::CVector *nextNextIt = nextIt + 1;
224 if (nextNextIt == endIt) nextNextIt = startIt;
225 float *date = &_SamplingDate[0];
227 NLMISC::CVector t0 = (*nextIt - *currIt);
228 NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
230 uint leftToDo = _UsedNbSegs + 1;
232 float lambda = 0.f;
233 float lambdaStep = 1.f;
236 for (;;)
238 float dt = date[0] - date[1];
240 if (dt < 10E-6f) // we reached the start of ribbon
245 *dest = *currIt;
246 #ifdef NL_DEBUG
247 nlassert(NLMISC::isValidDouble(dest->x));
248 nlassert(NLMISC::isValidDouble(dest->y));
249 nlassert(NLMISC::isValidDouble(dest->z));
250 #endif
251 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
253 while (--leftToDo);
254 return;
257 float newLambdaStep = _UsedSegDuration / dt;
258 // readapt lambda
259 lambda *= newLambdaStep / lambdaStep;
260 lambdaStep = newLambdaStep;
261 for(;;)
263 if (lambda >= 1.f) break;
264 /// compute a location
265 BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
266 #ifdef NL_DEBUG
267 nlassert(NLMISC::isValidDouble(dest->x));
268 nlassert(NLMISC::isValidDouble(dest->y));
269 nlassert(NLMISC::isValidDouble(dest->z));
270 #endif
271 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
272 -- leftToDo;
273 if (!leftToDo) return;
274 lambda += lambdaStep;
277 ++date;
278 lambda -= 1.f;
280 // Start new segment and compute new tangents
281 t0 = t1;
282 currIt = nextIt;
283 nextIt = nextNextIt;
284 ++nextNextIt;
285 if (nextNextIt == endIt) nextNextIt = startIt;
286 if (nextNextIt == firstIt)
288 t1 = *nextIt - *currIt;
290 else
292 t1 = 0.5f * (*nextNextIt - *currIt);
297 //=======================================================
298 void CPSRibbonBase::computeLinearRibbon(uint index, NLMISC::CVector *dest, uint stride)
300 NL_PS_FUNC(CPSRibbonBase_computeLinearRibbon)
301 nlassert(!_Parametric);
302 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
303 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
304 NLMISC::CVector *currIt = startIt + _RibbonIndex;
305 NLMISC::CVector *nextIt = currIt + 1;
306 if (nextIt == endIt) nextIt = startIt;
307 NLMISC::CVector *nextNextIt = nextIt + 1;
308 if (nextNextIt == endIt) nextNextIt = startIt;
309 float *date = &_SamplingDate[0];
311 uint leftToDo = _UsedNbSegs + 1;
313 float lambda = 0.f;
314 float lambdaStep = 1.f;
316 for (;;)
318 float dt = date[0] - date[1];
320 if (dt < 10E-6f) // we reached the start of ribbon
324 *dest = *currIt;
325 #ifdef NL_DEBUG
326 nlassert(NLMISC::isValidDouble(dest->x));
327 nlassert(NLMISC::isValidDouble(dest->y));
328 nlassert(NLMISC::isValidDouble(dest->z));
329 #endif
330 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
333 while (--leftToDo);
334 return;
338 float newLambdaStep = _UsedSegDuration / dt;
339 // readapt lambda
340 lambda *= newLambdaStep / lambdaStep;
341 lambdaStep = newLambdaStep;
343 float oneMinusLambda = 1.f - lambda;
344 for(;;)
346 if (lambda >= 1.f) break;
347 /// compute a location
348 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
349 #ifdef NL_DEBUG
350 nlassert(NLMISC::isValidDouble(dest->x));
351 nlassert(NLMISC::isValidDouble(dest->y));
352 nlassert(NLMISC::isValidDouble(dest->z));
353 #endif
354 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
355 -- leftToDo;
356 if (!leftToDo) return;
357 lambda += lambdaStep;
358 oneMinusLambda -= lambdaStep;
361 ++date;
362 lambda -= 1.f;
364 currIt = nextIt;
365 nextIt = nextNextIt;
366 ++nextNextIt;
367 if (nextNextIt == endIt) nextNextIt = startIt;
373 void CPSRibbonBase::computeLinearRibbon(uint index, NLMISC::CVector *dest, uint stride)
375 nlassert(!_Parametric);
376 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
377 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
378 NLMISC::CVector *currIt = startIt + _RibbonIndex;
379 NLMISC::CVector *nextIt = currIt + 1;
380 if (nextIt == endIt) nextIt = startIt;
381 NLMISC::CVector *nextNextIt = nextIt + 1;
382 if (nextNextIt == endIt) nextNextIt = startIt;
383 float *date = &_SamplingDate[0];
385 uint leftToDo = _UsedNbSegs + 1;
387 float lambda = 0.f;
390 float dt = date[0] - date[1];
391 if (dt < 10E-6f) // we reached the start of ribbon
395 *dest = *currIt;
396 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
398 while (--leftToDo);
399 return;
401 float lambdaStep = _UsedSegDuration / dt;
402 BuildLinearVector(*currIt, *nextIt, *dest, 0.f, 1.f);
403 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
404 -- leftToDo;
405 // snap lambda to nearest time step
406 lambda = lambdaStep * fmodf(date[0], _UsedSegDuration) / _UsedSegDuration;
407 for (;;)
409 float oneMinusLambda = 1.f - lambda;
410 for(;;)
412 if (lambda >= 1.f) break;
413 /// compute a location
414 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
415 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
416 -- leftToDo;
417 if (!leftToDo) return;
418 lambda += lambdaStep;
419 oneMinusLambda -= lambdaStep;
422 ++date;
423 lambda -= 1.f;
425 currIt = nextIt;
426 nextIt = nextNextIt;
427 ++nextNextIt;
428 if (nextNextIt == endIt) nextNextIt = startIt;
429 float dt = date[0] - date[1];
430 if (dt < 10E-6f) // we reached the start of ribbon
434 *dest = *currIt;
435 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
437 while (--leftToDo);
438 return;
440 float newLambdaStep = _UsedSegDuration / dt;
441 // readapt lambda
442 lambda *= newLambdaStep / lambdaStep;
443 lambdaStep = newLambdaStep;
450 //=======================================================
451 void CPSRibbonBase::computeLinearCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
453 NL_PS_FUNC(CPSRibbonBase_CVector )
454 nlassert(!_Parametric);
455 CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
456 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
457 NLMISC::CVector *currIt = startIt + _RibbonIndex;
458 NLMISC::CVector *firstIt = currIt;
459 NLMISC::CVector *nextIt = currIt + 1;
460 if (nextIt == endIt) nextIt = startIt;
461 NLMISC::CVector *nextNextIt = nextIt + 1;
462 if (nextNextIt == endIt) nextNextIt = startIt;
464 uint leftToDo = _UsedNbSegs + 1;
466 float lambda = 0.f;
467 float lambdaStep = 1.f;
470 /// Our goal here is to match the length of the ribbon, But if it isn't moving fast enough, we must truncate it
471 for (;;)
473 /// compute length between the 2 sampling points
474 const float sampleLength = (*nextIt - *currIt).norm();
475 if (sampleLength > 10E-6f)
477 /// compute lambda so that it match the length needed for each segment
478 float newLambdaStep = _UsedSegLength / sampleLength;
479 // readapt lambda
480 lambda *= newLambdaStep / lambdaStep;
481 lambdaStep = newLambdaStep;
483 float oneMinusLambda = 1.f - lambda;
484 for(;;)
486 if (lambda >= 1.f) break;
487 /// compute a location
488 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
489 #ifdef NL_DEBUG
490 nlassert(NLMISC::isValidDouble(dest->x));
491 nlassert(NLMISC::isValidDouble(dest->y));
492 nlassert(NLMISC::isValidDouble(dest->z));
493 #endif
494 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
495 -- leftToDo;
496 if (!leftToDo) return;
497 lambda += lambdaStep;
498 oneMinusLambda -= lambdaStep;
500 lambda -= 1.f;
503 /// go to next sampling pos
504 currIt = nextIt;
505 nextIt = nextNextIt;
506 ++nextNextIt;
507 if (nextNextIt == endIt) nextNextIt = startIt;
508 if (nextNextIt == firstIt)
510 // The length of the sampling curve is too short
511 // must truncate the ribbon.
512 NLMISC::CVector &toDup = *nextIt;
513 while (leftToDo --)
515 *dest = toDup;
516 #ifdef NL_DEBUG
517 nlassert(NLMISC::isValidDouble(dest->x));
518 nlassert(NLMISC::isValidDouble(dest->y));
519 nlassert(NLMISC::isValidDouble(dest->z));
520 #endif
521 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
523 return;
528 //=======================================================
529 void CPSRibbonBase::computeHermitteCstSizeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
531 NL_PS_FUNC(CPSRibbonBase_CVector )
532 nlassert(!_Parametric);
533 NLMISC::CVector *startIt = &_Ribbons[(_NbSegs + 1 + EndRibbonStorage) * index];
534 NLMISC::CVector *endIt = startIt + (_NbSegs + 1 + EndRibbonStorage);
535 NLMISC::CVector *currIt = startIt + _RibbonIndex;
536 NLMISC::CVector *firstIt = currIt;
537 NLMISC::CVector *nextIt = currIt + 1;
538 if (nextIt == endIt) nextIt = startIt;
539 NLMISC::CVector *nextNextIt = nextIt + 1;
540 if (nextNextIt == endIt) nextNextIt = startIt;
542 NLMISC::CVector t0 = (*nextIt - *currIt);
543 NLMISC::CVector t1 = 0.5f * (*nextNextIt - *currIt);
545 uint leftToDo = _UsedNbSegs + 1;
547 float lambda = 0.f;
548 float lambdaStep = 1.f;
551 /// Our goal here is to match the length of the ribbon, But if it isn't moving fast enough, we must truncate it
552 /// Having a constant speed over a hermite curve is expensive, so we make a (very) rough approximation...
553 for (;;)
555 /// compute length between the 2 sampling points
556 const float sampleLength = (*nextIt - *currIt).norm();
557 if (sampleLength > 10E-6f)
559 /// compute lambda so that it match the length needed for each segment
560 float newLambdaStep = _UsedSegLength / sampleLength;
561 // readapt lambda
562 lambda *= newLambdaStep / lambdaStep;
563 lambdaStep = newLambdaStep;
565 for(;;)
567 if (lambda >= 1.f) break;
568 /// compute a location
569 BuildHermiteVector(*currIt, *nextIt, t0, t1, *dest, lambda);
570 #ifdef NL_DEBUG
571 nlassert(NLMISC::isValidDouble(dest->x));
572 nlassert(NLMISC::isValidDouble(dest->y));
573 nlassert(NLMISC::isValidDouble(dest->z));
574 #endif
576 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
577 -- leftToDo;
578 if (!leftToDo) return;
579 lambda += lambdaStep;
581 lambda -= 1.f;
584 /// go to next sampling pos
585 currIt = nextIt;
586 nextIt = nextNextIt;
587 ++nextNextIt;
588 if (nextNextIt == endIt) nextNextIt = startIt;
589 if (nextNextIt == firstIt)
591 // The length of the sampling curve is too short
592 // must truncate the ribbon.
593 NLMISC::CVector &toDup = *nextIt;
594 while (leftToDo --)
596 *dest = toDup;
597 #ifdef NL_DEBUG
598 nlassert(NLMISC::isValidDouble(dest->x));
599 nlassert(NLMISC::isValidDouble(dest->y));
600 nlassert(NLMISC::isValidDouble(dest->z));
601 #endif
602 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
604 return;
606 /// update tangents
607 t0 = t1;
608 t1 = 0.5f * (*nextNextIt - *currIt);
613 //=======================================================
614 void CPSRibbonBase::computeRibbon(uint index, NLMISC::CVector *dest, uint stride /* = sizeof(NLMISC::CVector)*/)
616 NL_PS_FUNC(CPSRibbonBase_CVector )
617 switch (_InterpolationMode)
619 case Linear:
620 if (_RibbonMode == VariableSize)
622 computeLinearRibbon(index, dest, stride);
624 else
626 computeLinearCstSizeRibbon(index, dest, stride);
628 break;
629 case Hermitte:
630 if (_RibbonMode == VariableSize)
632 computeHermitteRibbon(index, dest, stride);
635 else
637 computeHermitteCstSizeRibbon(index, dest, stride);
639 break;
640 default:
641 nlassert(0);
642 break;
647 //=======================================================
648 void CPSRibbonBase::dupRibbon(uint dest, uint src)
650 NL_PS_FUNC(CPSRibbonBase_dupRibbon)
651 nlassert(!_Parametric);
652 nlassert(_Owner);
653 const uint size = _Owner->getSize();
654 nlassert(dest < size && src < size);
655 ::memcpy(&_Ribbons[dest * (_NbSegs + EndRibbonStorage + 1)], &_Ribbons[src * (_NbSegs + EndRibbonStorage + 1)], sizeof(NLMISC::CVector) * (_NbSegs + 1 + EndRibbonStorage));
658 //=======================================================
659 void CPSRibbonBase::newElement(const CPSEmitterInfo &info)
661 NL_PS_FUNC(CPSRibbonBase_newElement)
662 if (_Parametric) return;
663 /// dump the same pos for all pos of the ribbon
664 const uint index = _Owner->getNewElementIndex();
665 const NLMISC::CVector &pos = _Owner->getPos()[index]; // get the pos of the new element;
666 resetSingleRibbon(index, pos);
669 //=======================================================
670 void CPSRibbonBase::deleteElement(uint32 index)
672 NL_PS_FUNC(CPSRibbonBase_deleteElement)
673 if (_Parametric) return;
674 const uint32 size = _Owner->getSize();
675 if(index == (size - 1)) return; // was the last element, no permutation needed.
676 dupRibbon(index, size - 1);
679 //=======================================================
680 void CPSRibbonBase::resize(uint32 size)
682 NL_PS_FUNC(CPSRibbonBase_resize)
683 nlassert(size < (1 << 16));
684 if (_Parametric) return;
685 _Ribbons.resize(size * (_NbSegs + 1 + EndRibbonStorage));
686 resetFromOwner();
690 //=======================================================
691 void CPSRibbonBase::resetSingleRibbon(uint index, const NLMISC::CVector &pos)
693 NL_PS_FUNC(CPSRibbonBase_resetSingleRibbon)
694 nlassert(!_Parametric);
695 TPSMatrixMode mm = convertMatrixMode();
696 NLMISC::CVector *it = &_Ribbons[(index * (_NbSegs + 1 + EndRibbonStorage))];
697 if (mm == _Owner->getMatrixMode())
699 std::fill(it, it + (_NbSegs + 1 + EndRibbonStorage), pos);
701 else
703 nlassert(_Owner->getOwner());
704 const CMatrix &mat = CPSLocated::getConversionMatrix(*_Owner->getOwner(), mm, _Owner->getMatrixMode());
705 std::fill(it, it + (_NbSegs + 1 + EndRibbonStorage), mat * pos);
711 //=======================================================
712 void CPSRibbonBase::resetFromOwner()
714 NL_PS_FUNC(CPSRibbonBase_resetFromOwner)
715 nlassert(!_Parametric);
716 TPSAttribVector::iterator posIt = _Owner->getPos().begin();
717 TPSAttribVector::iterator endPosIt = _Owner->getPos().end();
718 for (uint k = 0; posIt != endPosIt; ++posIt, ++k)
720 resetSingleRibbon(k, *posIt);
724 //=======================================================
725 void CPSRibbonBase::motionTypeChanged(bool parametric)
727 NL_PS_FUNC(CPSRibbonBase_motionTypeChanged)
728 _Parametric = parametric;
729 if (parametric)
731 NLMISC::contReset(_Ribbons); // kill the vector
733 else
735 nlassert(_Owner);
736 resize(_Owner->getMaxSize());
737 initDateVect();
738 resetFromOwner();
743 //=======================================================
744 void CPSRibbonBase::initDateVect()
746 NL_PS_FUNC(CPSRibbonBase_initDateVect)
747 _SamplingDate.resize( _NbSegs + 1 + EndRibbonStorage);
748 std::fill(_SamplingDate.begin(), _SamplingDate.begin() + (_NbSegs + 1 + EndRibbonStorage), 0.f);
752 //=======================================================
753 void CPSRibbonBase::serial(NLMISC::IStream &f)
755 NL_PS_FUNC(CPSRibbonBase_serial)
756 CPSParticle::serial(f);
757 // version 2 : added matrix mode
758 sint ver = f.serialVersion(2);
759 f.serialEnum(_RibbonMode);
760 f.serialEnum(_InterpolationMode);
761 f.serial(_NbSegs, _SegDuration);
762 if (_RibbonMode == FixedSize)
764 f.serial(_RibbonLength);
765 if (f.isReading())
767 _SegLength = _RibbonLength / _NbSegs;
770 if (f.isReading())
772 if (_Owner)
774 resize(_Owner->getMaxSize());
775 initDateVect();
776 resetFromOwner();
779 if (ver >= 1)
781 f.serial(_LODDegradation);
783 if (ver >= 2)
785 f.serialEnum(_MatrixMode);
790 //=======================================================
791 void CPSRibbonBase::updateLOD()
793 NL_PS_FUNC(CPSRibbonBase_updateLOD)
794 nlassert(_Owner);
795 float ratio = _Owner->getOwner()->getOneMinusCurrentLODRatio();
796 float squaredRatio = ratio * ratio;
797 float lodRatio = _LODDegradation + (1.f - _LODDegradation ) * squaredRatio * squaredRatio * squaredRatio;
799 _UsedNbSegs = (uint) (_NbSegs * lodRatio);
800 NLMISC::clamp(_UsedNbSegs, 0u, _NbSegs);
801 const float epsilon = 10E-4f;
802 _UsedSegDuration = _SegDuration / std::max(epsilon, lodRatio);
803 _UsedSegLength = _SegLength / std::max(epsilon, lodRatio);
807 //=======================================================
808 void CPSRibbonBase::systemDateChanged()
810 NL_PS_FUNC(CPSRibbonBase_systemDateChanged)
811 nlassert(_Owner->getOwner());
812 _Owner->getOwner()->getSystemDate();
813 float date = _Owner->getOwner()->getSystemDate();
814 std::fill(_SamplingDate.begin(), _SamplingDate.end(), date);
815 _LastUpdateDate = date;
820 } // NL3D