1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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
;
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
,
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
);
61 static inline void BuildLinearVector(const NLMISC::CVector
&P0
,
62 const NLMISC::CVector
&P1
,
63 NLMISC::CVector
&dest
,
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),
83 _MatrixMode(FatherMatrix
),
85 _RibbonMode(VariableSize
),
86 _InterpolationMode(Hermitte
),
88 _SegLength(_RibbonLength
/ _NbSegs
),
92 NL_PS_FUNC(CPSRibbonBase_CPSRibbonBase
)
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
);
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);
140 resize(_Owner
->getMaxSize());
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
);
160 const uint size
= _Owner
->getSize();
162 const TAnimationTime currDate
= _Owner
->getOwner()->getSystemDate() + CParticleSystem::RealEllapsedTime
;
163 if (currDate
- _LastUpdateDate
>= _SegDuration
)
165 if (_RibbonIndex
== 0) _RibbonIndex
= _NbSegs
+ EndRibbonStorage
;
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
];
190 currIt
+= (_NbSegs
+ 1 + EndRibbonStorage
);
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
];
202 *currIt
= mat
* *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;
233 float lambdaStep
= 1.f
;
238 float dt
= date
[0] - date
[1];
240 if (dt
< 10E-6f
) // we reached the start of ribbon
247 nlassert(NLMISC::isValidDouble(dest
->x
));
248 nlassert(NLMISC::isValidDouble(dest
->y
));
249 nlassert(NLMISC::isValidDouble(dest
->z
));
251 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
257 float newLambdaStep
= _UsedSegDuration
/ dt
;
259 lambda
*= newLambdaStep
/ lambdaStep
;
260 lambdaStep
= newLambdaStep
;
263 if (lambda
>= 1.f
) break;
264 /// compute a location
265 BuildHermiteVector(*currIt
, *nextIt
, t0
, t1
, *dest
, lambda
);
267 nlassert(NLMISC::isValidDouble(dest
->x
));
268 nlassert(NLMISC::isValidDouble(dest
->y
));
269 nlassert(NLMISC::isValidDouble(dest
->z
));
271 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
273 if (!leftToDo
) return;
274 lambda
+= lambdaStep
;
280 // Start new segment and compute new tangents
285 if (nextNextIt
== endIt
) nextNextIt
= startIt
;
286 if (nextNextIt
== firstIt
)
288 t1
= *nextIt
- *currIt
;
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;
314 float lambdaStep
= 1.f
;
318 float dt
= date
[0] - date
[1];
320 if (dt
< 10E-6f
) // we reached the start of ribbon
326 nlassert(NLMISC::isValidDouble(dest
->x
));
327 nlassert(NLMISC::isValidDouble(dest
->y
));
328 nlassert(NLMISC::isValidDouble(dest
->z
));
330 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
338 float newLambdaStep
= _UsedSegDuration
/ dt
;
340 lambda
*= newLambdaStep
/ lambdaStep
;
341 lambdaStep
= newLambdaStep
;
343 float oneMinusLambda
= 1.f
- lambda
;
346 if (lambda
>= 1.f
) break;
347 /// compute a location
348 BuildLinearVector(*currIt
, *nextIt
, *dest
, lambda
, oneMinusLambda
);
350 nlassert(NLMISC::isValidDouble(dest
->x
));
351 nlassert(NLMISC::isValidDouble(dest
->y
));
352 nlassert(NLMISC::isValidDouble(dest
->z
));
354 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
356 if (!leftToDo
) return;
357 lambda
+= lambdaStep
;
358 oneMinusLambda
-= lambdaStep
;
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;
390 float dt = date[0] - date[1];
391 if (dt < 10E-6f) // we reached the start of ribbon
396 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
401 float lambdaStep = _UsedSegDuration / dt;
402 BuildLinearVector(*currIt, *nextIt, *dest, 0.f, 1.f);
403 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
405 // snap lambda to nearest time step
406 lambda = lambdaStep * fmodf(date[0], _UsedSegDuration) / _UsedSegDuration;
409 float oneMinusLambda = 1.f - lambda;
412 if (lambda >= 1.f) break;
413 /// compute a location
414 BuildLinearVector(*currIt, *nextIt, *dest, lambda, oneMinusLambda);
415 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
417 if (!leftToDo) return;
418 lambda += lambdaStep;
419 oneMinusLambda -= lambdaStep;
428 if (nextNextIt == endIt) nextNextIt = startIt;
429 float dt = date[0] - date[1];
430 if (dt < 10E-6f) // we reached the start of ribbon
435 dest = (NLMISC::CVector *) ((uint8 *) dest + stride);
440 float newLambdaStep = _UsedSegDuration / dt;
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;
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
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
;
480 lambda
*= newLambdaStep
/ lambdaStep
;
481 lambdaStep
= newLambdaStep
;
483 float oneMinusLambda
= 1.f
- lambda
;
486 if (lambda
>= 1.f
) break;
487 /// compute a location
488 BuildLinearVector(*currIt
, *nextIt
, *dest
, lambda
, oneMinusLambda
);
490 nlassert(NLMISC::isValidDouble(dest
->x
));
491 nlassert(NLMISC::isValidDouble(dest
->y
));
492 nlassert(NLMISC::isValidDouble(dest
->z
));
494 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
496 if (!leftToDo
) return;
497 lambda
+= lambdaStep
;
498 oneMinusLambda
-= lambdaStep
;
503 /// go to next sampling pos
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
;
517 nlassert(NLMISC::isValidDouble(dest
->x
));
518 nlassert(NLMISC::isValidDouble(dest
->y
));
519 nlassert(NLMISC::isValidDouble(dest
->z
));
521 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
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;
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...
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
;
562 lambda
*= newLambdaStep
/ lambdaStep
;
563 lambdaStep
= newLambdaStep
;
567 if (lambda
>= 1.f
) break;
568 /// compute a location
569 BuildHermiteVector(*currIt
, *nextIt
, t0
, t1
, *dest
, lambda
);
571 nlassert(NLMISC::isValidDouble(dest
->x
));
572 nlassert(NLMISC::isValidDouble(dest
->y
));
573 nlassert(NLMISC::isValidDouble(dest
->z
));
576 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
578 if (!leftToDo
) return;
579 lambda
+= lambdaStep
;
584 /// go to next sampling pos
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
;
598 nlassert(NLMISC::isValidDouble(dest
->x
));
599 nlassert(NLMISC::isValidDouble(dest
->y
));
600 nlassert(NLMISC::isValidDouble(dest
->z
));
602 dest
= (NLMISC::CVector
*) ((uint8
*) dest
+ stride
);
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
)
620 if (_RibbonMode
== VariableSize
)
622 computeLinearRibbon(index
, dest
, stride
);
626 computeLinearCstSizeRibbon(index
, dest
, stride
);
630 if (_RibbonMode
== VariableSize
)
632 computeHermitteRibbon(index
, dest
, stride
);
637 computeHermitteCstSizeRibbon(index
, dest
, stride
);
647 //=======================================================
648 void CPSRibbonBase::dupRibbon(uint dest
, uint src
)
650 NL_PS_FUNC(CPSRibbonBase_dupRibbon
)
651 nlassert(!_Parametric
);
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
));
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
);
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
;
731 NLMISC::contReset(_Ribbons
); // kill the vector
736 resize(_Owner
->getMaxSize());
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
);
767 _SegLength
= _RibbonLength
/ _NbSegs
;
774 resize(_Owner
->getMaxSize());
781 f
.serial(_LODDegradation
);
785 f
.serialEnum(_MatrixMode
);
790 //=======================================================
791 void CPSRibbonBase::updateLOD()
793 NL_PS_FUNC(CPSRibbonBase_updateLOD
)
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
;